Explorar o código

管控类界面添加

hongrunxia hai 1 ano
pai
achega
cd0cf36dca
Modificáronse 100 ficheiros con 8542 adicións e 566 borrados
  1. 2 2
      .env.development
  2. 5 2
      .env.production
  3. 1 0
      index.html
  4. 6 0
      pnpm-lock.yaml
  5. BIN=BIN
      public/model/glft/fire/tunFace_2023-06-29.glb
  6. 0 0
      public/model/glft/fire/workFace1_2023-06-02.glb
  7. BIN=BIN
      public/model/glft/fire/workFace_2023-06-29.glb
  8. 9 0
      src/assets/icons/CO-title.svg
  9. 8 0
      src/assets/icons/O2-aveg.svg
  10. 10 0
      src/assets/icons/O2-low.svg
  11. 8 0
      src/assets/icons/O2-top.svg
  12. 19 0
      src/assets/icons/beamTube-title.svg
  13. 9 0
      src/assets/icons/control-setting.svg
  14. 9 0
      src/assets/icons/dianji-title.svg
  15. 9 0
      src/assets/icons/fdbs.svg
  16. 22 0
      src/assets/icons/fiber-title.svg
  17. 19 0
      src/assets/icons/jizu-title.svg
  18. 9 0
      src/assets/icons/nitrogen-title.svg
  19. 9 0
      src/assets/icons/param-setting.svg
  20. 9 0
      src/assets/icons/person.svg
  21. 9 0
      src/assets/icons/plsz.svg
  22. 9 0
      src/assets/icons/pulp-title.svg
  23. 12 0
      src/assets/icons/shandian.svg
  24. 12 0
      src/assets/icons/smoke-title.svg
  25. 9 0
      src/assets/icons/temperature-title.svg
  26. 9 0
      src/assets/icons/warning-analyze-title.svg
  27. 9 0
      src/assets/icons/warning-title.svg
  28. 9 0
      src/assets/icons/ytws.svg
  29. BIN=BIN
      src/assets/images/vent/down.png
  30. BIN=BIN
      src/assets/images/vent/title-boder-left.png
  31. BIN=BIN
      src/assets/images/vent/title-boder-right.png
  32. BIN=BIN
      src/assets/images/vent/up.png
  33. 2 1
      src/components/Form/src/jeecg/components/MTreeSelect.vue
  34. 3 2
      src/components/jeecg/ExcelButton.vue
  35. 80 26
      src/design/vent/comment.less
  36. 4 4
      src/design/vent/index.less
  37. 1 1
      src/design/vent/modal.less
  38. 1 0
      src/hooks/system/useListPage.ts
  39. 15 0
      src/hooks/web/useWebColumns.ts
  40. 24 0
      src/router/routes/basic.ts
  41. 0 22
      src/router/routes/index.ts
  42. 2 1
      src/utils/threejs/main.worker.ts
  43. 2 2
      src/views/system/menuModal/MenuDrawer.vue
  44. 4 7
      src/views/system/menuModal/index.vue
  45. 1 1
      src/views/vent/comment/components/bottomMenu.vue
  46. 2 2
      src/views/vent/comment/components/customHeader.vue
  47. 5 1
      src/views/vent/deviceManager/comment/DeviceModal.vue
  48. 8 7
      src/views/vent/deviceManager/comment/NormalTable.vue
  49. 22 20
      src/views/vent/deviceManager/comment/warningTabel/DevicePointTable.vue
  50. 38 67
      src/views/vent/deviceManager/comment/warningTabel/index1.vue
  51. 94 84
      src/views/vent/deviceManager/comment/warningTabel/index2.vue
  52. 36 4
      src/views/vent/deviceManager/comment/warningTabel/warning.api.ts
  53. 117 2
      src/views/vent/deviceManager/comment/warningTabel/warning.data.ts
  54. 60 0
      src/views/vent/deviceManager/deviceTable/device.api.ts
  55. 155 0
      src/views/vent/deviceManager/deviceTable/device.data.ts
  56. 134 0
      src/views/vent/deviceManager/deviceTable/index.vue
  57. 2 2
      src/views/vent/deviceManager/fanTabel/fan.data.ts
  58. 2 2
      src/views/vent/deviceManager/ledTabel/led.data.ts
  59. 6 0
      src/views/vent/deviceManager/pointTabel/point.data.ts
  60. 3 3
      src/views/vent/deviceManager/sensorTabel/sensor.data.ts
  61. 2 2
      src/views/vent/deviceManager/windWindowTabel/ventanalyWindow.data.ts
  62. 1 1
      src/views/vent/deviceManager/windfindingTabel/windfinding.data.ts
  63. 26 14
      src/views/vent/deviceManager/workingFace/workingFace.data.ts
  64. 18 0
      src/views/vent/monitorManager/balancePressMonitor/balancePress.api.ts
  65. 150 0
      src/views/vent/monitorManager/balancePressMonitor/balancePress.data.ts
  66. 104 0
      src/views/vent/monitorManager/balancePressMonitor/balancePress.threejs.base.ts
  67. 117 0
      src/views/vent/monitorManager/balancePressMonitor/balancePress.threejs.ts
  68. 30 0
      src/views/vent/monitorManager/balancePressMonitor/components/balancePressAlarmHistory.vue
  69. 25 0
      src/views/vent/monitorManager/balancePressMonitor/components/balancePressHandleHistory.vue
  70. 28 0
      src/views/vent/monitorManager/balancePressMonitor/components/balancePressHistory.vue
  71. 255 0
      src/views/vent/monitorManager/balancePressMonitor/components/balancePressHome.vue
  72. 223 0
      src/views/vent/monitorManager/balancePressMonitor/index.vue
  73. 18 0
      src/views/vent/monitorManager/beltTunMonitor/beltTun.api.ts
  74. 731 0
      src/views/vent/monitorManager/beltTunMonitor/beltTun.data.ts
  75. 326 0
      src/views/vent/monitorManager/beltTunMonitor/beltTun.threejs.base.ts
  76. 120 0
      src/views/vent/monitorManager/beltTunMonitor/beltTun.threejs.ts
  77. 35 0
      src/views/vent/monitorManager/beltTunMonitor/components/beltTunAlarmHistory.vue
  78. 244 0
      src/views/vent/monitorManager/beltTunMonitor/components/beltTunDustHome.vue
  79. 342 0
      src/views/vent/monitorManager/beltTunMonitor/components/beltTunFireHome.vue
  80. 327 0
      src/views/vent/monitorManager/beltTunMonitor/components/beltTunGasHome.vue
  81. 40 0
      src/views/vent/monitorManager/beltTunMonitor/components/beltTunHandleHistory.vue
  82. 28 0
      src/views/vent/monitorManager/beltTunMonitor/components/beltTunHistory.vue
  83. 325 0
      src/views/vent/monitorManager/beltTunMonitor/components/beltTunHome.vue
  84. 174 0
      src/views/vent/monitorManager/beltTunMonitor/components/beltTunVentHome.vue
  85. 358 0
      src/views/vent/monitorManager/beltTunMonitor/index.vue
  86. 0 13
      src/views/vent/monitorManager/chamberMonitor/chamber.threejs.base.ts
  87. 322 253
      src/views/vent/monitorManager/chamberMonitor/components/chamberHome.vue
  88. 6 5
      src/views/vent/monitorManager/comment/AlarmHistoryTable.vue
  89. 12 13
      src/views/vent/monitorManager/comment/HandlerHistoryTable.vue
  90. 1 0
      src/views/vent/monitorManager/comment/HistoryTable.vue
  91. 167 0
      src/views/vent/monitorManager/comment/WorkFaceAlarmHistoryTable.vue
  92. 175 0
      src/views/vent/monitorManager/comment/WorkFaceHandlerHistoryTable.vue
  93. 649 0
      src/views/vent/monitorManager/comment/less/workFace.less
  94. 0 0
      src/views/vent/monitorManager/deviceMonitor/components/device/device.api.ts
  95. 0 0
      src/views/vent/monitorManager/deviceMonitor/components/device/device.data.ts
  96. 1109 0
      src/views/vent/monitorManager/deviceMonitor/components/device/index.vue
  97. 0 0
      src/views/vent/monitorManager/deviceMonitor/components/device/modal/bundle.modal.vue
  98. 0 0
      src/views/vent/monitorManager/deviceMonitor/components/device/modal/dust.modal.vue
  99. 0 0
      src/views/vent/monitorManager/deviceMonitor/components/device/modal/fiber.modal.vue
  100. 990 0
      src/views/vent/monitorManager/deviceMonitor/components/network/index.vue

+ 2 - 2
.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.4:9999"],["/upload","http://localhost:3300/upload"]]
+#VITE_PROXY = [["/jeecgsystem","http://192.168.1.8:9999"],["/upload","http://localhost:3300/upload"]]
 
 # 控制台不输出
 VITE_DROP_CONSOLE = false
@@ -19,7 +19,7 @@ VITE_GLOB_API_URL=/jeecgsystem
 
 #后台接口全路径地址(必填)
 VITE_GLOB_DOMAIN_URL=http://47.94.222.6:9999
-#VITE_GLOB_DOMAIN_URL=http://192.168.1.4:9999
+#VITE_GLOB_DOMAIN_URL=http://192.168.1.8:9999
 
 # 接口前缀
 VITE_GLOB_API_URL_PREFIX=

+ 5 - 2
.env.production

@@ -14,6 +14,7 @@ VITE_BUILD_COMPRESS = 'gzip'
 
 # 使用压缩时是否删除原始文件,默认为false
 VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
+#VITE_PROXY = [["/jeecgsystem","http://10.248.223.116: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.1.4:9999"],["/upload","http://localhost:3300/upload"]]
 #VITE_PROXY = [["/jeecgsystem","http://192.168.0.79:9999"],["/upload","http://localhost:3300/upload"]]
@@ -27,6 +28,7 @@ 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://10.248.223.50:9999
 #VITE_GLOB_DOMAIN_URL=http://192.168.1.4:9999
 #VITE_GLOB_DOMAIN_URL=http://192.168.0.79:9999
 #VITE_GLOB_DOMAIN_URL=http://127.0.0.1:9999
@@ -48,7 +50,8 @@ VITE_USE_PWA = false
 VITE_LEGACY = false
 
 #微前端qiankun应用,命名必须以VITE_APP_SUB_开头,jeecg-app-1为子应用的项目名称,也是子应用的路由父路径
-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 = [["micro-need-air", "//10.248.223.116:7777/"], ["micro-vent-3dModal", "//10.248.223.116:7121/"]]
+VITE_APP_SUB_APP = [["micro-need-air", "//47.94.222.6:7123/"], ["micro-vent-3dModal", "//47.94.222.6:7121/"]]
 #VITE_APP_SUB_APP = [["micro-vent-3dModal", "//192.168.0.79:7121/"]]
 #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/"]]
+#VITE_APP_SUB_APP = [["micro-need-air", "//127.0.0.1:7123/"], ["micro-vent-3dModal", "//127.0.0.1:7121/"]]  

+ 1 - 0
index.html

@@ -6,6 +6,7 @@
     <meta name="renderer" content="webkit" />
     <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0" />
     <title><%= title %></title>
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />
     <!-- <link rel="icon" href="/logo.png" /> -->
     <!-- 全局配置 -->
     <script>

+ 6 - 0
pnpm-lock.yaml

@@ -146,6 +146,7 @@ specifiers:
   vue-json-pretty: ^2.0.6
   vue-print-nb-jeecg: ^1.0.10
   vue-router: ^4.0.14
+  vue-tree-list: ^1.5.0
   vue-tsc: ^0.33.9
   vue-types: ^4.1.1
   vuedraggable: ^4.1.0
@@ -213,6 +214,7 @@ dependencies:
   vue-json-pretty: 2.2.3_vue@3.2.45
   vue-print-nb-jeecg: 1.0.11
   vue-router: 4.1.6_vue@3.2.45
+  vue-tree-list: 1.5.0
   vue-types: 4.2.1_vue@3.2.45
   vuedraggable: 4.1.0_vue@3.2.45
   vxe-table: 4.1.0_vue@3.2.45+xe-utils@3.5.7
@@ -12714,6 +12716,10 @@ packages:
       vue: 3.2.45
     dev: false
 
+  /vue-tree-list/1.5.0:
+    resolution: {integrity: sha512-qHRJtPMmjCYA9I9kpHgIT6F1H7leR1ZxcNETrP2r97otSHYdHdK42qt12t4glf2mNvI+wBpY2fLClUGcaQJnpg==}
+    dev: false
+
   /vue-tsc/0.33.9_typescript@4.9.4:
     resolution: {integrity: sha512-s/+r4JNsCh4e3MUdsYrjEA8IgPPDzHL5kEah/OznxIHd1XMlYiIkXGdiyU6JE5J+lzXNOKdOlNliqwwpeETQWw==}
     hasBin: true

BIN=BIN
public/model/glft/fire/tunFace_2023-06-29.glb


+ 0 - 0
public/model/glft/fire/workFace_2023-06-02.glb → public/model/glft/fire/workFace1_2023-06-02.glb


BIN=BIN
public/model/glft/fire/workFace_2023-06-29.glb


+ 9 - 0
src/assets/icons/CO-title.svg

@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="15.762" height="13.406" viewBox="0 0 15.762 13.406">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3df6ff"/>
+      <stop offset="1" stop-color="#b3fff5"/>
+    </linearGradient>
+  </defs>
+  <path id="路径_55482" data-name="路径 55482" d="M29.786,124.315a7.381,7.381,0,1,0-10.8,0Zm-2.253-1.345a.82.82,0,1,1,.82-.82A.819.819,0,0,1,27.534,122.97Zm1.725-4.358a.82.82,0,1,1-1.159,0A.82.82,0,0,1,29.259,118.612ZM27.4,115.468a.82.82,0,1,1-.82.82A.819.819,0,0,1,27.4,115.468Zm-.552,2.212-2.078,2-.76-.787,2.078-2Zm-2.988-3.116a.82.82,0,1,1,0,1.159A.82.82,0,0,1,23.857,114.563Zm-2.187,8.546a.82.82,0,1,1,.82-.82A.819.819,0,0,1,21.67,123.109Zm-.137-7.5a.82.82,0,1,1-.82.82A.819.819,0,0,1,21.533,115.6Zm-1.725,3.2a.82.82,0,1,1,0,1.159A.82.82,0,0,1,19.808,118.806Z" transform="translate(-16.506 -111.409)" stroke="rgba(0,0,0,0)" stroke-width="1" fill="url(#linear-gradient)"/>
+</svg>

+ 8 - 0
src/assets/icons/O2-aveg.svg

@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="47" height="60" viewBox="0 0 47 60">
+  <g id="组_13757" data-name="组 13757" transform="translate(-1548 -548)">
+    <g id="组_13752" data-name="组 13752" transform="translate(-123 188)">
+      <text id="O_" data-name="O₂" transform="translate(1671 409)" fill="#fff" font-size="45" font-family="Kingsoft_Cloud_Font"><tspan x="0" y="0">O</tspan><tspan y="0" font-family="SegoeUI-Bold, Segoe UI" font-weight="700">₂</tspan></text>
+    </g>
+    <path id="路径_55532" data-name="路径 55532" d="M64,120.4v3.189H79.763V120.4Zm0,19.507H79.763v-3.189H64Zm0-8.157H79.763V128.56H64Z" transform="translate(1514.237 428.6)" fill="#3df6ff"/>
+  </g>
+</svg>

+ 10 - 0
src/assets/icons/O2-low.svg

@@ -0,0 +1,10 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="47" height="60" viewBox="0 0 47 60">
+  <g id="组_13756" data-name="组 13756" transform="translate(-1652 -548)">
+    <text id="O_" data-name="O₂" transform="translate(1652 597)" fill="#fff" font-size="45" font-family="Kingsoft_Cloud_Font"><tspan x="0" y="0">O</tspan><tspan y="0" font-family="SegoeUI-Bold, Segoe UI" font-weight="700">₂</tspan></text>
+    <g id="组_13753" data-name="组 13753" transform="translate(0 141)">
+      <g id="组_13620" data-name="组 13620" transform="translate(-19 -22.778)">
+        <path id="路径_55370" data-name="路径 55370" d="M283.9,158.66v13h2.627v-13l2.759,2.759,1.839-1.97-5.911-5.911-5.911,5.911,1.839,1.839Zm-6.568-6.7H293.1v-2.627H277.333Z" transform="translate(1423.904 280.445)" fill="#3df6ff"/>
+      </g>
+    </g>
+  </g>
+</svg>

+ 8 - 0
src/assets/icons/O2-top.svg

@@ -0,0 +1,8 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="47" height="60" viewBox="0 0 47 60">
+  <g id="组_13755" data-name="组 13755" transform="translate(-1756 -548)">
+    <g id="组_13754" data-name="组 13754" transform="translate(85 118.222)">
+      <text id="O_" data-name="O₂" transform="translate(1671 478.778)" fill="#fff" font-size="45" font-family="Kingsoft_Cloud_Font"><tspan x="0" y="0">O</tspan><tspan y="0" font-family="SegoeUI-Bold, Segoe UI" font-weight="700">₂</tspan></text>
+    </g>
+    <path id="路径_55533" data-name="路径 55533" d="M283.9,162.338v-13h2.627v13l2.759-2.759,1.839,1.97-5.911,5.911L279.3,161.55l1.839-1.839Zm-6.568,6.7H293.1v2.627H277.333Z" transform="translate(1508.904 398.666)" fill="#3df6ff"/>
+  </g>
+</svg>

+ 19 - 0
src/assets/icons/beamTube-title.svg

@@ -0,0 +1,19 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14" height="14" viewBox="0 0 14 14">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3df6ff"/>
+      <stop offset="1" stop-color="#b3fff5"/>
+    </linearGradient>
+  </defs>
+  <g id="组_13570" data-name="组 13570" transform="translate(-522 -703)">
+    <path id="椭圆_2583" data-name="椭圆 2583" d="M7,1a6,6,0,1,0,6,6A6.007,6.007,0,0,0,7,1M7,0A7,7,0,1,1,0,7,7,7,0,0,1,7,0Z" transform="translate(522 703)" fill="url(#linear-gradient)"/>
+    <path id="路径_55457" data-name="路径 55457" d="M2.881.323a2,2,0,1,0,2,2,2,2,0,0,0-2-2m0-.5a2.5,2.5,0,1,1-2.5,2.5A2.5,2.5,0,0,1,2.881-.177Z" transform="translate(524 704)" fill="url(#linear-gradient)"/>
+    <path id="椭圆_2585" data-name="椭圆 2585" d="M2,.5A1.5,1.5,0,1,0,3.5,2,1.5,1.5,0,0,0,2,.5M2,0A2,2,0,1,1,0,2,2,2,0,0,1,2,0Z" transform="translate(529 704)" fill="url(#linear-gradient)"/>
+    <path id="路径_55458" data-name="路径 55458" d="M1.782.022A1.739,1.739,0,1,0,3.521,1.761,1.741,1.741,0,0,0,1.782.022m0-.5A2.239,2.239,0,1,1-.457,1.761,2.239,2.239,0,0,1,1.782-.478Z" transform="translate(527.338 708.239)" fill="url(#linear-gradient)"/>
+    <path id="椭圆_2586" data-name="椭圆 2586" d="M2,.5A1.5,1.5,0,1,0,3.5,2,1.5,1.5,0,0,0,2,.5M2,0A2,2,0,1,1,0,2,2,2,0,0,1,2,0Z" transform="translate(531 707)" fill="url(#linear-gradient)"/>
+    <path id="路径_55454" data-name="路径 55454" d="M1.719.076A1.713,1.713,0,1,0,3.432,1.789,1.715,1.715,0,0,0,1.719.076m0-.5A2.213,2.213,0,1,1-.494,1.789,2.213,2.213,0,0,1,1.719-.424Z" transform="translate(528.037 712.574)" fill="url(#linear-gradient)"/>
+    <path id="路径_55455" data-name="路径 55455" d="M1.241-.2A1.649,1.649,0,1,0,2.89,1.448,1.651,1.651,0,0,0,1.241-.2m0-.5A2.149,2.149,0,1,1-.908,1.448,2.149,2.149,0,0,1,1.241-.7Z" transform="translate(525 711.702)" fill="url(#linear-gradient)"/>
+    <path id="路径_55456" data-name="路径 55456" d="M1.345-.2A1.753,1.753,0,1,0,3.1,1.551,1.755,1.755,0,0,0,1.345-.2m0-.5A2.253,2.253,0,1,1-.908,1.551,2.253,2.253,0,0,1,1.345-.7Z" transform="translate(523 708.196)" fill="url(#linear-gradient)"/>
+    <path id="路径_55459" data-name="路径 55459" d="M.885-.108a1.5,1.5,0,1,0,1.5,1.5,1.5,1.5,0,0,0-1.5-1.5m0-.5a2,2,0,1,1-2,2A2,2,0,0,1,.885-.608Z" transform="translate(531.908 711.065)" fill="url(#linear-gradient)"/>
+  </g>
+</svg>

+ 9 - 0
src/assets/icons/control-setting.svg

@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="13.68" height="12.095" viewBox="0 0 13.68 12.095">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3df6ff"/>
+      <stop offset="1" stop-color="#b3fff5"/>
+    </linearGradient>
+  </defs>
+  <path id="路径_55524" data-name="路径 55524" d="M180.177,222.051v-.792h1.585v.792h1.585v1.585h-1.585v.792h-1.585v-.792h-9.51v-1.585Zm-3.962-3.962V217.3H177.8v.793h5.548v1.585H177.8v.792h-1.585v-.792h-5.548v-1.585Zm-3.963-3.963v-.792h1.585v.792h9.51v1.585h-9.51v.792h-1.585v-.792h-1.585v-1.585Z" transform="translate(-170.167 -212.833)" stroke="rgba(0,0,0,0)" stroke-width="1" fill="url(#linear-gradient)"/>
+</svg>

+ 9 - 0
src/assets/icons/dianji-title.svg

@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14.31" height="14.309" viewBox="0 0 14.31 14.309">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3df6ff"/>
+      <stop offset="1" stop-color="#b3fff5"/>
+    </linearGradient>
+  </defs>
+  <path id="路径_55426" data-name="路径 55426" d="M12.478,1.608A9.518,9.518,0,0,0,6.655,0,9.518,9.518,0,0,0,.832,1.608,2.022,2.022,0,0,0,0,3.12V7.876A.166.166,0,0,0,0,7.9H0v2.288c0,1.722,2.979,3.12,6.655,3.12s6.655-1.4,6.655-3.12V7.9h0c0-.023,0-.045,0-.069V3.12A2.022,2.022,0,0,0,12.478,1.608ZM.832,4.631A9.518,9.518,0,0,0,6.655,6.239a9.518,9.518,0,0,0,5.823-1.608V5.661a6.607,6.607,0,0,1-.764.419,12.23,12.23,0,0,1-5.059.992A12.209,12.209,0,0,1,1.6,6.078a6.607,6.607,0,0,1-.764-.419V4.631Zm0,2.357A9.518,9.518,0,0,0,6.655,8.6a9.518,9.518,0,0,0,5.823-1.608V8.017a6.808,6.808,0,0,1-.764.419,12.235,12.235,0,0,1-5.059.992A12.235,12.235,0,0,1,1.6,8.436a6.607,6.607,0,0,1-.764-.419Zm10.882,3.8a12.235,12.235,0,0,1-5.059.992A12.235,12.235,0,0,1,1.6,10.792a6.935,6.935,0,0,1-.733-.4.7.7,0,0,1-.031-.2V9.346a9.518,9.518,0,0,0,5.823,1.608,9.526,9.526,0,0,0,5.823-1.608v.845a.708.708,0,0,1-.031.2A6.706,6.706,0,0,1,11.714,10.792Z" transform="translate(0.5 0.5)" stroke="rgba(0,0,0,0)" stroke-miterlimit="10" stroke-width="1" fill="url(#linear-gradient)"/>
+</svg>

+ 9 - 0
src/assets/icons/fdbs.svg

@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="11.121" height="13.146" viewBox="0 0 11.121 13.146">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3df6ff"/>
+      <stop offset="1" stop-color="#b3fff5"/>
+    </linearGradient>
+  </defs>
+  <path id="路径_55526" data-name="路径 55526" d="M192.506,133.061h1.518v-2.024a3.036,3.036,0,0,1,6.073,0v2.024h1.518a.508.508,0,0,1,.506.506v6.073a.508.508,0,0,1-.506.506h-9.109a.508.508,0,0,1-.506-.506v-6.073A.508.508,0,0,1,192.506,133.061Zm4.555,4.555a1.012,1.012,0,1,0-1.012-1.012A1.015,1.015,0,0,0,197.061,137.615Zm-2.024-4.555h4.049v-2.024a2.024,2.024,0,1,0-4.049,0Z" transform="translate(-191.5 -127.5)" stroke="rgba(0,0,0,0)" stroke-width="1" fill="url(#linear-gradient)"/>
+</svg>

+ 22 - 0
src/assets/icons/fiber-title.svg

@@ -0,0 +1,22 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14.862" height="14.397" viewBox="0 0 14.862 14.397">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3df6ff"/>
+      <stop offset="1" stop-color="#b3fff5"/>
+    </linearGradient>
+  </defs>
+  <g id="组_13534" data-name="组 13534" transform="translate(-550.616 -678.559)">
+    <path id="路径_55460" data-name="路径 55460" d="M-18853.848,4261.253l-.227-.332c.27-.184,6.621-4.514,8.908-5.177l.111.386C-18847.279,4256.775-18853.781,4261.208-18853.848,4261.253Z" transform="translate(19410.531 -3573.261)" fill="url(#linear-gradient)"/>
+    <path id="路径_55461" data-name="路径 55461" d="M-18854.439,4258.433l-.246-.319,8.2-6.3.246.319Z" transform="translate(19410.494 -3570.736)" fill="url(#linear-gradient)"/>
+    <path id="路径_55464" data-name="路径 55464" d="M.25,6.722,0,6.407,8.089,0l.249.315Z" transform="matrix(0.996, 0.087, -0.087, 0.996, 556.219, 681.331)" fill="url(#linear-gradient)"/>
+    <path id="路径_55463" data-name="路径 55463" d="M.245,6.623,0,6.3,8.2,0l.246.319Z" transform="matrix(0.998, -0.07, 0.07, 0.998, 554.767, 681.376)" fill="url(#linear-gradient)"/>
+    <path id="路径_55465" data-name="路径 55465" d="M.245,6.623,0,6.3,8.2,0l.246.319Z" transform="translate(554.019 681.415) rotate(-8)" fill="url(#linear-gradient)"/>
+    <path id="路径_55462" data-name="路径 55462" d="M.279,7.625,0,7.336C1.756,5.638,6.387,1.011,6.722,0L7.1.127A7.241,7.241,0,0,1,5.827,1.894c-.582.671-1.361,1.511-2.315,2.5C1.888,6.069.3,7.609.279,7.625Z" transform="matrix(0.998, -0.07, 0.07, 0.998, 555.119, 679.055)" fill="url(#linear-gradient)"/>
+    <g id="组_13474" data-name="组 13474" transform="translate(554.94 684.987) rotate(45)">
+      <path id="路径_55459" data-name="路径 55459" d="M3.056,2.128H.353C.158,2.128,0,1.908,0,1.638V0H3.408V1.638C3.408,1.908,3.25,2.128,3.056,2.128Z" transform="translate(0.873 0)" fill="url(#linear-gradient)"/>
+      <path id="路径_55458" data-name="路径 55458" d="M.6,4,.981,2.278H0L.006,2.27,1.873,0,1.456,1.643h.993ZM.02,2.269H.992v.006L.62,3.957,2.43,1.652H1.444L1.853.039.02,2.269Z" transform="translate(1.356 1.302)" fill="url(#linear-gradient)"/>
+      <path id="路径_55456" data-name="路径 55456" d="M1.572,2.128H.181c-.1,0-.181-.219-.181-.49V0H1.753V1.638C1.754,1.908,1.672,2.128,1.572,2.128Z" transform="translate(1.7 5.689)" fill="url(#linear-gradient)"/>
+      <path id="路径_55454" data-name="路径 55454" d="M5.043.07A.066.066,0,0,0,4.984,0H.068A.066.066,0,0,0,.008.07s-.019.739,0,.984C.056,1.68.295,2.91.336,3.536c0,0,0,0,0,0,.444.527,1.113.66,1.26,1.268a.315.315,0,0,0,.289.262H3.167a.315.315,0,0,0,.289-.262c.147-.608.816-.741,1.26-1.268,0,0,0,0,0,0C4.757,2.91,5,1.68,5.043,1.055,5.062.81,5.043.07,5.043.07Z" transform="translate(0 0.903)" fill="url(#linear-gradient)"/>
+    </g>
+  </g>
+</svg>

+ 19 - 0
src/assets/icons/jizu-title.svg

@@ -0,0 +1,19 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12.056" height="13.502" viewBox="0 0 12.056 13.502">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3df6ff"/>
+      <stop offset="1" stop-color="#b3fff5"/>
+    </linearGradient>
+  </defs>
+  <g id="组_13324" data-name="组 13324" transform="translate(-54.857 0)">
+    <path id="路径_55417" data-name="路径 55417" d="M128,0m.294,0h.858a.26.26,0,0,1,.294.294V8.056a.26.26,0,0,1-.294.294h-.858A.26.26,0,0,1,128,8.056V.294A.26.26,0,0,1,128.294,0Z" transform="translate(-72.179 0)" fill="url(#linear-gradient)"/>
+    <path id="路径_55418" data-name="路径 55418" d="M128,776.229m.294,0h.858a.26.26,0,0,1,.294.294V779.2a.26.26,0,0,1-.294.294h-.858A.26.26,0,0,1,128,779.2v-2.679A.26.26,0,0,1,128.294,776.229Z" transform="translate(-72.179 -765.994)" fill="url(#linear-gradient)"/>
+    <path id="路径_55419" data-name="路径 55419" d="M786.286,0m.294,0h.858a.26.26,0,0,1,.294.294V8a.26.26,0,0,1-.294.294h-.858A.26.26,0,0,1,786.286,8V.294A.26.26,0,0,1,786.58,0Z" transform="translate(-721.785 0)" fill="url(#linear-gradient)"/>
+    <path id="路径_55420" data-name="路径 55420" d="M786.286,779.154m.294,0h.858a.26.26,0,0,1,.294.294v2.64a.26.26,0,0,1-.294.294h-.858a.26.26,0,0,1-.294-.294v-2.64A.26.26,0,0,1,786.58,779.154Z" transform="translate(-721.785 -768.88)" fill="url(#linear-gradient)"/>
+    <path id="路径_55421" data-name="路径 55421" d="M457.143,390.949m.294,0h.858a.26.26,0,0,1,.294.294V399a.26.26,0,0,1-.294.294h-.858a.26.26,0,0,1-.294-.294v-7.759A.26.26,0,0,1,457.437,390.949Z" transform="translate(-396.982 -385.794)" fill="url(#linear-gradient)"/>
+    <path id="路径_55422" data-name="路径 55422" d="M56.545,586.831m-1.688,0a1.688,1.688,0,1,0,1.688-1.688A1.688,1.688,0,0,0,54.857,586.831Z" transform="translate(0 -577.427)" fill="url(#linear-gradient)"/>
+    <path id="路径_55423" data-name="路径 55423" d="M385.688,179.974m-1.688,0a1.688,1.688,0,1,0,1.688-1.688A1.688,1.688,0,0,0,384,179.974Z" transform="translate(-324.803 -175.935)" fill="url(#linear-gradient)"/>
+    <path id="路径_55424" data-name="路径 55424" d="M714.831,586.831m-1.688,0a1.688,1.688,0,1,0,1.688-1.688A1.688,1.688,0,0,0,713.143,586.831Z" transform="translate(-649.606 -577.427)" fill="url(#linear-gradient)"/>
+    <path id="路径_55425" data-name="路径 55425" d="M457.143,0m.294,0h.858a.26.26,0,0,1,.294.294v2.38a.26.26,0,0,1-.294.294h-.858a.26.26,0,0,1-.294-.294V.294A.26.26,0,0,1,457.437,0Z" transform="translate(-396.982 0)" fill="url(#linear-gradient)"/>
+  </g>
+</svg>

+ 9 - 0
src/assets/icons/nitrogen-title.svg

@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="6.882" height="14.955" viewBox="0 0 6.882 14.955">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3df6ff"/>
+      <stop offset="1" stop-color="#b3fff5"/>
+    </linearGradient>
+  </defs>
+  <path id="路径_55487" data-name="路径 55487" d="M1.647,14c-.208-.12-.395-.226-.578-.34-.025-.015-.033-.072-.033-.109,0-.332,0-.664,0-1a.157.157,0,0,0-.09-.156,1.783,1.783,0,0,1-.577-.5.986.986,0,0,1-.187-.8A1.08,1.08,0,0,0,.2,10.884,1.156,1.156,0,0,1,.3,10.4a.779.779,0,0,0,.04-.262C.352,10,.351,9.86.351,9.72q0-2.545,0-5.09a.7.7,0,0,0-.128-.418,1.348,1.348,0,0,1,.226-1.77c.218-.179.423-.376.642-.554A2.553,2.553,0,0,1,2.452,1.31c.078-.009.122-.039.111-.125a.23.23,0,0,1,0-.062A.178.178,0,0,0,2.431.9.379.379,0,0,1,2.172.543.405.405,0,0,1,2.422.1a1.089,1.089,0,0,1,.948.014.416.416,0,0,1,.221.458.331.331,0,0,1-.235.32c-.176.054-.2.164-.182.317,0,.021,0,.042,0,.073.128.021.255.042.382.066a2.412,2.412,0,0,1,1.381.794,3.129,3.129,0,0,0,.335.274,1.227,1.227,0,0,1,.473.766A1.376,1.376,0,0,1,5.558,4.2a.914.914,0,0,0-.172.53c.005,1.669,0,3.338,0,5.007,0,.175,0,.35.012.525a.2.2,0,0,0,.034.1,1.32,1.32,0,0,1,.134.853,1.708,1.708,0,0,1-.068.375,1.254,1.254,0,0,1-.5.664.263.263,0,0,0-.121.249c.006.335,0,.67,0,1.005a.154.154,0,0,1-.089.156c-.154.083-.306.174-.456.265a.127.127,0,0,1-.151,0c-.159-.1-.32-.191-.483-.28a.136.136,0,0,1-.077-.141c0-.228,0-.455,0-.7-.174.015-.332.039-.489.04-.255,0-.51-.007-.764-.017-.074,0-.087.03-.087.092,0,.211,0,.422,0,.632,0,.037-.012.092-.037.108-.18.113-.366.218-.571.337" transform="translate(0.614 0.502)" stroke="rgba(0,0,0,0)" stroke-width="1" fill="url(#linear-gradient)"/>
+</svg>

+ 9 - 0
src/assets/icons/param-setting.svg

@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12.119" height="12.029" viewBox="0 0 12.119 12.029">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3df6ff"/>
+      <stop offset="1" stop-color="#b3fff5"/>
+    </linearGradient>
+  </defs>
+  <path id="路径_55527" data-name="路径 55527" d="M74.572,70.549l-.936-.709a2.691,2.691,0,0,0,0-.65l.936-.709a.638.638,0,0,0,.158-.837l-1.044-1.763a.674.674,0,0,0-.581-.335.611.611,0,0,0-.226.039l-1.113.433a3.776,3.776,0,0,0-.581-.325l-.167-1.132a.659.659,0,0,0-.66-.561H68.25a.66.66,0,0,0-.66.551l-.158,1.142a4.3,4.3,0,0,0-.581.325l-1.113-.433a.662.662,0,0,0-.236-.039.638.638,0,0,0-.571.325l-1.054,1.773a.642.642,0,0,0,.158.837l.936.709c-.01.118-.02.226-.02.325a1.912,1.912,0,0,0,.02.325l-.936.709a.638.638,0,0,0-.158.837l1.044,1.763a.674.674,0,0,0,.581.335.611.611,0,0,0,.226-.039l1.113-.433a3.777,3.777,0,0,0,.581.325l.167,1.132a.661.661,0,0,0,.66.561h2.107a.66.66,0,0,0,.66-.551l.167-1.142a4.3,4.3,0,0,0,.581-.325l1.113.433a.662.662,0,0,0,.236.039.638.638,0,0,0,.571-.325l1.054-1.782A.641.641,0,0,0,74.572,70.549Zm-2.905-1.034A2.363,2.363,0,1,1,69.3,67.151,2.37,2.37,0,0,1,71.667,69.515Z" transform="translate(-63.241 -63.5)" stroke="rgba(0,0,0,0)" stroke-width="1" fill="url(#linear-gradient)"/>
+</svg>

+ 9 - 0
src/assets/icons/person.svg

@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="17.002" height="17" viewBox="0 0 17.002 17">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3df6ff"/>
+      <stop offset="1" stop-color="#b3fff5"/>
+    </linearGradient>
+  </defs>
+  <path id="路径_55528" data-name="路径 55528" d="M13.607,15.983a.459.459,0,0,0,.436-.471l0-.165h.008c.006-.12.009-.225.009-.327A6.881,6.881,0,0,0,10.047,8.61l-.274-.118.242-.175A4.645,4.645,0,0,0,11.88,4.542,4.379,4.379,0,0,0,7.692,0,4.379,4.379,0,0,0,3.5,4.542,4.645,4.645,0,0,0,5.368,8.317l.242.175-.274.118a6.886,6.886,0,0,0-4.014,6.409c0,.1,0,.2.009.327h.011l0,.169A.465.465,0,0,0,1.782,16c.242,0,11.586-.019,11.824-.019M12.53,8.9a4.19,4.19,0,0,1,2.8,1.6,5.384,5.384,0,0,1,1.1,3.327.474.474,0,0,0,.447.5.468.468,0,0,0,.443-.475l0-.015a.011.011,0,0,1,0-.008A5.728,5.728,0,0,0,13.98,8.5l-.274-.118.242-.175A3.852,3.852,0,0,0,15.5,5.073a3.7,3.7,0,0,0-2.648-3.657l-.009,0-.043,0a.145.145,0,0,1-.028,0l-.011,0a.481.481,0,0,0-.453.5.485.485,0,0,0,.385.5l.021,0,.019.008a.8.8,0,0,0,.1.032l.019.006h0a2.716,2.716,0,0,1,1.715,2.577,2.681,2.681,0,0,1-2.04,2.671l-.019.011-.039,0a.591.591,0,0,0,.013,1.17l.038,0,.017.011h0m0,0" transform="translate(-0.822 0.498)" stroke="rgba(0,0,0,0)" stroke-width="1" fill="url(#linear-gradient)"/>
+</svg>

+ 9 - 0
src/assets/icons/plsz.svg

@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="15.321" height="11.291" viewBox="0 0 15.321 11.291">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3df6ff"/>
+      <stop offset="1" stop-color="#b3fff5"/>
+    </linearGradient>
+  </defs>
+  <path id="路径_55525" data-name="路径 55525" d="M182.371,271.2a.674.674,0,0,1,.624.421l2.956,7.393,1.167-2.917a.672.672,0,0,1,.624-.421h2.909a.671.671,0,1,1,0,1.342h-2.456l-1.622,4.052a.673.673,0,0,1-1.248,0l-2.954-7.39L181.2,276.6a.672.672,0,0,1-.624.421h-2.909a.671.671,0,1,1,0-1.342h2.453l1.622-4.052A.67.67,0,0,1,182.371,271.2Z" transform="translate(-176.5 -270.7)" stroke="rgba(0,0,0,0)" stroke-width="1" fill="url(#linear-gradient)"/>
+</svg>

+ 9 - 0
src/assets/icons/pulp-title.svg

@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="10.995" height="12.883" viewBox="0 0 10.995 12.883">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3df6ff"/>
+      <stop offset="1" stop-color="#b3fff5"/>
+    </linearGradient>
+  </defs>
+  <path id="路径_55486" data-name="路径 55486" d="M9.995.988v.058a1.7,1.7,0,0,0-.017.171V5.175a1.7,1.7,0,0,0,.017.171v.029c-.047.066-.1.129-.142.2Q8.822,7.263,7.794,8.955L7.049,10.18l1.2.762v.941H2.964v-.946l1.213-.773L3.054,8.714q-1.238-1.6-2.479-3.2A.484.484,0,0,1,.465,5.19c0-1.035,0-2.071,0-3.106v-.2L0,1.947V1.366l.466.021V1.235c0-.3,0-.3.3-.368.163-.037.329-.065.5-.1,0-.032,0-.056.008-.08.014-.111,0-.305.047-.318A.36.36,0,0,0,1.562.158c.011-.024.07-.024.107-.037L2,0h.087a.4.4,0,0,0,.46.264C3.126.23,3.7.211,4.277.213,5.515.219,6.754.238,7.992.262c.352.007.7.049,1.056.074.1.007.143.056.133.161a2.365,2.365,0,0,0,0,.242ZM1.6.258l.013.048L2.118.269,2.126.217c-.045-.026-.1-.08-.134-.072A3.9,3.9,0,0,0,1.6.258Z" transform="translate(0.5 0.5)" stroke="rgba(0,0,0,0)" stroke-width="1" fill="url(#linear-gradient)"/>
+</svg>

+ 12 - 0
src/assets/icons/shandian.svg

@@ -0,0 +1,12 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="7.896" height="11.673" viewBox="0 0 7.896 11.673">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3df6ff"/>
+      <stop offset="1" stop-color="#b3fff5"/>
+    </linearGradient>
+  </defs>
+  <g id="组_13722" data-name="组 13722" transform="translate(-200.9 -66.9)">
+    <path id="路径_55530" data-name="路径 55530" d="M207.214,72.773H203.3l3.914-5.873h3.7Z" transform="translate(-2.369)" fill="url(#linear-gradient)"/>
+    <path id="路径_55531" data-name="路径 55531" d="M200.9,369.83l3.981-7.83H208.8" transform="translate(0 -291.257)" fill="url(#linear-gradient)"/>
+  </g>
+</svg>

+ 12 - 0
src/assets/icons/smoke-title.svg

@@ -0,0 +1,12 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14.413" height="13.751" viewBox="0 0 14.413 13.751">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3df6ff"/>
+      <stop offset="1" stop-color="#b3fff5"/>
+    </linearGradient>
+  </defs>
+  <g id="组_13545" data-name="组 13545" transform="translate(-13.724 -13.748)">
+    <path id="路径_55484" data-name="路径 55484" d="M285.683,279.336a2.5,2.5,0,0,1,2.578.849,1.19,1.19,0,0,0,1.255.506,2.661,2.661,0,0,1,2.638,1.222,2.958,2.958,0,0,1,.217,2.965,1.328,1.328,0,0,0-.046.907,3.678,3.678,0,0,1-.379,3.765,3.625,3.625,0,0,1-3.705,1.469,1.4,1.4,0,0,0-1.28.354,2.658,2.658,0,0,1-4.271-1.145c.38-.163.639-.324.947.179a1.7,1.7,0,0,0,1.779.816A1.945,1.945,0,0,0,287.1,289.6c.355-.017.755-.214.789.391,0,.068.156.148.254.187a2.984,2.984,0,0,0,3.026-.939,3.113,3.113,0,0,0,.45-3,1.03,1.03,0,0,0-.177-.193l-1.119.391-.242-.674.222-.11.421-.21a2.117,2.117,0,0,0-1.068-3.991c-.454.025-.784.168-.738.72a2.969,2.969,0,0,1-.1.657c-.469-.032-.714-.15-.687-.673a1.894,1.894,0,0,0-1.352-2.015,1.853,1.853,0,0,0-2.083.716c-.337.432-.59.383-.958.019a2.435,2.435,0,0,1,1.945-1.539Zm-6.067,6.444.082.006c2.3.258,4.587.543,6.959.828l-.092.775-7.268-.861c.023-.372-.18-.808.4-.743Zm6.957-1.871.048.766-7.293.446-.045-.8,7.29-.411Z" transform="translate(-265.031 -265.026)" fill="url(#linear-gradient)"/>
+    <path id="路径_55484_-_轮廓" data-name="路径 55484 - 轮廓" d="M286.329,278.774a2.851,2.851,0,0,1,2.324,1.1.656.656,0,0,0,.593.333,1.784,1.784,0,0,0,.21-.014,3.707,3.707,0,0,1,.437-.026,3.132,3.132,0,0,1,2.674,1.464,3.451,3.451,0,0,1,.265,3.436.851.851,0,0,0-.043.532,4.164,4.164,0,0,1-.441,4.246,4.062,4.062,0,0,1-3.371,1.731,5.328,5.328,0,0,1-.814-.065,1.712,1.712,0,0,0-.261-.023.854.854,0,0,0-.614.259,3.121,3.121,0,0,1-2.084.775,3.023,3.023,0,0,1-3-2.183l-.1-.408.385-.166.073-.032a1.512,1.512,0,0,1,.618-.169,1.031,1.031,0,0,1,.879.577,1.207,1.207,0,0,0,1.036.606,1.343,1.343,0,0,0,.23-.02,1.454,1.454,0,0,0,1.278-1.237l.08-.377.385-.018c.044,0,.1-.01.157-.018a2.128,2.128,0,0,1,.3-.027.81.81,0,0,1,.825.667,1.483,1.483,0,0,0,.5.08,2.785,2.785,0,0,0,1.938-.9,2.745,2.745,0,0,0,.453-2.258l-1.23.43-.56-1.56,1.04-.518a1.712,1.712,0,0,0,.767-1.975,1.742,1.742,0,0,0-1.525-1.071l-.059,0a.685.685,0,0,0-.262.048.4.4,0,0,0,0,.132,1.9,1.9,0,0,1-.062.576c-.015.07-.03.135-.04.2l-.072.451-.456-.031a1.062,1.062,0,0,1-1.152-1.2,1.392,1.392,0,0,0-1.021-1.518,1.13,1.13,0,0,0-.382-.066,1.479,1.479,0,0,0-1.138.619,1.133,1.133,0,0,1-.853.5,1.245,1.245,0,0,1-.85-.433l-.236-.234.124-.308a2.945,2.945,0,0,1,2.318-1.844A4.089,4.089,0,0,1,286.329,278.774Zm2.528,2.395a1.478,1.478,0,0,1-.418-.16,2.4,2.4,0,0,1,.138.444.957.957,0,0,1,.084-.112A.982.982,0,0,1,288.857,281.169ZM287.69,290.5a.7.7,0,0,1-.258-.293,2.576,2.576,0,0,1-.211.412A1.723,1.723,0,0,1,287.69,290.5Zm-.649-7.12.111,1.761-5.659.346c1.092.128,2.188.261,3.325.4l1.9.23.5.06L287,287.944l-8.233-.975.029-.472a1.565,1.565,0,0,0-.007-.19,1.113,1.113,0,0,1,.095-.659l-.027,0-.1-1.8Z" transform="translate(-265.031 -265.026)" fill="url(#linear-gradient)"/>
+  </g>
+</svg>

+ 9 - 0
src/assets/icons/temperature-title.svg

@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="9.672" height="15.852" viewBox="0 0 9.672 15.852">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3df6ff"/>
+      <stop offset="1" stop-color="#b3fff5"/>
+    </linearGradient>
+  </defs>
+  <path id="路径_55485" data-name="路径 55485" d="M217.915,9.142V5.158a.44.44,0,0,0-.439-.439h-.035a.426.426,0,0,0-.426.426v4a1.547,1.547,0,0,0-1.136,1.475,1.586,1.586,0,1,0,2.036-1.475Zm2.333-1.765a.4.4,0,0,1-.157-.3v-4.5a2.628,2.628,0,0,0-5.256,0V6.945a.626.626,0,0,1-.213.48,4.177,4.177,0,0,0-1.494,3.193,4.337,4.337,0,0,0,8.672,0A4.177,4.177,0,0,0,220.249,7.377Zm-2.784,6.13a2.934,2.934,0,0,1-2.97-2.89,2.863,2.863,0,0,1,1.388-2.442l.21-.129a.233.233,0,0,0,.11-.2V2.568a1.264,1.264,0,0,1,2.526,0v5.28a.233.233,0,0,0,.11.2l.21.129a2.86,2.86,0,0,1,1.386,2.442,2.937,2.937,0,0,1-2.972,2.89Z" transform="translate(-212.629 0.5)" stroke="rgba(0,0,0,0)" stroke-width="1" fill="url(#linear-gradient)"/>
+</svg>

+ 9 - 0
src/assets/icons/warning-analyze-title.svg

@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="15.588" height="13.877" viewBox="0 0 15.588 13.877">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3df6ff"/>
+      <stop offset="1" stop-color="#b3fff5"/>
+    </linearGradient>
+  </defs>
+  <path id="路径_55428" data-name="路径 55428" d="M14.6,11.6,8.314.722a.994.994,0,0,0-1.726,0L.3,11.6a1,1,0,0,0,.867,1.5H13.735a1,1,0,0,0,.863-1.5ZM6.741,4.609a.716.716,0,1,1,1.432,0V8.344a.725.725,0,0,1-1.421,0Zm1.432,7.426H6.723v-1.45h1.45Z" transform="translate(0.343 0.279)" stroke="rgba(0,0,0,0)" stroke-miterlimit="10" stroke-width="1" fill="url(#linear-gradient)"/>
+</svg>

+ 9 - 0
src/assets/icons/warning-title.svg

@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14.825" height="14.752" viewBox="0 0 14.825 14.752">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3df6ff"/>
+      <stop offset="1" stop-color="#b3fff5"/>
+    </linearGradient>
+  </defs>
+  <path id="路径_55427" data-name="路径 55427" d="M16.944,12.754h-1V8.142a4.74,4.74,0,1,1,9.48,0v4.612H16.945Zm4.087-7.442L18.693,9.163h1.87L20.1,12.051,22.433,8.2h-1.87l.468-2.888Zm3.586-4.23a.462.462,0,0,1,.168.629l-.84,1.461-.794-.46.84-1.461a.457.457,0,0,1,.624-.17h0ZM20.687,0a.481.481,0,0,1,.5.464V2.12H20.19V.463a.481.481,0,0,1,.5-.463ZM16.76,1.082a.458.458,0,0,1,.627.168l.84,1.461-.794.46L16.591,1.71a.461.461,0,0,1,.168-.628ZM13.884,3.97A.457.457,0,0,1,14.51,3.8l1.456.845-.458.8L14.052,4.6a.461.461,0,0,1-.168-.628Zm13.609,0a.462.462,0,0,1-.168.629l-1.456.844-.458-.8L26.866,3.8a.458.458,0,0,1,.625.166s0,0,0,0ZM14.324,12.754h12.73a.5.5,0,1,1,0,1H14.324a.5.5,0,1,1,0-1Z" transform="translate(-13.276 0.5)" stroke="rgba(0,0,0,0)" stroke-width="1" fill="url(#linear-gradient)"/>
+</svg>

+ 9 - 0
src/assets/icons/ytws.svg

@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14.201" height="10.901" viewBox="0 0 14.201 10.901">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3df6ff"/>
+      <stop offset="1" stop-color="#b3fff5"/>
+    </linearGradient>
+  </defs>
+  <path id="路径_55529" data-name="路径 55529" d="M12.376,132.125a.78.78,0,0,1-.825-.825v-.5L8,134.353H8a.8.8,0,0,1-1.155,0h0l-1.073-1.073-1.9,1.9h0a.749.749,0,0,1-.578.248.78.78,0,0,1-.825-.825.749.749,0,0,1,.248-.578h0L5.2,131.548h0a.8.8,0,0,1,1.155,0h0l1.073,1.073,2.97-2.97H9.9a.825.825,0,0,1,0-1.65h2.475a.78.78,0,0,1,.825.825V131.3A.78.78,0,0,1,12.376,132.125Zm0,4.125a.825.825,0,1,1,0,1.65H.825A.78.78,0,0,1,0,137.076v-8.251A.78.78,0,0,1,.825,128a.78.78,0,0,1,.825.825v7.426Z" transform="translate(0.5 -127.5)" stroke="rgba(0,0,0,0)" stroke-width="1" fill="url(#linear-gradient)"/>
+</svg>

BIN=BIN
src/assets/images/vent/down.png


BIN=BIN
src/assets/images/vent/title-boder-left.png


BIN=BIN
src/assets/images/vent/title-boder-right.png


BIN=BIN
src/assets/images/vent/up.png


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

@@ -2,6 +2,7 @@
   <a-tree-select
     allowClear
     style="width: 100%"
+    :multiple = "multiple"
     :showSearch = "false"
     :getPopupContainer="(node) => node.parentNode"
     :dropdownStyle="{ maxHeight: '400px', overflow: 'auto', zIndex: 99999 }"
@@ -80,7 +81,7 @@
     } else if (value instanceof Array) {
       emitValue(value.map((item) => item.value).join(','));
     } else {
-      emitValue(value);
+      emitValue(value+'*');
     }
     treeValue.value = value;
     console.log(treeValue.value);

+ 3 - 2
src/components/jeecg/ExcelButton.vue

@@ -18,6 +18,7 @@
       url: string;
       // 导出文件名
       name?: string | (() => string);
+      params?: Object;
       //按钮权限
       auth?: string | string[];
     };
@@ -47,10 +48,10 @@
   const $message = useMessage();
   // 导出 excel
   function onExportXls() {
-    let { url, name } = props.config?.export ?? {};
+    let { url, name, params } = props.config?.export ?? {};
     if (url) {
       let title = typeof name === 'function' ? name() : name;
-      return handleExportXls(title as string, url);
+      return handleExportXls(title as string, url, params);
     } else {
       $message.createMessage.warn('没有传递 export.url 参数');
       return Promise.reject();

+ 80 - 26
src/design/vent/comment.less

@@ -45,6 +45,9 @@
 .vent-margin-t-10 {
   margin-top: 10px;
 }
+.vent-margin-l-5 {
+  margin-left: 5px;
+}
 .vent-margin-l-8 {
   margin-left: 8px;
 }
@@ -60,11 +63,16 @@
 .vent-margin-r-8 {
   margin-right: 8px;
 }
+.vent-margin-r-5 {
+  margin-right: 5px;
+}
 
 .vent-padding-lr-5{
   padding: 0 5px
 }
-
+.vent-padding-lr-10 {
+  padding: 0 10px
+}
 .table-action-link {
   color: #00e7ff;
   padding: 0 5px;
@@ -90,38 +98,84 @@
     }
   }
 
-  .signal-round-gry {
-    background-color: #858585;
+.signal-round-gry {
+  background-color: #858585;
 
-    &::after {
-      background-color: #85858544;
-      box-shadow: 0 0 1px 1px #85858599;
-    }
+  &::after {
+    background-color: #85858544;
+    box-shadow: 0 0 1px 1px #85858599;
   }
+}
 
-  .signal-round-run {
-    background-color: #67fc00;
+.signal-round-run {
+  background-color: #67fc00;
+  &::after {
+    background-color: #67fc0044;
+    box-shadow: 0 0 1px 1px #c6ff77;
+  }
+}
 
-    &::after {
-      background-color: #67fc0044;
-      box-shadow: 0 0 1px 1px #c6ff77;
-    }
+.signal-round-blue {
+  background-color: #00ffe1;
+  &::after {
+    background-color: #00b2de66;
+    box-shadow: 0 0 1px 1px rgba(105, 238, 255, 0.3);
   }
+}
 
-  .signal-round-blue {
-    background-color: #00ffe1;
+.signal-round-warning {
+  background-color: #e9170b;
 
-    &::after {
-      background-color: #00b2de66;
-      box-shadow: 0 0 1px 1px rgba(105, 238, 255, 0.3);
-    }
+  &::after {
+    background-color: #e9170b44;
+    box-shadow: 0 0 1px 1px #e9170b;
   }
+}
 
-  .signal-round-warning {
-    background-color: #e9170b;
+.vent-breathe-zc {
+  display: inline-block;
+  position: relative;
+  width: 14px;
+  height: 14px;
+  line-height: 14px;
+  border: 1px solid #008000;
+  border-radius: 10px;
+  color: #fff;
+  font-size: 20px;
+  text-align: center;
+  cursor: pointer;
+  box-shadow: 0 1px 2px rgba(0, 0, 0, .3);
+  overflow: hidden;
+  background-color: #00FF00;
+  animation: ease-in-out breathe 500ms infinite alternate;
+}
 
-    &::after {
-      background-color: #e9170b44;
-      box-shadow: 0 0 1px 1px #e9170b;
-    }
-  }
+.vent-breathe-yc {
+  position: relative;
+  width: 14px;
+  height: 14px;
+  line-height: 14px;
+  border: 1px solid #008000;
+  border-radius: 10px;
+  color: #fff;
+  font-size: 20px;
+  text-align: center;
+  cursor: pointer;
+  box-shadow: 0 1px 2px rgba(0, 0, 0, .3);
+  overflow: hidden;
+  background-color: #FF0000;
+  animation: ease-in-out breathe 100ms infinite alternate;
+}
+
+@keyframes breathe {
+  0% {
+    opacity: .2;
+    box-shadow: 0 1px 2px rgba(255, 255, 255, 0.1);
+  }
+
+  100% {
+    opacity: 1;
+    border: 1px solid rgba(59, 235, 235, 1);
+    box-shadow: 0 1px 30px rgba(59, 255, 255, 1);
+  }
+}

+ 4 - 4
src/design/vent/index.less

@@ -10,12 +10,12 @@
 
 /* 按钮 */
 .@{ventSpace}-btn-primary {
-  border-color: #91e9fe !important;
-  background: #275088 !important;
+  border-color: #56b3c96b !important;
+  background: #1c638a !important;
   &:hover,
   &:focus {
-    background: #27508899 !important;
-    border-color: #91e9fe99 !important;
+    background: #1c638a99 !important;
+    border-color: #56b3c96b !important;
   }
 }
 .@{ventSpace}-btn-dangerous{

+ 1 - 1
src/design/vent/modal.less

@@ -363,7 +363,7 @@
   .bottom-tabs-box {
     position: fixed;
     width: calc(100% - 10px);
-    height: 280px;
+    height: 240px;
     bottom: 20px;
     padding: 0 20px;
     margin: 0 5px;

+ 1 - 0
src/hooks/system/useListPage.ts

@@ -90,6 +90,7 @@ export function useListPage(options: ListPageOptions) {
       if (selectedRowKeys.value && selectedRowKeys.value.length > 0) {
         paramsForm['selections'] = selectedRowKeys.value.join(',');
       }
+      debugger
       return handleExportXls(title as string, realUrl, filterObj(paramsForm));
       //update-end---author:wangshuai ---date:20220411  for:导出新增自定义参数--------------
     } else {

+ 15 - 0
src/hooks/web/useWebColumns.ts

@@ -2,6 +2,7 @@ import { computed, ref } from 'vue';
 import { useVentStore } from '/@/store/modules/vent';
 import { BasicColumn } from '/@/components/Table';
 
+
 const ventStore = useVentStore();
 
 const arrToColumns = (tableHeaderColumns = []) => {
@@ -22,6 +23,8 @@ const arrToColumns = (tableHeaderColumns = []) => {
   return columns;
 };
 
+
+
 export const getTableHeaderColumns = (webColumnsKey) => {
   const key = webColumnsKey;
   const allTableHeaderColumnArr = ventStore.getAllTableHeaderColumns;
@@ -35,6 +38,18 @@ export const getTableHeaderColumns = (webColumnsKey) => {
   return [];
 };
 
+export const getFormSchemaColumns = (webColumnsKey) => {
+  const key = webColumnsKey;
+  const allTableHeaderColumnArr = ventStore.getAllTableHeaderColumns;
+  if (allTableHeaderColumnArr) {
+    debugger
+    const tabelHeaderColumns = allTableHeaderColumnArr[key];
+    return tabelHeaderColumns;
+    // return arrToFormColumns(tabelHeaderColumns);
+  }
+  return [];
+};
+
 // export const getTableHeaderColumns = async (columnsKey) => {
 //   const allTableHeaderColumnArr = await ventStore.getAllTableHeaderColumnsAction();
 //   if (allTableHeaderColumnArr) {

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

@@ -26,6 +26,30 @@ export const PAGE_NOT_FOUND_ROUTE: AppRouteRecordRaw = {
   ],
 };
 
+export const DeviceTableRoute: AppRouteRecordRaw = {
+  path: '/monitorChannel/deviceManager/auto',
+  name: 'deviceManager',
+  component: LAYOUT,
+
+  meta: {
+    title: '设备管理',
+    hideBreadcrumb: true,
+    hideMenu: true,
+  },
+  children: [
+    {
+      path: '/:type',
+      name: '',
+      component: () => import('/@/views/vent/deviceManager/deviceTable/index.vue'),
+      meta: {
+        title: '',
+        hideBreadcrumb: true,
+        hideMenu: true,
+      },
+    },
+  ],
+};
+
 export const QIANKUN_ROUTE: AppRouteRecordRaw = {
   path: '/micro-:path(.*)*',
   name: QIANKUN_ROUTE_NAME,

+ 0 - 22
src/router/routes/index.ts

@@ -38,27 +38,6 @@ export const LoginRoute: AppRouteRecordRaw = {
   },
 };
 
-export const testRoute: AppRouteRecordRaw = {
-  path: '/monitor',
-  name: 'monitor',
-  components: LAYOUT,
-  meta: {
-    title: 'testRoute',
-    isAuth: false,
-  },
-  children: [
-    {
-      path: '/monitor-fan-main',
-      name: 'monitor-fan-main',
-      component: () => import('/@/views/vent/monitorManager/mainFanMonitor/index.vue'),
-      meta: {
-        title: '',
-        isAuth: false,
-      },
-    },
-  ],
-};
-
 //update-begin---author:wangshuai ---date:20220629  for:auth2登录页面路由------------
 export const Oauth2LoginRoute: AppRouteRecordRaw = {
   path: '/oauth2-app/login',
@@ -92,5 +71,4 @@ export const basicRoutes = [
   PAGE_NOT_FOUND_ROUTE,
   TokenLoginRoute,
   Oauth2LoginRoute,
-  testRoute,
 ];

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

@@ -36,7 +36,8 @@ export function initModalWorker() {
     'ztfj/ztfj_2023-06-02.glb',
     'fire/laneway_2023-06-02.glb',
     'fire/chamber_2023-06-02.glb',
-    'fire/workFace_2023-06-02.glb',
+    'fire/workFace_2023-06-29.glb',
+    'fire/tunFace_2023-06-29.glb',
     'fire/nitrogen_2023-06-02.glb',
     'fire/grout_2023-06-02.glb',
     'yafeng/compressor_2023-06-02.glb',

+ 2 - 2
src/views/system/menuModal/MenuDrawer.vue

@@ -37,7 +37,7 @@
     menuType.value = data?.record?.menuType;
 
     //获取下拉树信息
-    const treeData = await list();
+    const treeData = await list({kind: 2});
     updateSchema([
       {
         field: 'parentId',
@@ -77,7 +77,7 @@
       }
       setDrawerProps({ confirmLoading: true });
       //提交表单
-      await saveOrUpdateMenu(values, unref(isUpdate));
+      await saveOrUpdateMenu({...values, kind: 2}, unref(isUpdate));
       closeDrawer();
       emit('success');
     } finally {

+ 4 - 7
src/views/system/menuModal/index.vue

@@ -96,7 +96,6 @@
     showFooter.value = true;
     openDrawer(true, {
       isUpdate: false,
-      kind: 2
     });
   }
 
@@ -108,7 +107,6 @@
     openDrawer(true, {
       record,
       isUpdate: true,
-      kind: 2
     });
   }
   /**
@@ -119,7 +117,6 @@
     openDrawer(true, {
       record,
       isUpdate: true,
-      kind: 2
     });
   }
   /**
@@ -127,9 +124,9 @@
    */
   function handleAddSub(record) {
     openDrawer(true, {
-      record: { parentId: record.id, menuType: 1 },
+      record: { parentId: record.id, menuType: 1, kind: 2 },
       isUpdate: false,
-      kind: 2
+
     });
   }
   /**
@@ -143,13 +140,13 @@
    * 删除
    */
   async function handleDelete(record) {
-    await deleteMenu({ id: record.id, kind: 2 }, reload);
+    await deleteMenu({ id: record.id }, reload);
   }
   /**
    * 批量删除事件
    */
   async function batchHandleDelete() {
-    await batchDeleteMenu({ ids: checkedKeys.value, kind: 2 }, reload);
+    await batchDeleteMenu({ ids: checkedKeys.value }, reload);
   }
   /**
    * 成功回调

+ 1 - 1
src/views/vent/comment/components/bottomMenu.vue

@@ -18,7 +18,7 @@ export default defineComponent({
         {
           title: '监控界面',
           pathName: 'monitor',
-          isHover: true
+          isHover: false
         },
         {
           title: '历史监测记录',

+ 2 - 2
src/views/vent/comment/components/customHeader.vue

@@ -115,10 +115,10 @@ export default defineComponent({
       position: relative;
 
       .title-select {
-        width: 198px;
+        width: 228px;
         position: absolute;
         top: 0;
-        left: 180px;
+        left: 160px;
       }
     }
   }

+ 5 - 1
src/views/vent/deviceManager/comment/DeviceModal.vue

@@ -33,6 +33,9 @@
       <a-tab-pane v-if="deviceType == 'managesys'" key = "6" tab="报警控制设备配置">
         <ManagerWarningDeviceTable :deviceId="deviceData.id" :pointType="record.strtype"/>
       </a-tab-pane>
+      <a-tab-pane v-if="deviceType == 'managesys'" key = "7" tab="一键反风控制设备配置">
+        <BackWindDeviceTable :deviceId="deviceData.id" :pointType="record.strtype"/>
+      </a-tab-pane>
       <a-tab-pane key="5" tab="摄像头配置"
         ><EditRowTable
           :columns="cameraColumns"
@@ -53,11 +56,12 @@
   import WarningTable from './warningTabel/index.vue';
   import ManagerWarningTable from './warningTabel/index1.vue';
   import ManagerWarningDeviceTable from './warningTabel/index2.vue';
+  import BackWindDeviceTable from './warningTabel/index3.vue';
   import WorkFacePointTable from './pointTabel/WorkFacePointTable.vue';
   import FormModal from './FormModal.vue';
   import { cloneDeep } from 'lodash-es';
   import { columns as pointColumns } from './pointTabel/point.data';
-  import { saveOrUpdate as pointSaveOrUpdate, deleteById as pointDeleteById, warningDeleteById } from './pointTabel/point.api';
+  import { saveOrUpdate as pointSaveOrUpdate, deleteById as pointDeleteById } from './pointTabel/point.api';
   import { columns as cameraColumns } from './cameraTabel/camera.data';
   import { list as cameraList, saveOrUpdate as cameraSaveOrUpdate, deleteById as cameraDeleteById } from './cameraTabel/camera.api';
 

+ 8 - 7
src/views/vent/deviceManager/comment/NormalTable.vue

@@ -112,6 +112,9 @@
   const isUpdate = ref(false);
   const record = reactive({});
 
+  const deviceTypeId = ref('')
+  const pageType = ref('')
+
   provide('formSchema', props.formSchema);
   provide('isUpdate', isUpdate);
   provide('formData', record);
@@ -148,15 +151,13 @@
         width: 180,
       },
       beforeFetch: (params) => {
-        if(params['devicetype']) params['devicetype'] = params['devicetype']+'*'
+        // if(params['devicetype']) {
+        //   deviceTypeId.value = params['devicetype']
+        //   params['devicetype'] = params['devicetype'] + '*'
+        // }
+        // pageType.value = params['pagetype']
         return Object.assign({ column: 'createTime', order: 'desc' }, params);
       },
-      exportConfig: {
-        url: props.getExportUrl,
-      },
-      importConfig: {
-        url: props.getImportUrl,
-      },
     },
     exportConfig: {
       name: props.title,

+ 22 - 20
src/views/vent/deviceManager/comment/warningTabel/DevicePointTable.vue

@@ -8,37 +8,35 @@
     :showCancelBtn="false"
     :showOkBtn="false"
     :footer="null"
-    destroyOnClose
+    :destroy-on-close="true"
   >
     <div>
       <a-button type="primary" @click="saveData"> 确定 </a-button>
     </div>
     <a-table
-      :rowSelection="{ selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
+      v-if="refresh"
+      :row-selection="{ selections: true, selectedRowKeys: selectedRowKeys, onChange: onSelectChange }"
       :columns="columns"
       :dataSource="dataSource"
-      :rowKey="(record) => record.id"
+      :row-key="(record) => record.id"
       size="small"
     />
   </BasicModal>
 </template>
 <script lang="ts" setup>
-  import { onMounted, ref, defineEmits, onUpdated, defineExpose } from 'vue';
-  import { workFacePointList, workFaceWarningBatchAdd } from './warning.api';
+  import { onMounted, ref, defineEmits, watch, nextTick } from 'vue';
   import { columns } from '../../pointTabel/point.data';
   import { BasicModal, useModalInner } from '/@/components/Modal';
 
   const DeviceModalTable = ref();
   const props = defineProps({
-    deviceType: { type: String, default: '' },
-    deviceId: { type: String, default: '' },
-    sysId: { type: String, default: '' },
+    dataSource: { type: Array, default: () => [] },
     selectionRowKeys: { type: Array, default: () => [] },
   });
   const emit = defineEmits(['reload', 'register']);
 
-  const dataSource = ref<any[]>([]);
-  const selectedRowKeys = ref([]);
+  const refresh = ref(true)
+  const selectedRowKeys = ref<any[]>([]);
   const selectionRows = ref([]);
 
   const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
@@ -46,9 +44,6 @@
     setModalProps({ confirmLoading: false });
   });
 
-  const getDataSource = async () => {
-    dataSource.value = await workFacePointList({ deviceType: props.deviceType, valueType: 2 });
-  };
 
   /**
    * 复选框选中事件
@@ -61,17 +56,24 @@
   }
 
   const saveData = async () => {
-    const monitorList = <any[]>[]
-    selectionRows.value.forEach(item => {
-      monitorList.push({ deviceId: props.deviceId,  monitorId: item['id'], monitorName: item['valuename'], sysId: props.sysId })
-    })
-    await workFaceWarningBatchAdd(monitorList)
+    
+    emit('reload', selectionRows.value);
+
     closeModal();
-    emit('reload');
+    
   };
 
+  watch(() => props.selectionRowKeys, (newVal: any[]) => {
+    selectedRowKeys.value = newVal
+    refresh.value = false
+    nextTick(() => {
+      refresh.value = true
+    })
+  })
+
+
   onMounted(async () => {
-    await getDataSource();
+
   });
 
 </script>

+ 38 - 67
src/views/vent/deviceManager/comment/warningTabel/index1.vue

@@ -1,13 +1,15 @@
 <template>
   <div class="vent-flex-row">
-    <span style = "color: #fff;">关联设备:</span>
+    <span style = "color: #fff;">关联的监测设备:</span>
     <a-select
       v-model:value="sysDeviceId"
       style="width: 200px"
       placeholder="关联设备"
       :options="sysDeviceOptions"
       @change="handleChange"
+      :allowClear="true"
     />
+    <a-button class="vent-margin-l-8" type="primary" @click="getDeviceWarningPointList"> 查询 </a-button>
     <a-button class="vent-margin-l-8" type="primary" @click="addPoint"> 新增 </a-button>
   </div>
 
@@ -24,14 +26,14 @@
 
   </EditRowTableVue>
 
-  <DevicePointTable @register="registerModal" :device-type="sysDeviceType" :selection-row-keys="selectionRowKeys" :device-id="sysDeviceId" :sys-id="deviceId" @reload="reload"/>
+  <DevicePointTable @register="registerModal" :data-source="devicePointList" :selection-row-keys="selectionRowKeys" @reload="reload"/>
 </template>
 
 <script lang="ts" setup>  
   import { defineProps, ref, onMounted } from 'vue';
   import { manageWarningPointColumns } from './warning.data';
   import EditRowTableVue from '../../../comment/EditRowTable.vue';
-  import { workFaceWarningList,  workFaceWarningEdit, workFaceWarningDelete, workFaceDeviceList } from './warning.api';
+  import { workFaceWarningList,  workFaceWarningEdit, workFaceWarningDelete, workFaceDeviceList, workFacePointList, workFaceWarningBatchAdd } from './warning.api';
   import DevicePointTable from './DevicePointTable.vue';
   import { useModal } from '/@/components/Modal';
   
@@ -45,6 +47,7 @@
 
   const sysDeviceId = ref('') // 选中的关联设备的id
   const sysDeviceType = ref('')
+  const devicePointList = ref<any[]>([])
   const selectionRowKeys = ref<any[]>([])
   const sysDeviceOptions = ref<any[]>([])
   let sysDeviceList = <any[]>[]
@@ -61,25 +64,32 @@
       return element.id == value
     })
     sysDeviceType.value = obj['strtype']
-    await getDevicePointList()
+    await getDeviceWarningPointList()
   }
 
-  async function getDevicePointList() {
+  async function getDeviceWarningPointList() {
 
     const result = await workFaceWarningList({ deviceId: sysDeviceId.value})
-
     if(result && result.records.length > 0){
       dataSource.value = result.records
-      const rowKeys = <any[]>[]
-      result.records.forEach((item) => {
-        rowKeys.push(item['id'])
-      })
-      selectionRowKeys.value = rowKeys
     }else{
       dataSource.value = []
-      selectionRowKeys.value = []
     }
   }
+
+  async function getDevicePointList() {
+    try {
+      const result = await workFacePointList({ deviceType: sysDeviceType.value, valueType: 2 });
+      devicePointList.value = result
+      const rowKeys = <any[]>[]
+      dataSource.value.forEach((item) => {
+        rowKeys.push(item['monitorId'])
+      })
+      selectionRowKeys.value = rowKeys
+    } catch (error) {
+      devicePointList.value = []
+    }
+  };
   
   async function getDeviceOptions() {
     const result = await workFaceDeviceList({id: props.deviceId})
@@ -104,72 +114,33 @@
   }
 
   function handleDelete(id) {
-    workFaceWarningDelete({id}, getDevicePointList)
+    workFaceWarningDelete({id}).then(() => {
+      getDeviceWarningPointList()
+    })
   }
 
-  function reload() {
-    getDevicePointList()
+  async function reload(list) {
+    const monitorList = <any[]>[]
+    list.forEach(item => {
+      monitorList.push({ deviceId: sysDeviceId.value, monitorId: item['id'], monitorName: item['valuename'], sysId: props.deviceId })
+    })
+    await workFaceWarningBatchAdd(monitorList)
+    getDeviceWarningPointList()
   }
 
-
   function addPoint() {
-    openModal();
+    getDevicePointList().then(() => {
+      openModal();
+    })
   }
 
   onMounted(async () => {
     await getDeviceOptions()
+    await getDeviceWarningPointList()
   });
 </script>
 
 <style lang="less" scoped>
-  .device-button-group{
-    // margin: 0 20px;
-    display: flex;
-    flex-wrap: wrap;
-    pointer-events: auto;
-    position: relative;
-    margin-top: 10px;
-    margin-bottom: 5px;
-    &::after{
-      position:absolute;
-      content: '';
-      width: calc(100% + 10px);
-      height: 2px;
-      top: 30px;
-      left: -10px;
-      border-bottom: 1px solid #0efcff;
-    }
-    .device-button{
-      padding: 4px 10px;
-      position: relative;
-      display: flex;
-      justify-content: center;
-      align-items: center;
-      font-size: 14px;
-      
-      color: #fff;
-      cursor: pointer;
-      margin: 0 1px;
-
-      &::before{
-        content: '';
-        position: absolute;
-        top: 0;
-        right: 0;
-        bottom: 0;
-        left: 0;
-        border: 1px solid #6176AF;
-        // transform: skewX(-38deg);
-        background-color: rgba(0, 77, 103,85%);
-        z-index: -1;
-      }
-    }
-    .device-active{
-      // color: #0efcff;
-      &::before{
-        border-color: #0efcff;
-        box-shadow: 1px 1px 3px 1px #0efcff inset;
-      }
-    }
-  }
+  @ventSpace: zxm;
+
 </style>

+ 94 - 84
src/views/vent/deviceManager/comment/warningTabel/index2.vue

@@ -5,38 +5,39 @@
       <a-select
         v-model:value="sysDeviceId"
         style="width: 180px"
-        placeholder="预警监测设备"
         :options="sysDeviceOptions"
         @change="handleChange"
+        :allowClear="true"
       />
     </div>
     <div class="vent-flex-row vent-padding-lr-5">
       <span style = "color: #fff;">预警条目:</span>
       <a-select
-        v-model:value="sysDeviceId"
+        v-model:value="sysWarningId"
         style="width: 180px"
-        placeholder="监测设备预警条目"
         :options="warningOptions"
-        @change="handleChange"
+        @change="handleWarningChange"
+        :allowClear="true"
       />
     </div>
     <div class="vent-flex-row">
       <span style = "color: #fff;">预警控制设备:</span>
       <a-select
-        v-model:value="sysDeviceId"
+        v-model:value="controlDeviceId"
         style="width: 180px"
-        placeholder="预警控制设备"
-        :options="warningOptions"
-        @change="handleChange"
+        :options="sysDeviceOptions"
+        @change="handleDeviceChange"
+        :allowClear="true"
       />
     </div>
+    <a-button class="vent-margin-l-8" type="primary" @click="getWarningControlDevicePointList"> 查询 </a-button>
     <a-button class="vent-margin-l-8" type="primary" @click="addPoint"> 新增 </a-button>
   </div>
 
-  <EditRowTableVue 
+  <EditRowTableVue
     v-if="refresh"
     ref="RefComponent"
-    :columns="manageWarningPointColumns"
+    :columns="controlDevicePointColumns"
     :data-source="dataSource"
     @save-or-update="saveOrUpdate"
     @delete-by-id="handleDelete"
@@ -46,16 +47,17 @@
 
   </EditRowTableVue>
 
-  <DevicePointTable @register="registerModal" :device-type="sysDeviceType" :selection-row-keys="selectionRowKeys" :device-id="sysDeviceId" :sys-id="deviceId" @reload="reload"/>
+  <DevicePointTable @register="registerModal" :data-source="controlDevicePointList" :selection-row-keys="selectionRowKeys" @reload="reload"/>
 </template>
 
 <script lang="ts" setup>  
   import { defineProps, ref, onMounted } from 'vue';
-  import { manageWarningPointColumns } from './warning.data';
+  import { controlDevicePointColumns } from './warning.data';
   import EditRowTableVue from '../../../comment/EditRowTable.vue';
-  import { workFaceWarningList, workFaceWarningEdit, workFaceWarningDelete, workFaceDeviceList, workFacePointList } from './warning.api';
+  import { workFaceWarningList, warkFaceControlDevicePointEdit, workFacePointList, warkFaceControlDevicePointDelete, workFaceDeviceList, warkFaceControlDevicePointBatchAdd, warkFaceControlDevicePointList } from './warning.api';
   import DevicePointTable from './DevicePointTable.vue';
   import { useModal } from '/@/components/Modal';
+  import { useMessage } from '/@/hooks/web/useMessage';
   
   const props = defineProps({
     deviceId: { type: String },
@@ -64,45 +66,83 @@
       requried: true,
     },
   });
+  const { createMessage } = useMessage();
 
   const sysDeviceId = ref('') // 选中的关联设备的id
-  const sysDeviceType = ref('')
+  const sysWarningId = ref('') // 选中的预警条目的id
+  const controlDeviceId = ref('') //预警条目控制的设备id
+  const controlDeviceType = ref('')
   const selectionRowKeys = ref<any[]>([])
   const sysDeviceOptions = ref<any[]>([])
   const warningOptions = ref<any[]>([]) //设备预警条目列表
   let sysDeviceList = <any[]>[]
   const RefComponent = ref()
   const dataSource = ref<any[]>([])
+  const controlDevicePointList = ref<any[]>([])
 
   const refresh = ref(true)
 
   const [registerModal, { openModal }] = useModal();
 
-  const handleChange = async (value) => {
-    sysDeviceId.value = value
+  const handleChange = async () => {
+    sysWarningId.value = ''
+    controlDeviceId.value = ''
+    dataSource.value = []
+    await getWarningPointList()
+  }
+
+  const handleWarningChange = () => {
+    if(!sysDeviceId.value){
+      createMessage.warning('请先选择预警监测设备。。。')
+    }
+    controlDeviceId.value = ''
+    dataSource.value = []
+  }
+
+  const handleDeviceChange = async(value) => {
+    if (!sysWarningId.value) {
+      createMessage.warning('请先选择预警条目。。。')
+      controlDeviceId.value = ''
+      return
+    }
     const obj = sysDeviceList.find((element) => {
       return element.id == value
     })
-    sysDeviceType.value = obj['strtype']
-    await getDevicePointList()
+    controlDeviceType.value = obj['strtype']
+    await getWarningControlDevicePointList()
   }
 
-  async function getDevicePointList() {
-    
-    const result = await workFaceWarningList({ deviceId: sysDeviceId.value})
+  async function getWarningPointList() {
+    const result = await workFaceWarningList({ deviceId: sysDeviceId.value })
+    const options = <any[]>[]
+    if (result && result.records.length > 0) {
+      result.records.forEach(element => {
+        options.push({ value: element.id, label: element.monitorName })
+      });
+      warningOptions.value = options
+    }else {
+      warningOptions.value = []
+    }
+  }
 
-    if(result && result.records.length > 0){
-      dataSource.value = result.records
+  async function getWarningControlDevicePointList() {;
+    const result = await warkFaceControlDevicePointList({ alarmId: sysWarningId.value, deviceId: controlDeviceId.value })
+    dataSource.value = result.records
+  }
+
+  async function getControlDevicePointList() {
+    try {
+      const result = await workFacePointList({ deviceType: controlDeviceType.value, valueType: 1 });
+      controlDevicePointList.value = result
       const rowKeys = <any[]>[]
-      result.records.forEach((item) => {
-        rowKeys.push(item['id'])
+      dataSource.value.forEach((item) => {
+        rowKeys.push(item['monitorId'])
       })
       selectionRowKeys.value = rowKeys
-    }else{
-      dataSource.value = []
-      selectionRowKeys.value = []
+    } catch (error) {
+      controlDevicePointList.value = []
     }
-  }
+  };
   
   async function getDeviceOptions() {
     const result = await workFaceDeviceList({id: props.deviceId})
@@ -120,79 +160,49 @@
   async function saveOrUpdate(record) {
     try {
       if (record.id) {
-        await workFaceWarningEdit({ ...record });
+        await warkFaceControlDevicePointEdit({ ...record });
       }
       RefComponent.value.reload()
     } catch (error) { }
   }
 
   function handleDelete(id) {
-    workFaceWarningDelete({id}, getDevicePointList)
+    warkFaceControlDevicePointDelete({id}).then(() => {
+      getWarningControlDevicePointList()
+    })
   }
 
-  function reload() {
-    getDevicePointList()
+  async function reload(list) {
+    const monitorList = <any[]>[]
+    const obj = sysDeviceOptions.value.find(item => {
+      return item.id === controlDeviceId.value
+    })
+    list.forEach(item => {
+      monitorList.push({ alarmId: sysWarningId.value,  monitorId: item['id'], monitorName: item['valuename'], deviceId: controlDeviceId.value, devicePos: obj ? obj['strinstallpos']: null })
+    })
+    warkFaceControlDevicePointBatchAdd(monitorList).then(() => {
+      getWarningControlDevicePointList()
+    })
   }
 
 
   function addPoint() {
-    openModal();
+    if (!controlDeviceId.value) {
+      createMessage.warning('请先选择报警控制设备。。。')
+      return
+    }
+    getControlDevicePointList().then(() => {
+      openModal();
+    })
   }
 
   onMounted(async () => {
     await getDeviceOptions()
+    await getWarningControlDevicePointList()
   });
 </script>
 
 <style lang="less" scoped>
-  .device-button-group{
-    // margin: 0 20px;
-    display: flex;
-    flex-wrap: wrap;
-    pointer-events: auto;
-    position: relative;
-    margin-top: 10px;
-    margin-bottom: 5px;
-    &::after{
-      position:absolute;
-      content: '';
-      width: calc(100% + 10px);
-      height: 2px;
-      top: 30px;
-      left: -10px;
-      border-bottom: 1px solid #0efcff;
-    }
-    .device-button{
-      padding: 4px 10px;
-      position: relative;
-      display: flex;
-      justify-content: center;
-      align-items: center;
-      font-size: 14px;
-      
-      color: #fff;
-      cursor: pointer;
-      margin: 0 1px;
-
-      &::before{
-        content: '';
-        position: absolute;
-        top: 0;
-        right: 0;
-        bottom: 0;
-        left: 0;
-        border: 1px solid #6176AF;
-        // transform: skewX(-38deg);
-        background-color: rgba(0, 77, 103,85%);
-        z-index: -1;
-      }
-    }
-    .device-active{
-      // color: #0efcff;
-      &::before{
-        border-color: #0efcff;
-        box-shadow: 1px 1px 3px 1px #0efcff inset;
-      }
-    }
-  }
+  @ventSpace: zxm;
+
 </style>

+ 36 - 4
src/views/vent/deviceManager/comment/warningTabel/warning.api.ts

@@ -16,12 +16,23 @@ enum Api {
   exportXls = '/sys/user/exportXls',
 
   workFaceDeviceList = '/safety/managesysDevice/getManagesDeviceInfo',
+  
   workFaceWarningList = '/safety/managesysAlarm/list',
   workFaceWarningAdd = '/safety/managesysAlarm/add',
   workFaceWarningBatchAdd = '/safety/managesysAlarm/addBatch',
   workFaceWarningEdit = '/safety/managesysAlarm/edit',
   workFaceWarningDelete = '/safety/managesysAlarm/delete',
   workFacePointList = '/safety/ventanalyMonitorParams/getListByType', // 参数1 :设置点位 2:读取点位
+
+  warkFaceControlDevicePointList = '/safety/managesysAlarmAuto/list',
+  warkFaceControlDevicePointBatchAdd = '/safety/managesysAlarmAuto/addBatch',
+  warkFaceControlDevicePointDelete = '/safety/managesysAlarmAuto/delete',
+  warkFaceControlDevicePointEdit = '/safety/managesysAlarmAuto/edit',
+
+  backWindControlDevicePointList = '/safety/managesysAuto/list',
+  backWindControlDevicePointBatchAdd = '/safety/managesysAuto/addBatch',
+  backWindControlDevicePointDelete = '/safety/managesysAuto/delete',
+  backWindControlDevicePointEdit = '/safety/managesysAuto/edit',
 }
 /**
  * 导出api
@@ -83,10 +94,31 @@ export const workFaceWarningBatchAdd = (params) => defHttp.post({ url: Api.workF
 
 export const workFaceWarningEdit = (params) => defHttp.put({ url: Api.workFaceWarningEdit, params });
 
-export const workFaceWarningDelete = (params, handleSuccess) => {
-  return defHttp.delete({ url: Api.workFaceWarningDelete, params }, { joinParamsToUrl: true }).then(() => {
-    handleSuccess();
-  });
+export const workFaceWarningDelete = (params) => {
+  return defHttp.delete({ url: Api.workFaceWarningDelete, params }, { joinParamsToUrl: true });
 };
 
 export const workFacePointList = (params) => defHttp.get({ url: Api.workFacePointList, params });
+
+// 预警控制设备点位管理
+export const warkFaceControlDevicePointList = (params) => defHttp.get({ url: Api.warkFaceControlDevicePointList, params });
+
+export const warkFaceControlDevicePointBatchAdd = (params) => defHttp.post({ url: Api.warkFaceControlDevicePointBatchAdd, params });
+
+export const warkFaceControlDevicePointEdit = (params) => defHttp.put({ url: Api.warkFaceControlDevicePointEdit, params });
+
+export const warkFaceControlDevicePointDelete = (params) => {
+  return defHttp.delete({ url: Api.warkFaceControlDevicePointDelete, params }, { joinParamsToUrl: true }).then(() => {});
+};
+
+// 一件反风控制设备点位管理
+export const backWindControlDevicePointList = (params) => defHttp.get({ url: Api.backWindControlDevicePointList, params });
+
+export const backWindControlDevicePointBatchAdd = (params) => defHttp.post({ url: Api.backWindControlDevicePointBatchAdd, params });
+
+export const backWindControlDevicePointEdit = (params) => defHttp.put({ url: Api.backWindControlDevicePointEdit, params });
+
+export const backWindControlDevicePointDelete = (params) => {
+  return defHttp.delete({ url: Api.backWindControlDevicePointDelete, params }, { joinParamsToUrl: true }).then(() => {});
+};
+

+ 117 - 2
src/views/vent/deviceManager/comment/warningTabel/warning.data.ts

@@ -1,7 +1,5 @@
 import { BasicColumn, FormSchema } from '/@/components/Table';
 import { initDictOptions } from '/@/utils/dict';
-import { defHttp } from '/@/utils/http/axios';
-const list = '/safety/ventanalyManageSystem/list';
 
 export const levelColumns: BasicColumn[] = [
   {
@@ -191,6 +189,11 @@ export const workFaceColumns: BasicColumn[] = [
 
 export const manageWarningPointColumns: BasicColumn[] = [
   {
+    title: '设备名称',
+    dataIndex: 'deviceName',
+    align: 'center',
+  },
+  {
     title: '报警条目',
     dataIndex: 'monitorName',
     align: 'center',
@@ -224,4 +227,116 @@ export const manageWarningPointColumns: BasicColumn[] = [
   },
 ];
 
+export const controlDevicePointColumns: BasicColumn[] = [
+  {
+    title: '报警条目',
+    dataIndex: 'alarmName',
+    align: 'center',
+  },
+  {
+    title: '设备安装位置',
+    dataIndex: 'devicePos',
+    align: 'center',
+  },
+  {
+    title: '控制点位描述',
+    dataIndex: 'monitorName',
+    align: 'center',
+  },
+  {
+    title: '值',
+    dataIndex: 'value',
+    edit: true,
+    editComponent: 'Input',
+    align: 'center',
+  },
+  // {
+  //   title: '审批状态',
+  //   dataIndex: 'bpmStatus',
+  //   align: 'center',
+  //   edit: true,
+  //   editComponent: 'Select',
+  //   editComponentProps: {
+  //     options: [
+  //       {
+  //         label: '审批',
+  //         value: '1',
+  //       },
+  //       {
+  //         label: '不审批',
+  //         value: '0',
+  //       },
+  //     ],
+  //   },
+  // },
+  {
+    title: '执行顺序',
+    dataIndex: 'orderNum',
+    align: 'center',
+    edit: true,
+    editComponent: 'InputNumber',
+  },
+  {
+    title: '更新人',
+    dataIndex: 'updateBy',
+    align: 'center',
+    width: 100,
+  },
+];
 
+export const BackWindDevicePointColumns: BasicColumn[] = [
+  {
+    title: '设备名称',
+    dataIndex: 'deviceName',
+    align: 'center',
+  },
+  {
+    title: '设备安装位置',
+    dataIndex: 'devicePos',
+    align: 'center',
+  },
+  {
+    title: '控制点位描述',
+    dataIndex: 'monitorName',
+    align: 'center',
+  },
+  {
+    title: '值',
+    dataIndex: 'value',
+    edit: true,
+    editComponent: 'Input',
+    align: 'center',
+  },
+  // {
+  //   title: '审批状态',
+  //   dataIndex: 'bpmStatus',
+  //   align: 'center',
+  //   edit: true,
+  //   editComponent: 'Select',
+  //   editComponentProps: {
+  //     options: [
+  //       {
+  //         label: '审批',
+  //         value: '1',
+  //       },
+  //       {
+  //         label: '不审批',
+  //         value: '0',
+  //       },
+  //     ],
+  //   },
+  // },
+  {
+    title: '执行顺序',
+    dataIndex: 'orderNum',
+    align: 'center',
+    edit: true,
+    editComponent: 'InputNumber',
+  },
+  {
+    title: '更新人',
+    dataIndex: 'updateBy',
+    align: 'center',
+    width: 100,
+  },
+];

+ 60 - 0
src/views/vent/deviceManager/deviceTable/device.api.ts

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

+ 155 - 0
src/views/vent/deviceManager/deviceTable/device.data.ts

@@ -0,0 +1,155 @@
+import { BasicColumn } from '/@/components/Table';
+import { FormSchema } from '/@/components/Table';
+import { list } from '../substationTabel/substation.api';
+
+export const columns: BasicColumn[] = [
+  {
+    title: '名称',
+    dataIndex: 'strname',
+    width: 120,
+  },
+  {
+    title: '安装位置',
+    dataIndex: 'strinstallpos',
+    width: 100,
+  },
+  {
+    title: '风筒长度(m)',
+    dataIndex: 'flength',
+    width: 100,
+  },
+  {
+    title: '风筒直径(m)',
+    dataIndex: 'fclearwidth',
+    width: 80,
+  },
+  {
+    title: '风机类型',
+    dataIndex: 'ntype_dictText',
+    width: 100,
+  },
+  {
+    title: '所属分站',
+    width: 150,
+    dataIndex: 'stationname',
+  },
+];
+
+export const recycleColumns: BasicColumn[] = [
+  {
+    title: '名称',
+    dataIndex: 'strname',
+    width: 100,
+  },
+  {
+    title: '是否为常闭型',
+    dataIndex: 'bnormalclose',
+    width: 100,
+  },
+];
+
+export const searchFormSchema: FormSchema[] = [
+  {
+    label: '名称',
+    field: 'strname',
+    component: 'Input',
+    colProps: { span: 6 },
+  },
+  {
+    label: '安装位置',
+    field: 'strinstallpos',
+    component: 'Input',
+    colProps: { span: 6 },
+  },
+  {
+    label: '所属分站',
+    field: 'nsubstationid',
+    component: 'ApiSelect',
+    componentProps: {
+      api: list,
+      labelField: 'strname',
+      valueField: 'id',
+    },
+  },
+];
+
+export const formSchema: FormSchema[] = [
+  {
+    label: '',
+    field: 'id',
+    component: 'Input',
+    show: false,
+  },
+  {
+    label: '名称',
+    field: 'strname',
+    component: 'Input',
+  },
+  {
+    label: '安装位置',
+    field: 'strinstallpos',
+    component: 'Input',
+  },
+  {
+    label: '风筒长度(m)',
+    field: 'flength',
+    component: 'InputNumber',
+  },
+  {
+    label: '风筒直径(m)',
+    field: 'fclearwidth',
+    component: 'InputNumber',
+  },
+  {
+    label: '风机类型',
+    field: 'ntype',
+    component: 'JDictSelectTag',
+    componentProps: {
+      dictCode: 'fantype',
+      placeholder: '请选择状态',
+      // stringToNumber: true,
+    },
+  },
+  {
+    label: '所属分站',
+    field: 'nsubstationid',
+    component: 'ApiSelect',
+    componentProps: {
+      api: list,
+      labelField: 'strname',
+      valueField: 'id',
+    },
+  },
+  {
+    label: '点表',
+    field: 'strtype',
+    component: 'JDictSelectTag',
+    componentProps: {
+      dictCode: 'fanlocalkind',
+      placeholder: '请选择状态',
+    },
+  },
+  {
+    label: '监测类型',
+    field: 'monitorflag_dictText',
+    component: 'JDictSelectTag',
+    componentProps: {
+      dictCode: 'monitorflag',
+      placeholder: '请选择状态',
+    },
+  },
+  {
+    label: '是否模拟数据',
+    field: 'testflag',
+    component: 'RadioGroup',
+    defaultValue: 1,
+    componentProps: () => {
+      return {
+        options: [
+          { label: '是', value: 1, key: '1' },
+          { label: '否', value: 0, key: '2' },
+        ],
+      };
+    },
+  },
+];

+ 134 - 0
src/views/vent/deviceManager/deviceTable/index.vue

@@ -0,0 +1,134 @@
+<template>
+  <div class="device-manager-box">
+    <NormalTable
+      v-if="isRefresh"
+      :columns="columns"
+      :searchFormSchema="searchFormSchema"
+      :list="list.bind(null, { devicekind: deviceType })"
+      :getImportUrl="getImportUrl"
+      :getExportUrl="getExportUrl"
+      :formSchema="formSchema"
+      :deleteById="deleteById"
+      :batchDelete="batchDeleteById"
+      :saveOrUpdate="saveOrUpdate"
+      designScope="device-tabel"
+      title="设备列表"
+      :showTab="true"
+      :deviceType="deviceType"
+    />
+  </div>
+</template>
+
+<script lang="ts" name="system-user" setup>
+  //ts语法
+  import { ref, onMounted } from 'vue'
+  import { FormSchema } from '/@/components/Table';
+  import NormalTable from '../comment/NormalTable.vue';
+  import { searchFormSchema } from './device.data';
+  import { list, getImportUrl, getExportUrl, deleteById, batchDeleteById, saveOrUpdate } from './device.api';
+  import { getFormSchemaColumns, getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
+  import { list as substationList } from '../substationTabel/substation.api';
+  import { useRouter } from 'vue-router';
+
+  const { currentRoute } = useRouter()
+
+  const formSchema = ref<FormSchema[]>([])
+  const isRefresh = ref(false)
+
+  const deviceType = ref('')
+
+  const columns = ref<any[]>([])
+
+  const arrToFormColumns = (tableHeaderColumns = []) => {
+    const columnList: any[] = [];
+    tableHeaderColumns.forEach((item: any) => {
+      let columnsItem;
+      if (item.type == 1 || item.type == 10) {
+        columnsItem = {
+          label: item.unit ? `${item.des}(${item.unit})` : item.des, //_dictText
+          field: item.monitorcode,
+          component: item.type == 1 ? 'Input' : item.type == 10 ? 'InputTextArea' : '',
+        };
+      } else {
+        if (item.type == 2 && item['monitorcode'] == 'nsubstationid') {
+          columnsItem = {
+            label: item.unit ? `${item.des}(${item.unit})` : item.des, //_dictText
+            field: item.monitorcode,
+            component: 'ApiSelect',
+            componentProps: {
+              api: substationList,
+              labelField: 'strname',
+              valueField: 'id',
+            },
+          };
+        }
+        if (item.type == 3) {
+          columnsItem = {
+            label: item.unit ? `${item.des}(${item.unit})` : item.des, //_dictText
+            field: item.monitorcode,
+            component: 'RadioGroup',
+            defaultValue: 1,
+            componentProps: () => {
+              return {
+                options: [
+                  { label: '是', value: 1, key: '1' },
+                  { label: '否', value: 0, key: '2' },
+                ],
+              };
+            },
+          };
+        }
+        if (item.type == 4) {
+          columnsItem = {
+            label: item.unit ? `${item.des}(${item.unit})` : item.des, //_dictText
+            field: item.monitorcode,
+            component: 'JDictSelectTag',
+            componentProps: {
+              dictCode: item.dict,
+              placeholder: '请选择',
+              stringToNumber: true,
+            },
+          };
+        }
+      }
+      columnList.push(columnsItem);
+    });
+    formSchema.value = columnList
+    formSchema.value.unshift(
+      {
+        label: '设备id', //_dictText
+        field: 'id',
+        component: 'Input',
+        componentProps: {
+          disabled: true
+        },
+      }, 
+      {
+        label: '点表',
+        field: 'strType',
+        component: 'JDictSelectTag',
+        componentProps: {
+          dictCode: `${deviceType.value}kind`,
+          placeholder: '请选择点表',
+        },
+      }
+    )
+  };
+
+  onMounted(() => {
+    const pageType = currentRoute.value.name
+    if(pageType === 'nitrogen'){
+      deviceType.value = 'pressurefan'
+    }else {
+      deviceType.value = pageType
+    }
+    columns.value = getTableHeaderColumns(`${deviceType.value}_list`) || []
+    const formSchemaColumns = getFormSchemaColumns(`${deviceType.value}_edit`) || []
+
+    arrToFormColumns(formSchemaColumns)
+    isRefresh.value = true
+  })
+
+</script>
+
+<style scoped></style>

+ 2 - 2
src/views/vent/deviceManager/fanTabel/fan.data.ts

@@ -68,7 +68,7 @@ export const searchFormSchema: FormSchema[] = [
     componentProps: {
       api: list,
       labelField: 'strname',
-      valueField: 'nsubstationid',
+      valueField: 'id',
     },
   },
 ];
@@ -117,7 +117,7 @@ export const formSchema: FormSchema[] = [
     componentProps: {
       api: list,
       labelField: 'strname',
-      valueField: 'nsubstationid',
+      valueField: 'id',
     },
   },
   {

+ 2 - 2
src/views/vent/deviceManager/ledTabel/led.data.ts

@@ -58,7 +58,7 @@ export const searchFormSchema: FormSchema[] = [
     componentProps: {
       api: list,
       labelField: 'strname',
-      valueField: 'nsubstationid',
+      valueField: 'id',
     },
   },
 ];
@@ -97,7 +97,7 @@ export const formSchema: FormSchema[] = [
     componentProps: {
       api: list,
       labelField: 'strname',
-      valueField: 'nsubstationid',
+      valueField: 'id',
     },
   },
   {

+ 6 - 0
src/views/vent/deviceManager/pointTabel/point.data.ts

@@ -4,6 +4,12 @@ import { queryDeviceList } from './point.api';
 import { defHttp } from '/@/utils/http/axios';
 
 export const columns: BasicColumn[] = [
+  // {
+  //   title: 'id',
+  //   dataIndex: 'id',
+  //   width: 120,
+  //   ifShow: true,
+  // },
   {
     title: '设备类型',
     dataIndex: 'devicekind_dictText',

+ 3 - 3
src/views/vent/deviceManager/sensorTabel/sensor.data.ts

@@ -63,7 +63,7 @@ export const searchFormSchema: FormSchema[] = [
     componentProps: {
       api: list,
       labelField: 'strname',
-      valueField: 'nsubstationid',
+      valueField: 'id',
     },
     colProps: { span: 6 },
   },
@@ -123,7 +123,7 @@ export const formSchema: FormSchema[] = [
     componentProps: {
       api: list,
       labelField: 'strname',
-      valueField: 'nsubstationid',
+      valueField: 'id',
     },
   },
   {
@@ -133,7 +133,7 @@ export const formSchema: FormSchema[] = [
     componentProps: {
       api: list,
       labelField: 'strname',
-      valueField: 'nsubstationid',
+      valueField: 'id',
     },
   },
   {

+ 2 - 2
src/views/vent/deviceManager/windWindowTabel/ventanalyWindow.data.ts

@@ -89,7 +89,7 @@ export const searchFormSchema: FormSchema[] = [
     componentProps: {
       api: list,
       labelField: 'strname',
-      valueField: 'nsubstationid',
+      valueField: 'id',
     },
     colProps: { span: 6 },
   },
@@ -168,7 +168,7 @@ export const formSchema: FormSchema[] = [
     componentProps: {
       api: list,
       labelField: 'strname',
-      valueField: 'nsubstationid',
+      valueField: 'id',
     },
   },
   {

+ 1 - 1
src/views/vent/deviceManager/windfindingTabel/windfinding.data.ts

@@ -78,7 +78,7 @@ export const searchFormSchema: FormSchema[] = [
     componentProps: {
       api: list,
       labelField: 'strname',
-      valueField: 'nsubstationid',
+      valueField: 'id',
     },
   },
 ];

+ 26 - 14
src/views/vent/deviceManager/workingFace/workingFace.data.ts

@@ -8,11 +8,11 @@ export const columns: BasicColumn[] = [
     dataIndex: 'strname',
     width: 120,
   },
-  {
-    title: '系统型号',
-    dataIndex: 'strinstallpos',
-    width: 100,
-  },
+  // {
+  //   title: '系统型号',
+  //   dataIndex: 'strinstallpos',
+  //   width: 100,
+  // },
   {
     title: '系统Code',
     dataIndex: 'nwindowtype_dictText',
@@ -74,12 +74,6 @@ export const formSchema: FormSchema[] = [
     field: 'systemname',
     component: 'Input',
   },
-
-  {
-    label: '系统型号',
-    field: 'strsystype',
-    component: 'Input',
-  },
   {
     label: '系统Code',
     field: 'code',
@@ -121,9 +115,11 @@ export const formSchema: FormSchema[] = [
     label: '点表',
     field: 'strtype',
     component: 'JDictSelectTag',
-    componentProps: {
-      dictCode: 'syskind',
-      placeholder: '请选择状态',
+    componentProps: () => {
+      return {
+        dictCode: 'syskind',
+        placeholder: '请选择状态',
+      };
     },
   },
   {
@@ -169,4 +165,20 @@ export const formSchema: FormSchema[] = [
       };
     },
   },
+  {
+    label: '模型类型',
+    field: 'strsystype',
+    component: 'JDictSelectTag',
+    componentProps: ({ formModel }) => {
+      if (formModel['strtype']) {
+        return {
+          dictCode: `${formModel['strtype']}_modal`,
+          placeholder: '请选择模型类型',
+        };
+      }
+      return {
+        options: [],
+      };
+    },
+  },
 ];

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

@@ -0,0 +1,18 @@
+import { defHttp } from '/@/utils/http/axios';
+import { Modal } from 'ant-design-vue';
+
+enum Api {
+  list = '/ventanaly-device/monitor/device',
+  baseList = '/safety/ventanalyManageSystem/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 });

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

@@ -0,0 +1,150 @@
+import { reactive } from 'vue';
+import { BasicColumn } from '/@/components/Table';
+
+export const warningConfig = reactive({
+  header: ['设备名称', '预警信息', '时间'],
+  data: [
+    ['火焰6', '严重报警', '03-05'],
+    ['测点43', '一般预警', '03-05'],
+    ['CO23', '一版预警', '03-05'],
+    ['测点6', '超高预警', '03-05'],
+    ['测点65', '超高预警', '03-05'],
+    ['温度4', '一般预警', '03-05'],
+    ['测点61', '一般预警', '03-05'],
+    ['测点87', '一般信息', '03-05'],
+  ],
+  index: false,
+  // columnWidth: [150, 80, 150, 150],
+  headerBGC: '#3d9dd45d',
+  oddRowBGC: '#009acd10',
+  evenRowBGC: '#009acd05',
+  align: ['center', 'center', 'center'],
+});
+
+export const sensorColumns: BasicColumn[] = [
+  {
+    title: '名称',
+    dataIndex: 'strname',
+    width: 100,
+    align: 'center',
+  },
+  {
+    title: '实时值',
+    dataIndex: 'smokeval',
+    width: 80,
+    align: 'center',
+  },
+  {
+    title: '报警',
+    dataIndex: 'warnFlag',
+    width: 100,
+    align: 'center',
+  },
+];
+export const windowParam = [
+  {
+    title: '当前面积',
+    code: '',
+    unit: '㎡',
+  },
+  {
+    title: '过风风量',
+    code: '',
+    unit: 'm³/min',
+  },
+  {
+    title: '风窗压差',
+    code: '',
+    unit: 'Pa',
+  },
+];
+
+export const localFanParam = [
+  {
+    title: '风机频率',
+    code: '',
+    unit: 'Hz',
+  },
+  {
+    title: '运行风机',
+    code: '',
+    unit: '',
+  },
+  {
+    title: '供风量',
+    code: '',
+    unit: 'm³/min',
+  },
+];
+export const settingParam1 = [
+  {
+    title: 'CO浓度限值',
+    value: '',
+    unit: '%',
+  },
+  {
+    title: 'O2浓度限值',
+    value: '',
+    unit: '%',
+  },
+  {
+    title: '30min CO下降梯度',
+    value: '',
+    unit: '%',
+  },
+  {
+    title: '30min O2下降梯度',
+    value: '',
+    unit: '%',
+  },
+];
+export const settingParam2 = [
+  {
+    title: '风窗面积调整梯度',
+    value: '',
+    unit: '㎡',
+  },
+  {
+    title: '风窗调节判定时间',
+    value: '',
+    unit: 'min',
+  },
+  {
+    title: '最小风窗面积',
+    value: '',
+    unit: '㎡',
+  },
+  {
+    title: '默认风窗面积',
+    value: '',
+    unit: '㎡',
+  },
+];
+
+export const settingParam3 = [
+  {
+    title: '调节最短持续时间',
+    value: '',
+    unit: 'min',
+  },
+  {
+    title: 'CO浓度不高于',
+    value: '',
+    unit: '㎡',
+  },
+  {
+    title: 'CO最高限值持续时间',
+    value: '',
+    unit: 'min',
+  },
+  {
+    title: 'O2浓度不低于',
+    value: '',
+    unit: '㎡',
+  },
+  {
+    title: 'O2最低限值持续时间',
+    value: '',
+    unit: 'min',
+  },
+];

+ 104 - 0
src/views/vent/monitorManager/balancePressMonitor/balancePress.threejs.base.ts

@@ -0,0 +1,104 @@
+import * as THREE from 'three';
+import { setModalCenter } from '/@/utils/threejs/util';
+// import * as dat from 'dat.gui';
+// const gui = new dat.GUI();
+// gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
+
+class balancePressBase {
+  model;
+  modelName = 'balancePress';
+  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();
+    // });
+  }
+
+  mountedThree() {
+    return new Promise((resolve) => {
+      this.model.setGLTFModel([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 += 40;
+          resolve(null);
+          this.addLight();
+        }
+      });
+    });
+  }
+
+  destroy() {
+    this.model.clearGroup(this.group);
+    this.model = null;
+    this.group = null;
+  }
+}
+export default balancePressBase;

+ 117 - 0
src/views/vent/monitorManager/balancePressMonitor/balancePress.threejs.ts

@@ -0,0 +1,117 @@
+import * as THREE from 'three';
+import UseThree from '../../../../utils/threejs/useThree';
+import balancePressBase from './balancePress.threejs.base';
+import { animateCamera, setModalCenter } from '/@/utils/threejs/util';
+import { useAppStore } from '/@/store/modules/app';
+
+// 模型对象、 文字对象
+let model,
+  balancePressBaseObj: balancePressBase,
+  group,
+  balancePressType = 'balancePressBase'; // workerFaceFiber
+const appStore = useAppStore();
+
+// 鼠标点击事件
+const mouseEvent = (event) => {
+  event.stopPropagation();
+  if (!model) return;
+  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 (balancePressType === 'balancePressBase') {
+      // balancePressBaseObj.mousedownModel.call(balancePressBaseObj, 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 addbalancePressText = (selectData) => {
+  if (balancePressType === 'balancePressBase') {
+    return balancePressBaseObj.addbalancePressText.call(balancePressBaseObj, selectData);
+  }
+};
+
+// 切换模型类型
+export const setModelType = (type) => {
+  balancePressType = type;
+  return new Promise((resolve) => {
+    if (balancePressType === 'balancePressBase') {
+      group = balancePressBaseObj.group;
+      const oldCameraPosition = { x: 124.736, y: 63.486, z: 103.337 };
+      model.scene.add(balancePressBaseObj.group);
+      setModalCenter(model.scene);
+      model.camera.position.set(0, 0, 300);
+      setTimeout(async () => {
+        // const position = { x: 0, y: 3.8, z: 10.5 };
+        await animateCamera(
+          oldCameraPosition,
+          oldCameraPosition,
+          { x: 0.519594036828229, y: 411.8877286329627, z: 330.7728952161751 },
+          { x: 3.534969685817257, y: 14.506061950306899, z: -16.565361577001262 },
+          model,
+          0.8
+        );
+      }, 300);
+
+      resolve(null);
+    }
+  });
+};
+
+export const mountedThree = () => {
+  return new Promise(async (resolve) => {
+    model = new UseThree('#balancePress3D');
+    model.setEnvMap('test1');
+    model.renderer.toneMappingExposure = 1;
+    // model.camera.position.set(100, 0, 1000);
+
+    balancePressBaseObj = new balancePressBase(model);
+    await balancePressBaseObj.mountedThree();
+
+    // model.scene.add(balancePressBaseObj.group);
+
+    addMouseEvent();
+    // render();
+    model.animate();
+    resolve(null);
+  });
+};
+
+export const destroy = () => {
+  if (model) {
+    balancePressBaseObj.destroy();
+    model.deleteModal();
+    model = null;
+    group = null;
+    balancePressBaseObj = null;
+  }
+};

+ 30 - 0
src/views/vent/monitorManager/balancePressMonitor/components/balancePressAlarmHistory.vue

@@ -0,0 +1,30 @@
+<template>
+  <div class="alarm-history">
+    <AlarmHistoryTable columns-type="alarm" device-type="sys_surface_junya"
+      :list="list"
+      :sys-id="deviceId"
+      :device-list-api="workFaceDeviceList.bind(null, { id: deviceId })" designScope="alarm-history" />
+  </div>
+</template>
+<script setup lang="ts">
+import AlarmHistoryTable from '../../comment/AlarmHistoryTable.vue';
+import { workFaceDeviceList } from '../../../deviceManager/comment/warningTabel/warning.api'
+import { defHttp } from '/@/utils/http/axios';
+
+const list = (params) => defHttp.get({ url: '/safety/managesysAutoLog/list', params })
+const props = defineProps({
+  deviceType: {
+    type: String,
+    required: true,
+  },
+  deviceId: {
+    type: String,
+    required: true,
+  }
+})
+</script>
+<style lang="less" scoped>
+.alarm-history {
+  pointer-events: auto;
+}
+</style>

+ 25 - 0
src/views/vent/monitorManager/balancePressMonitor/components/balancePressHandleHistory.vue

@@ -0,0 +1,25 @@
+<template>
+  <div class="handle-history">
+    <HandlerHistoryTable columns-type="operatorhistory" device-type="sys_surface_caimei"
+      :device-list-api="getTableList.bind(null, { strtype: 'pressurefan' })" designScope="pressurefan_history" />
+  </div>
+</template>
+<script setup lang="ts">
+import HandlerHistoryTable from '../../comment/HandlerHistoryTable.vue';
+import { getTableList } from '../balancePress.api'
+  const props = defineProps({
+    deviceType: {
+      type: String,
+      required: true,
+    },
+    deviceId: {
+      type: String,
+      required: true,
+    }
+  })
+</script>
+<style lang="less" scoped>
+.handle-history {
+  pointer-events: auto;
+}
+</style>

+ 28 - 0
src/views/vent/monitorManager/balancePressMonitor/components/balancePressHistory.vue

@@ -0,0 +1,28 @@
+<template>
+  <div class="history-box">
+    <HistoryTable :columns-type="`${deviceType}`" :device-type="deviceType" :sysId="deviceId"
+      :device-list-api="getTableList.bind(null, { strtype: deviceType, sysId: deviceId })" designScope="pressurefan_history" />
+  </div>
+</template>
+<script setup lang="ts">
+import { ref, defineProps } from 'vue'
+import HistoryTable from '../../comment/HistoryTable.vue';
+import { getTableList } from '../balancePress.api'
+
+const props = defineProps({
+  deviceType: {
+    type: String,
+    required: true,
+  },
+  deviceId: {
+    type: String,
+    required: true,
+  }
+})
+
+</script>
+<style lang="less" scoped>
+.history-box {
+  pointer-events: auto;
+}
+</style>

+ 255 - 0
src/views/vent/monitorManager/balancePressMonitor/components/balancePressHome.vue

@@ -0,0 +1,255 @@
+<template>
+  <a-spin tip="Loading..." :spinning="loading">
+    <div class="monitor-container">
+      <div class="lr left-box">
+        <div class="monitor-info item-box">
+          <ventBox1>
+            <template #title>
+              <div>均压与低氧参数监测与设置</div>
+            </template>
+            <template #container>
+              <div class="vent-flex-row-between auto-control">
+                  <div class="title">自动调节:</div>
+                  <a-radio-group v-model:value="isAutoControl" name="radioGroup"
+                    @change="changeType(isAutoControl)">
+                    <a-radio value="1">关闭</a-radio>
+                    <a-radio value="2">开启</a-radio>
+                  </a-radio-group>
+                </div>
+              <div class="input-box">
+                <div class="divider-line">开始条件</div>
+                <div v-for="(item, index) in settingParam1" class="input-item" :key="index">
+                  <div class="title">{{ item.title }}:</div>
+                  <a-input-number class="input-value" v-model="item.value" placeholder="" />
+                  <div class="unit">{{ item.unit }}</div>
+                </div>
+                <div class="divider-line">调节参数</div>
+                <div v-for="(item, index) in settingParam2" class="input-item" :key="index">
+                  <div class="title">{{ item.title }}:</div>
+                  <a-input-number class="input-value" v-model="item.value" placeholder="" />
+                  <div class="unit">{{ item.unit }}</div>
+                </div>
+                <div class="divider-line">结束时间</div>
+                <div v-for="(item, index) in settingParam3" class="input-item" :key="index">
+                  <div class="title">{{ item.title }}:</div>
+                  <a-input-number class="input-value" v-model="item.value" placeholder="" />
+                  <div class="unit">{{ item.unit }}</div>
+                </div>
+              </div>
+              <div class="btn-box" style="text-align: center;">
+                <div class="btn btn1">提交</div>
+              </div>
+            </template>
+          </ventBox1>
+        </div>
+      </div>
+      <div class="lr right-box">
+        <div class="item-box sensor-container">
+          <ventBox1>
+            <template #title>
+              <div>CO与O2监测</div>
+            </template>
+            <template #container>
+              
+            </template>
+          </ventBox1>
+          <ventBox1 class="vent-margin-t-10">
+            <template #title>
+              <div>设备监测详情</div>
+            </template>
+            <template #container>
+              <div class="parameter-title group-parameter-title"><SvgIcon class="icon" size="14" name="fiber-title"/><span>风窗</span></div>
+              <div class="input-box">
+                <div v-for="(item, index) in windowParam" class="input-item" :key="index">
+                  <div class="title">{{ item.title }}</div>
+                  <div class="value">-</div>
+                  <div class="unit">{{ item.unit }}</div>
+                </div>
+              </div>
+              <div class="parameter-title group-parameter-title"><SvgIcon class="icon" size="14" name="fiber-title"/><span>均压局扇</span></div>
+              <div class="input-box">
+                <div v-for="(item, index) in localFanParam" class="input-item" :key="index">
+                  <div class="title">{{ item.title }}</div>
+                  <div class="value">-</div>
+                  <div class="unit">{{ item.unit }}</div>
+                </div>
+              </div>
+            </template>
+          </ventBox1>
+        </div>
+        <div class="item-box" >
+          <LivePlayer id="fm-player1" style="height: 250px;" ref="player1" :videoUrl="flvURL1()" muted live loading controls />
+        </div>
+      </div>
+    </div>
+  </a-spin>
+
+</template>
+
+<script setup lang="ts">
+
+import { onBeforeMount, ref, onMounted, onUnmounted, reactive, defineProps, watch } from 'vue';
+import ventBox1 from '/@/components/vent/ventBox1.vue'
+import { SvgIcon } from '/@/components/Icon';
+import { mountedThree, destroy, setModelType } from '../balancePress.threejs';
+import { settingParam1, settingParam2, settingParam3, windowParam, localFanParam } from '../balancePress.data'
+import { list } from '../balancePress.api';
+import LivePlayer from '@liveqing/liveplayer-v3';
+
+const props = defineProps({
+  deviceId: {
+    type: String,
+    require: true
+  }
+})
+
+const loading = ref(false);
+
+// 默认初始是第一行
+const isAutoControl = ref('1')
+
+// 监测数据
+const selectData = reactive({});
+
+const changeType = (isAutoControl) =>{
+  isAutoControl
+  //
+}
+
+const flvURL1 = () => {
+  return `https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv`;
+  // return ''
+};
+
+// https获取监测数据
+let timer: null | NodeJS.Timeout = null;
+function getMonitor() {
+  if (Object.prototype.toString.call(timer) === '[object Null]') {
+    timer = setTimeout(async () => {
+      if (props.deviceId) {
+        const data = await getDataSource(props.deviceId)
+        Object.assign(selectData, data); 
+      }
+      if (timer) {
+        timer = null;
+      }
+      await getMonitor();
+      loading.value = false
+    }, 1000);
+  }
+};
+
+async function getDataSource(systemID) {
+  const res = await list({ devicetype: 'sys', systemID });
+  const result = res.msgTxt;
+  result.forEach(item => {
+
+
+    if (item.type === 'sys') {
+      // 硐室基本
+      // fiberDataSource.value = item.filter((data: any) => {
+      //   const readData = data.readData;
+      //   return Object.assign(data, readData);
+      // })
+    }
+  })
+}
+
+// 喷粉操作
+function handleDust() {
+  //
+}
+
+watch(() => props.deviceId, () => {
+  setModelType('balancePressBase')
+  loading.value = true
+})
+
+onBeforeMount(() => {
+
+});
+
+onMounted(() => {
+  getMonitor()
+  // loading.value = true;
+  // mountedThree().then(async () => {
+  //   await setModelType('balancePressBase');
+  //   loading.value = false;
+  //   timer = null
+  //   await getMonitor()
+  // });
+});
+
+onUnmounted(() => {
+  destroy();
+  if (timer) {
+    clearTimeout(timer);
+    timer = undefined;
+  }
+});
+
+</script>
+<style lang="less" scoped>
+@import '/@/design/vent/modal.less';
+@import '../../comment/less/workFace.less';
+@ventSpace: zxm;
+
+.lr{
+  width: 340px !important;
+}
+.auto-control{
+  padding: 10px 8px;
+  margin: 0 4px 4px 4px;
+  border-radius: 4px;
+  border: 1px solid #ffffff05;
+  background-image: linear-gradient(to left, #39deff15, #3977e500, #39deff15);
+}
+.divider-line{
+  position: relative;
+  color: aqua;
+  padding-left: 20px;
+  font-size: 14px;
+  &::before{
+    position: absolute;
+    content: '';
+    display: block;
+    top: 10px;
+    left: 0;
+    height: 1px;
+    width: 15px;
+    background-color: #ffffff33;
+  }
+  &::after{
+    position: absolute;
+    content: '';
+    display: block;
+    top: 10px;
+    right: 0;
+    height: 1px;
+    width: calc(100% - 85px);
+    background-color: #ffffff33;
+  }
+}
+.input-value{
+  width: 120px !important;
+}
+.unit{
+  text-align: right;
+}
+.btn-box{
+  margin: 10px 4px;
+  .btn1{
+    padding: 4px 0;
+  }
+}
+
+:deep(.@{ventSpace}-tabs-tabpane-active) {
+  overflow: auto;
+}
+
+:deep(.@{ventSpace}-input-number) {
+  border-color: #ffffff88 !important;
+}
+
+
+</style>

+ 223 - 0
src/views/vent/monitorManager/balancePressMonitor/index.vue

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

+ 18 - 0
src/views/vent/monitorManager/beltTunMonitor/beltTun.api.ts

@@ -0,0 +1,18 @@
+import { defHttp } from '/@/utils/http/axios';
+import { Modal } from 'ant-design-vue';
+
+enum Api {
+  list = '/ventanaly-device/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 });

+ 731 - 0
src/views/vent/monitorManager/beltTunMonitor/beltTun.data.ts

@@ -0,0 +1,731 @@
+import { reactive, ref } from 'vue';
+import { BasicColumn } from '/@/components/Table';
+import echarts from '/@/utils/lib/echarts';
+
+export const monitorNav = [
+  {
+    title: '一通三防综合管控',
+    isShow: true,
+  },
+  {
+    title: '通风监测与管控',
+    isShow: false,
+  },
+  {
+    title: '防灭火监测与管控',
+    isShow: false,
+  },
+  {
+    title: '防尘监测与管控',
+    isShow: false,
+  },
+  {
+    title: '瓦斯防治监测与管控',
+    isShow: false,
+  },
+];
+
+export const echartsOption = reactive({
+  tooltip: { trigger: 'axis', axisPointer: { lineStyle: { color: '#fff' } } },
+  legend: {
+    top: '-5',
+    icon: 'rect',
+    data: ['风量', '风速'],
+    right: '10px',
+    textStyle: { fontSize: 12, color: '#fff' },
+  },
+  grid: { x: 50, y: 50, x2: 12, y2: 40, bottom: '25', top: '10' },
+  xAxis: {
+    type: 'category',
+    boundaryGap: false,
+    axisLine: { lineStyle: { color: '#8EAFB9' } },
+    axisLabel: { textStyle: { color: '#ffffffcc' } },
+    splitLine: { show: true, lineStyle: { color: '#57617B22', type: 'dashed' } },
+    data: [],
+  },
+  yAxis: [
+    {
+      type: 'value',
+      name: 'm³/min',
+      axisTick: {
+        show: false,
+      },
+      axisLine: { lineStyle: { show: true, color: '#8EAFB9' } },
+      axisLabel: { margin: 10, textStyle: { fontSize: 12, color: '#ffffffcc' } },
+      splitLine: { show: true, lineStyle: { color: '#57617B22', type: 'dashed' } },
+    },
+  ],
+  series: [
+    {
+      name: '风量',
+      type: 'bar',
+      smooth: true,
+      lineStyle: { normal: { width: 2 } },
+      yAxisIndex: 0,
+      // markLine: {
+      //   data: [{ yAxis: 0, name: '需风量' }],
+      // },
+      areaStyle: {
+        normal: {
+          color: new echarts.graphic.LinearGradient(
+            0,
+            0,
+            0,
+            1,
+            [
+              {
+                offset: 0,
+                color: 'rgba(185,150,248,0.3)',
+              },
+              {
+                offset: 0.8,
+                color: 'rgba(185,150,248,0)',
+              },
+            ],
+            false
+          ),
+          shadowColor: 'rgba(0, 0, 0, 0.1)',
+          shadowBlur: 10,
+        },
+      },
+      itemStyle: { normal: { color: '#B996F8' } },
+      data: [],
+    },
+    {
+      name: '风速',
+      type: 'line',
+      smooth: true,
+      lineStyle: { normal: { width: 2 } },
+      yAxisIndex: 0,
+      // markLine: {
+      //   data: [{ yAxis: 0, name: '需风量' }],
+      // },
+      areaStyle: {
+        normal: {
+          color: new echarts.graphic.LinearGradient(
+            0,
+            0,
+            0,
+            1,
+            [
+              {
+                offset: 0,
+                color: 'rgba(3, 194, 236, 0.3)',
+              },
+              {
+                offset: 0.8,
+                color: 'rgba(3, 194, 236, 0)',
+              },
+            ],
+            false
+          ),
+          shadowColor: 'rgba(0, 0, 0, 0.1)',
+          shadowBlur: 10,
+        },
+      },
+      itemStyle: { normal: { color: '#03C2EC' } },
+      data: [],
+    },
+  ],
+});
+
+export const ventParam = [
+  {
+    title: '允许超出风量(m³/min)',
+    value: '',
+    type: 'input',
+  },
+  {
+    title: '瓦斯浓度限值(%)',
+    value: '',
+    type: 'input',
+  },
+  {
+    title: '瓦斯持续超限时间(s)',
+    value: '',
+    type: 'input',
+  },
+  {
+    title: '风量调控策略',
+    value: '1',
+    type: 'radio',
+  },
+];
+
+export const warningConfig = reactive({
+  header: ['设备名称', '预警信息', '时间'],
+  data: [
+    ['火焰6', '严重报警', '03-05'],
+    ['测点43', '一般预警', '03-05'],
+    ['CO23', '一版预警', '03-05'],
+    ['测点6', '超高预警', '03-05'],
+    ['测点65', '超高预警', '03-05'],
+    ['温度4', '一般预警', '03-05'],
+    ['测点61', '一般预警', '03-05'],
+    ['测点87', '一般信息', '03-05'],
+  ],
+  index: false,
+  headerBGC: '#3d9dd45d',
+  oddRowBGC: '#009acd10',
+  evenRowBGC: '#009acd05',
+  align: ['center', 'center', 'center'],
+});
+
+export const locationConfig = reactive({
+  header: ['人名', '所在位置', '距离'],
+  data: [],
+  index: false,
+  columnWidth: [100, 200, 80],
+  headerBGC: '#3d9dd45d',
+  oddRowBGC: '#009acd10',
+  evenRowBGC: '#009acd05',
+  align: ['center', 'center', 'center'],
+});
+
+export const sensorColumns: BasicColumn[] = [
+  {
+    title: '名称',
+    dataIndex: 'strname',
+    width: 100,
+    align: 'center',
+  },
+  {
+    title: '实时值',
+    dataIndex: 'smokeval',
+    width: 80,
+    align: 'center',
+  },
+  {
+    title: '报警',
+    dataIndex: 'warnFlag',
+    width: 100,
+    align: 'center',
+  },
+];
+
+export const gateColumns: BasicColumn[] = [
+  {
+    title: '名称',
+    dataIndex: 'strname',
+    width: 100,
+    align: 'center',
+  },
+  {
+    title: '前门状态',
+    dataIndex: 'frontGateOpen',
+    width: 80,
+    align: 'center',
+  },
+  {
+    title: '后门状态',
+    dataIndex: 'rearGateOpen',
+    width: 80,
+    align: 'center',
+  },
+  {
+    title: '操作',
+    dataIndex: 'action',
+    width: 120,
+    align: 'center',
+  },
+];
+
+export const windowColumns: BasicColumn[] = [
+  {
+    title: '名称',
+    dataIndex: 'strname',
+    width: 100,
+    align: 'center',
+  },
+  {
+    title: '过风量',
+    dataIndex: 'forntm3',
+    width: 80,
+    align: 'center',
+  },
+  {
+    title: '过风面积',
+    dataIndex: 'forntArea',
+    width: 80,
+    align: 'center',
+  },
+  {
+    title: '操作',
+    dataIndex: 'action',
+    width: 120,
+    align: 'center',
+  },
+];
+
+export const windColumns: BasicColumn[] = [
+  {
+    title: '名称',
+    dataIndex: 'strname',
+    width: 100,
+    align: 'center',
+  },
+  {
+    title: '风量',
+    dataIndex: 'm3',
+    width: 80,
+    align: 'center',
+  },
+  {
+    title: '操作',
+    dataIndex: 'action',
+    width: 80,
+    align: 'center',
+  },
+];
+
+export const dustColumns: BasicColumn[] = [
+  {
+    title: '名称',
+    dataIndex: 'strname',
+    width: 100,
+    align: 'center',
+  },
+  {
+    title: '链接状态',
+    dataIndex: 'netStatus',
+    width: 80,
+    align: 'center',
+  },
+  {
+    title: '操作',
+    dataIndex: 'action',
+    width: 100,
+    align: 'center',
+  },
+];
+
+export const dustFanParam = [
+  {
+    title: '输出电流 (A)',
+    code: '',
+  },
+  {
+    title: '输出电压 (V)',
+    code: '',
+  },
+  {
+    title: '排灰功率 (kW)',
+    code: '',
+  },
+  {
+    title: '运行频率 (Hz)',
+    code: '',
+  },
+  {
+    title: '漏风率 (%)',
+    code: '',
+  },
+  {
+    title: '工作噪声 (dB(A))',
+    code: '',
+  },
+  {
+    title: '震动速度 (mm/s)',
+    code: '',
+  },
+  {
+    title: '气液比(mm/s)',
+    code: '',
+  },
+];
+
+export const dustMonitor = ref([
+  {
+    title: '处理风量',
+    unit: '(m³/min)',
+    code: '',
+  },
+  {
+    title: '总粉尘除尘效率',
+    unit: '(%)',
+    code: '',
+  },
+  {
+    title: '进口粉尘允许浓度',
+    unit: '(g/m³)',
+    code: '',
+  },
+  {
+    title: '呼吸性粉尘除尘效率',
+    unit: '(%)',
+    code: '',
+  },
+]);
+
+export const dustFanSetting = ref([
+  {
+    title: '除尘器频率设置(Hz)',
+    code: 'dustFrequency',
+    type: 'input',
+    inputNum: 0,
+  },
+  {
+    title: '清灰时间(ms)',
+    code: 'clearDust',
+    type: 'input',
+    inputNum: 0,
+  },
+  {
+    title: '清灰周期(s)',
+    code: 'clearCycle',
+    type: 'input',
+    inputNum: 0,
+  },
+]);
+
+export const beamTubeColumns = [
+  {
+    gasval: '甲烷(%)',
+    ch2val: '乙烯(ppm)',
+  },
+  {
+    o2val: '氧气(%)',
+    chval: '乙炔(ppm)',
+  },
+  {
+    coval: '一氧化碳(ppm)',
+    co2val: '二氧化碳(%)',
+  },
+];
+
+export const groutColumns = [
+  {
+    flowRate: '流量(m³/min)',
+    pressure: '压力(Pa)',
+  },
+];
+
+export const sprayColumns: BasicColumn[] = [
+  {
+    title: '名称',
+    dataIndex: 'strname',
+    width: 100,
+    align: 'center',
+  },
+  {
+    title: '连接状态',
+    dataIndex: 'netStatus',
+    width: 80,
+    align: 'center',
+  },
+  {
+    title: '启停',
+    dataIndex: 'action',
+    width: 80,
+    align: 'center',
+  },
+];
+
+export const disasterParam = ref([
+  {
+    title: '触发灾变传感器',
+    value: '1',
+    type: 'select',
+    options: [
+      {
+        label: 'CO与烟雾',
+        value: '1',
+      },
+      {
+        label: 'CO',
+        value: '2',
+      },
+      {
+        label: '烟雾',
+        value: '3',
+      },
+    ],
+  },
+  {
+    title: 'CO浓度限值(ppm)',
+    value: '',
+    type: 'input',
+  },
+  {
+    title: 'CO报警持续时间(s)',
+    value: '',
+    type: 'input',
+  },
+  {
+    title: '烟雾报警持续时间(s)',
+    value: '',
+    type: 'input',
+  },
+]);
+
+export const coalMachineDustParam = [
+  {
+    title: '内喷雾压力',
+    value: '',
+    unit: 'Pa',
+  },
+  {
+    title: '内喷雾流量',
+    value: '',
+    unit: 'm³/min',
+  },
+  {
+    title: '外喷雾压力',
+    value: '',
+    unit: 'Pa',
+  },
+  {
+    title: '外喷雾流量',
+    value: '',
+    unit: 'm³/min',
+  },
+];
+
+export const beltMachineDustParam = [
+  {
+    title: '全尘',
+    value: '',
+    unit: 'mg/m³',
+  },
+  {
+    title: '呼尘',
+    value: '',
+    unit: 'mg/m³',
+  },
+  {
+    title: '内喷雾压力',
+    value: '',
+    unit: 'Pa',
+  },
+  {
+    title: '内喷雾流量',
+    value: '',
+    unit: 'm³/min',
+  },
+  {
+    title: '外喷雾压力',
+    value: '',
+    unit: 'Pa',
+  },
+  {
+    title: '外喷雾流量',
+    value: '',
+    type: 'input',
+    unit: 'm³/min',
+  },
+];
+
+export const dustConfig = reactive({
+  header: ['编号', '位置', '触发', '故障诊断'],
+  data: [
+    ['001', '0m', '是', '正常'],
+    ['002', '2m', '是', '正常'],
+    ['003', '4m', '是', '正常'],
+    ['004', '6m', '是', '正常'],
+    ['005', '8m', '是', '正常'],
+    ['006', '10m', '是', '正常'],
+    ['007', '12m', '是', '正常'],
+  ],
+  index: false,
+  headerBGC: '#3d9dd45d',
+  oddRowBGC: '#009acd10',
+  evenRowBGC: '#009acd05',
+  align: ['center', 'center', 'center', 'center'],
+});
+
+export const gasMonitor = [
+  {
+    title: '甲烷浓度T0 (%)',
+    code: 'T0',
+  },
+  {
+    title: '甲烷浓度T1 (%)',
+    code: 'T1',
+  },
+  {
+    title: '甲烷浓度T2 (%)',
+    code: 'T2',
+  },
+  {
+    title: '二氧化碳浓度 (%)',
+    code: 'CO2',
+  },
+  {
+    title: '瓦斯抽采浓度 (%)',
+    code: 'gasC',
+  },
+  {
+    title: '瓦斯抽采混量 (m³/min)',
+    code: 'gasMixMass',
+  },
+  {
+    title: '瓦斯抽采纯量 (m³/min)',
+    code: 'gasMass',
+  },
+  {
+    title: '残余瓦斯含量 (m³/t)',
+    code: 'gasMass',
+  },
+  {
+    title: '累计抽采量 (m³)',
+    code: 'gasTotalMass',
+  },
+  {
+    title: '风压 (kPa)',
+    code: 'windPressure',
+  },
+];
+
+export const gasParamData = [
+  {
+    title: '走向长度 (m)',
+    code: 'lenH',
+  },
+  {
+    title: '倾向长度 (m)',
+    code: 'lenDip',
+  },
+  {
+    title: '煤层厚度 (m)',
+    code: 'thickness',
+  },
+  {
+    title: '煤层倾角 (°)',
+    code: 'angleDip',
+  },
+  {
+    title: '吸附常数a (cm³/gdaf)',
+    code: 'adsorbA',
+  },
+  {
+    title: '吸附常数b (MPa-l)',
+    code: 'adsorbB',
+  },
+  {
+    title: '水分Mad (%)',
+    code: 'waterMad',
+  },
+  {
+    title: '灰分Ad (%)',
+    code: 'dustAd',
+  },
+  {
+    title: '挥发分Vdaf (%)',
+    code: 'volatilizeAd',
+  },
+  {
+    title: '孔隙率 (m³)',
+    code: 'poreRate',
+  },
+  {
+    title: '真相对密度',
+    code: 'trueDensity',
+  },
+  {
+    title: '视相对密度',
+    code: 'apparentDensity',
+  },
+];
+
+export const currentGasMonitor = [
+  {
+    title: '原始瓦斯含量 (m³/t)',
+    code: 'gasOriginalMass',
+  },
+  {
+    title: '残余瓦斯含量 (m³/t)',
+    code: 'gasRemnantMass',
+  },
+  {
+    title: '残存瓦斯含量 (m³/t)',
+    code: 'gasSurviveMass',
+  },
+  {
+    title: '瓦斯压力 (MPa)',
+    code: 'gasTotalMass',
+  },
+  {
+    title: '煤层厚度 (m)',
+    code: 'currentThickness',
+  },
+  {
+    title: '煤层倾角 (°)',
+    code: 'currentAngleDip',
+  },
+  {
+    title: '地质构造',
+    code: 'geologicStructure',
+  },
+];
+
+export const gasPumpValve = [
+  {
+    title: '1#智能阀门',
+    code: 'valve1Val',
+    inputNum: 0,
+  },
+  {
+    title: '2#智能阀门',
+    code: 'valve2Val',
+    inputNum: 0,
+  },
+  {
+    title: '3#智能阀门',
+    code: 'valve3Val',
+    inputNum: 0,
+  },
+  {
+    title: '4#智能阀门',
+    code: 'valve4Val',
+    inputNum: 0,
+  },
+  {
+    title: '5#智能阀门',
+    code: 'valve5Val',
+    inputNum: 0,
+  },
+];
+
+export const highTensionNum = 3;
+export const lowTensionNum = 1;
+export const gasExtractionUnit = [
+  {
+    title: '负压 (kPa)',
+    code: 'nPressure',
+  },
+  {
+    title: 'CH4 (%)',
+    code: 'CH4  ',
+  },
+  {
+    title: '流量 (m³/min)',
+    code: 'flowRate',
+  },
+  {
+    title: '纯量 (m³/min)',
+    code: 'scalarRate',
+  },
+  // {
+  //   title: '累计抽采量 (m³)',
+  //   code: 'unitTotalMass',
+  // },
+];
+export const gasPump = [
+  {
+    title: '1#抽采泵',
+    code: 'extractionPump1',
+    value: '0',
+    ctrCode: 'gasPump1Open',
+  },
+  {
+    title: '1#抽采泵',
+    code: 'extractionPump1',
+    value: '0',
+    ctrCode: 'gasPump2Open',
+  },
+];
+export const gasPumpCtr = reactive({
+  gasPump1Open: '0',
+  gasPump2Open: '0'
+});
+

+ 326 - 0
src/views/vent/monitorManager/beltTunMonitor/beltTun.threejs.base.ts

@@ -0,0 +1,326 @@
+import * as THREE from 'three';
+import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
+import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
+import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js';
+import { OutlinePass } from 'three/examples/jsm/postprocessing/OutlinePass.js';
+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';
+
+class WorkFace {
+  model;
+  modelName = 'beltTun';
+  group: THREE.Object3D = new THREE.Object3D();
+  bloomComposer: EffectComposer | null = null;
+  finalComposer: EffectComposer | null = null;
+  outlinePass: OutlinePass | null = null;
+  positions: THREE.Vector3[][] = [];
+  msgPositions = [];
+  bloomLayer = new THREE.Layers();
+  darkMaterial = new THREE.MeshBasicMaterial({ color: 'black', transparent: true, side: THREE.DoubleSide });
+  materials = {};
+  glob = {
+    ENTIRE_SCENE: 0,
+    BLOOM_SCENE: 1,
+    N: 100,
+  };
+  locationTexture: THREE.Texture | null = null;
+  warningLocationTexture: THREE.Texture | null = null;
+  errorLocationTexture: THREE.Texture | null = null;
+  playerStartClickTime1 = new Date().getTime();
+  playerStartClickTime2 = new Date().getTime();
+
+  constructor(model) {
+    this.model = model;
+    this.group.name = this.modelName;
+  }
+  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;
+
+    // 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();
+    // });
+  }
+  // 设置模型位置
+  setModalPosition() {
+    this.group?.scale.set(22, 22, 22);
+    this.group?.position.set(-15, 25, 15);
+  }
+
+  render() {
+    const _this = this;
+    if (this.model && this.model.scene.getObjectByName(this.modelName)) {
+      this.group?.traverse((obj) => {
+        _this.darkenNonBloomed(obj);
+      });
+      this.bloomComposer?.render();
+      this.group?.traverse((obj) => {
+        _this.restoreMaterial(obj);
+      });
+      this.finalComposer?.render();
+      this.model.css3dRender?.render(this.model.scene as THREE.Scene, this.model.camera as THREE.PerspectiveCamera);
+    }
+  }
+
+  setRenderPass = () => {
+    this.bloomLayer.set(this.glob.BLOOM_SCENE);
+
+    const params = {
+      bloomStrength: 2.5,
+      bloomThreshold: 0,
+      bloomRadius: 0,
+    };
+    const renderScene = new RenderPass(this.model.scene, this.model.camera);
+
+    const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85);
+
+    bloomPass.strength = params.bloomStrength;
+    bloomPass.radius = params.bloomRadius;
+    bloomPass.threshold = params.bloomThreshold;
+
+    this.bloomComposer = new EffectComposer(this.model.renderer);
+    this.bloomComposer.renderToScreen = false;
+    this.bloomComposer.addPass(renderScene);
+    this.bloomComposer.addPass(bloomPass);
+
+    const finalPass = new ShaderPass(
+      new THREE.ShaderMaterial({
+        uniforms: {
+          baseTexture: { value: null },
+          bloomTexture: { value: this.bloomComposer.renderTarget2.texture },
+        },
+        vertexShader: `
+      varying vec2 vUv;
+
+      void main() {
+        vUv = uv;
+        gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
+      }`,
+        fragmentShader: `uniform sampler2D baseTexture;
+      uniform sampler2D bloomTexture;
+
+      varying vec2 vUv;
+
+      void main() {
+        gl_FragColor = ( texture2D( baseTexture, vUv ) + vec4( 1.0, 1.0, 1.0, 0.0 ) * texture2D( bloomTexture, vUv ) );
+      }`,
+        defines: {},
+      }),
+      'baseTexture'
+    );
+    const gammaCorrection = new ShaderPass(GammaCorrectionShader);
+    finalPass.needsSwap = true;
+
+    this.finalComposer = new EffectComposer(this.model.renderer);
+    this.finalComposer.addPass(renderScene);
+
+    this.finalComposer.addPass(gammaCorrection);
+    this.finalComposer.addPass(finalPass);
+
+    const effectFXAA = new ShaderPass(FXAAShader);
+    effectFXAA.uniforms['resolution'].value.set(1 / window.innerWidth, 1 / window.innerHeight);
+    this.finalComposer.addPass(effectFXAA);
+
+    // this.outlinePass = new OutlinePass(new THREE.Vector2(window.innerWidth, window.innerHeight), this.model.scene, this.model.camera);
+    // this.finalComposer.addPass(this.outlinePass);
+  };
+
+  getPositions(num = 40) {
+    const curve1 = new THREE.LineCurve3(new THREE.Vector3(-0.818, 0.002, 0.363), new THREE.Vector3(0.722, 0.002, 0.363)); // 前
+    const curve2 = new THREE.LineCurve3(new THREE.Vector3(-0.818, 0.002, -0.459), new THREE.Vector3(0.718, -0.002, -0.459)); // 中
+    const curve3 = new THREE.LineCurve3(new THREE.Vector3(0.345, 0.008, 0.329), new THREE.Vector3(0.345, 0.008, -0.43)); // 后
+
+    const len1 = curve1.getLength();
+    const len2 = curve2.getLength();
+    const len3 = curve3.getLength();
+
+    const unit = (len1 + len2 + len3) / num;
+    const num1 = Math.floor(len1 / unit);
+    const num2 = Math.floor(len2 / unit);
+    const num3 = Math.floor(len3 / unit);
+
+    const points1 = curve1.getPoints(num1);
+    const points2 = curve2.getPoints(num2);
+    const points3 = curve3.getPoints(num3);
+
+    this.positions = [points1, points2, points3];
+
+    this.msgPositions = [curve1.getSpacedPoints(10), curve2.getSpacedPoints(10), curve3.getSpacedPoints(10)];
+  }
+
+  drawSpheres = () => {
+    const _this = this;
+    const pointLines = new THREE.Object3D();
+    pointLines.name = 'pointLines';
+    return new Promise((resolve) => {
+      new THREE.TextureLoader().load('/model/img/texture-smoke.png', (texture) => {
+        texture.encoding = THREE.sRGBEncoding;
+        const material = new THREE.PointsMaterial({
+          color: '#FFFFAF',
+          size: 0.03,
+          map: texture,
+          transparent: true, // 开启透明度
+        });
+
+        _this.positions.forEach((position, index) => {
+          const geometry = new THREE.BufferGeometry();
+          geometry.setFromPoints(position);
+          const points = new THREE.Points(geometry, material);
+          points.renderOrder = 0;
+          index == 0 ? (points.name = 'line_q') : index == 1 ? (points.name = 'line_h') : (points.name = 'line_z');
+          pointLines.add(points);
+          points.layers.enable(_this.glob.BLOOM_SCENE);
+        });
+
+        this.group.add(pointLines);
+
+        resolve(null);
+      });
+    });
+  };
+
+  darkenNonBloomed(obj) {
+    if (obj.isMesh && this.bloomLayer.test(obj.layers) === false) {
+      const opacity = obj.material.opacity;
+      this.materials[obj.uuid] = obj.material;
+      obj.material = this.darkMaterial.clone();
+      obj.material.opacity = opacity;
+    }
+  }
+
+  restoreMaterial(obj) {
+    if (this.materials[obj.uuid]) {
+      obj.material = this.materials[obj.uuid];
+      delete this.materials[obj.uuid];
+    }
+  }
+
+  /* 点击 */
+  mousedownModel(rayCaster: THREE.Raycaster) {
+    // const outlinePass = this.outlinePass;
+    // const selectedObjects = [];
+    // outlinePass.selectedObjects = selectedObjects;
+    const opticalFiber = this.group.getObjectByName('opticalfiber');
+    if (opticalFiber) {
+      const intersects = rayCaster?.intersectObjects([...opticalFiber.children]) as THREE.Intersection[];
+
+      // 判断是否点击到视频
+      // intersects.find((intersect) => {
+      //   const mesh = intersect.object;
+      //   if (mesh.name.startsWith('optical_fiber_')) {
+      //     // outlinePass?.selectedObjects.push(mesh);
+      //     return true;
+      //   }
+      //   return false;
+      // });
+    }
+    this.render();
+  }
+
+  mouseUpModel() {
+    //
+  }
+
+  mountedThree() {
+    return new Promise(async (resolve) => {
+      this.model.renderer.sortObjects = true;
+      this.model.camera.position.set(0, 3.1, 500);
+      this.setRenderPass();
+      this.model.orbitControls.update();
+      // this.model.orbitControls.addEventListener('change', _this.render.bind(_this));
+      this.model.setGLTFModel(['laneway']).then(async (gltf) => {
+        this.group = gltf[0];
+        this.group.name = this.modelName;
+        this.group.position.set(-3.5, 0.7, 0);
+        (this.group as THREE.Group).remove(this.group.getObjectByName('mesh001'));
+        const optical = this.group.getObjectByName('optical_fiber_');
+        if (optical) {
+          optical.renderOrder = 9;
+          optical.material = new THREE.MeshBasicMaterial({
+            color: 0x555555,
+            side: THREE.DoubleSide,
+            transparent: true,
+            opacity: 0.15,
+          });
+        }
+
+        this.getPositions();
+        this.addLight();
+        this.drawSpheres();
+        resolve(null);
+      });
+    });
+  }
+
+  destroy() {
+    this.model.clearGroup(this.group);
+    this.model = null;
+    this.group = null;
+  }
+}
+
+export default WorkFace;

+ 120 - 0
src/views/vent/monitorManager/beltTunMonitor/beltTun.threejs.ts

@@ -0,0 +1,120 @@
+import * as THREE from 'three';
+import UseThree from '../../../../utils/threejs/useThree';
+import WorkFace from './beltTun.threejs.base';
+import { animateCamera } from '/@/utils/threejs/util';
+import { useAppStore } from '/@/store/modules/app';
+
+// 模型对象、 文字对象
+let model,
+  beltTunObj: WorkFace,
+  group,
+  fiberType = 'beltTun'; // 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 (fiberType === 'beltTun') {
+      beltTunObj.mousedownModel.call(beltTunObj, model.rayCaster);
+    }
+    console.log(model.camera, model.orbitControls);
+    // 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 === 'beltTun') {
+    //     beltTunObj.mousedownModel.call(beltTunObj, intersects);
+    //   }
+    // }
+  }
+};
+
+const addMouseEvent = () => {
+  // 定义鼠标点击事件
+  model.canvasContainer?.addEventListener('mousedown', mouseEvent.bind(null));
+  model.canvasContainer?.addEventListener('pointerup', (event) => {
+    event.stopPropagation();
+    if (fiberType === 'beltTun') {
+      beltTunObj.mouseUpModel.call(beltTunObj);
+    }
+  });
+};
+
+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 refreshModal = () => {
+  if (fiberType === 'beltTun') {
+    beltTunObj.render();
+  }
+};
+
+// 切换风窗类型
+export const setModelType = (type) => {
+  fiberType = type;
+  return new Promise((resolve) => {
+    if (fiberType === 'beltTun' && beltTunObj) {
+      group = beltTunObj.group;
+
+      // const oldCameraPosition = { x: 124.736, y: 63.486, z: 103.337 };
+      const oldCameraPosition = { x: 124.736, y: 63.486, z: 103.337 };
+      if (!model.scene.getObjectByName('beltTun')) {
+        model.scene.add(beltTunObj.group);
+      }
+      model.orbitControls.addEventListener('change', beltTunObj.render.bind(beltTunObj));
+
+      setTimeout(async () => {
+        resolve(null);
+        const position = { x: 5.369494685025012, y: 3.6247292490341736, z: 7.5 };
+        await animateCamera(
+          oldCameraPosition,
+          oldCameraPosition,
+          { x: position.x, y: position.y, z: position.z },
+          { x: 0, y: 0, z: 0 },
+          model,
+          0.8,
+          beltTunObj.render.bind(beltTunObj)
+        );
+      }, 600);
+    }
+  });
+};
+
+export const mountedThree = () => {
+  return new Promise(async (resolve) => {
+    model = new UseThree('#beltTun3D', '#beltTun3DCSS');
+    model.setEnvMap('test1');
+    model.renderer.toneMappingExposure = 1;
+    model.camera.position.set(100, 0, 1000);
+    beltTunObj = new WorkFace(model);
+    await beltTunObj.mountedThree();
+
+    addMouseEvent();
+    render();
+    resolve(null);
+  });
+};
+
+export const destroy = () => {
+  if (model) {
+    beltTunObj.destroy();
+    model.deleteModal();
+    model = null;
+    group = null;
+    beltTunObj = null;
+  }
+};

+ 35 - 0
src/views/vent/monitorManager/beltTunMonitor/components/beltTunAlarmHistory.vue

@@ -0,0 +1,35 @@
+<template>
+  <div class="alarm-history">
+    <AlarmHistoryTable columns-type="alarm" device-type="sys_maintunnel_leather"
+      :device-list-api="workFaceDeviceList.bind(null, { id: deviceId })"
+      :list="list"
+      :sys-id="deviceId"
+      designScope="alarm-history" />
+  </div>
+</template>
+<script setup lang="ts">
+import AlarmHistoryTable from '../../comment/WorkFaceAlarmHistoryTable.vue';
+import { workFaceDeviceList } from '../../../deviceManager/comment/warningTabel/warning.api'
+import { defHttp } from '/@/utils/http/axios';
+
+const props = defineProps({
+  deviceType: {
+    type: String,
+    required: true,
+  },
+  deviceId: {
+    type: String,
+    required: true,
+  }
+})
+
+const list = (params) => defHttp.get({ url: '/safety/managesysAutoLog/list', params })
+
+
+</script>
+<style lang="less" scoped>
+.alarm-history {
+  pointer-events: auto;
+  margin-top: 60px !important;
+}
+</style>

+ 244 - 0
src/views/vent/monitorManager/beltTunMonitor/components/beltTunDustHome.vue

@@ -0,0 +1,244 @@
+<template>
+  <a-spin tip="Loading..." :spinning="loading">
+    <div class="monitor-container">
+      <div class="lr left-box vent-margin-t-10">
+        <ventBox1 class="vent-margin-t-10">
+          <template #title>
+            <div>煤机喷雾参数</div>
+          </template>
+          <template #container>
+            <div v-for="(item, index) in coalMachineDustParam" class="input-item" style="padding: 4px 8px; margin: 6px 0;"
+              :key="index">
+              <div class="title">{{ item.title }}</div>
+              <div class="value">-</div>
+              <div class="unit">{{ item.unit }}</div>
+            </div>
+          </template>
+        </ventBox1>
+      </div>
+      <div class="lr right-box">
+        <ventBox1>
+          <template #title>
+            <div>除尘风机监测与控制</div>
+          </template>
+          <template #container>
+            <div class="dust-fan-monitor">
+              <div class="dust-fan-monitor-item" v-for="(item, index) in dustMonitor" :key="index">
+                <div class="title">{{ item.title }}</div>
+                <div class=""><span class="value">-</span> <span class="unit"> {{ item.unit }} </span></div>
+              </div>
+              <div class="dust-fan-monitor-item fault">
+                <div class="title">风机故障诊断</div>
+                <div class=""><span class="value">正常</span></div>
+              </div>
+            </div>
+
+            <div class="parameter-title group-parameter-title vent-margin-t-10">
+              <SvgIcon class="icon" size="20" name="control-setting" /><span>设备基础参数</span>
+            </div>
+            <div class="data-group">
+              <div class="data-item" v-for="(item, index) in dustFanParam" :key="index">
+                <div class="title">{{ item.title }}</div>
+                <div class="value">-</div>
+              </div>
+            </div>
+            <div class="parameter-title group-parameter-title">
+              <SvgIcon class="icon" size="20" name="control-setting" /><span>控制设备</span>
+            </div>
+            <div class="input-item vent-flex-row-between">
+              <div>除尘器控制:</div>
+              <div class="vent-flex-row btn-box">
+                <div class="btn btn1">启动</div>
+                <div class="btn btn2">停机</div>
+              </div>
+            </div>
+            <div v-for="(item, index) in dustFanSetting" :key="index" class="input-item vent-flex-row-between">
+              <div class="title-auto">{{ item.title }}:</div>
+              <div>
+                <a-input class="input-value" v-model="item.inputNum" placeholder="" />
+                <span class="btn btn1 vent-margin-l-8">保存</span>
+              </div>
+            </div>
+          </template>
+        </ventBox1>
+
+      </div>
+    </div>
+  </a-spin>
+</template>
+
+<script setup lang="ts">
+
+import { onBeforeMount, ref, onMounted, onUnmounted, reactive, defineProps } from 'vue';
+import { list } from '../beltTun.api';
+import ventBox1 from '/@/components/vent/ventBox1.vue'
+import { SvgIcon } from '/@/components/Icon';
+import { dustFanParam, coalMachineDustParam, dustMonitor, dustFanSetting } from '../beltTun.data'
+
+const props = defineProps({
+  deviceId: {
+    type: String,
+    require: true
+  }
+})
+
+const loading = ref(false)
+
+// 默认初始是第一行
+const openDust = ref(false)
+const workFaceSource = ref({});
+const workFaceHistorySource = ref([])
+const gateDataSource = ref([]);
+const windowDataSource = ref([]);
+const windDataSource = ref([]);
+const temperatureDataSource = ref([]);
+const fireDataSource = ref([]);
+
+// 监测数据
+const selectData = reactive({});
+
+// https获取监测数据
+let timer: null | NodeJS.Timeout = null;
+function getMonitor(flag?) {
+  if (Object.prototype.toString.call(timer) === '[object Null]') {
+    timer = setTimeout(async () => {
+      if (props.deviceId) {
+        const data = await getDataSource(props.deviceId)
+        Object.assign(selectData, data);
+      }
+      if (timer) {
+        timer = null;
+      }
+      await getMonitor();
+      loading.value = false
+    }, flag ? 0 : 1000);
+  }
+};
+
+async function getDataSource(systemID) {
+  const res = await list({ devicetype: 'sys', systemID });
+  const result = res.msgTxt;
+  result.forEach(item => {
+    // ''.startsWith
+    if (item.type.startsWith('gate')) {
+      // 风门
+      gateDataSource.value = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+
+    }
+    if (item.type.startsWith('window')) {
+      // 风窗
+      windowDataSource.value = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+    }
+    if (item.type.startsWith('windrect')) {
+      // 测风
+      windDataSource.value = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+    }
+    if (item.type === 'modelsensor_temperature') {
+      // 温度
+      temperatureDataSource.value = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+    }
+    if (item.type === 'modelsensor_fire') {
+      // 火焰
+      fireDataSource.value = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+    }
+    if (item.type === 'sys') {
+      workFaceSource.value = Object.assign(item['datalist'][0], item['datalist'][0].readData);
+    }
+    if (item.type === 'surface_history') {
+      workFaceHistorySource.value = item['datalist'][0]
+    }
+    loading.value = false;
+  })
+}
+
+function toDetail() {
+
+}
+
+function changeType(e: Event, item) {
+  item.value = e.target?.value
+}
+
+onBeforeMount(() => {
+
+});
+
+onMounted(async () => {
+  loading.value = true;
+  timer = null
+  await getMonitor(true)
+});
+onUnmounted(() => {
+  if (timer) {
+    clearTimeout(timer);
+    timer = undefined;
+  }
+});
+</script>
+<style lang="less" scoped>
+@import '/@/design/vent/modal.less';
+@import '../../comment/less/workFace.less';
+@ventSpace: zxm;
+
+.dust-fan-monitor {
+  display: flex;
+  flex-wrap: wrap;
+}
+
+.dust-fan-monitor-item {
+  width: 152px;
+  height: 70px;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  border: 1px solid rgba(25, 251, 255, 0.4);
+  box-shadow: inset 0 0 20px rgba(0, 197, 255, 0.4);
+  background: rgba(0, 0, 0, 0.06666667);
+  margin-bottom: 5px;
+  padding: 8px 0;
+
+  &:nth-child(2n) {
+    margin-left: 12px;
+  }
+
+  .title {
+    color: #5dfaff;
+  }
+
+  .unit {
+    font-size: 13px;
+    color: #ffffffaa;
+  }
+
+  .value {
+    color: #FFB212;
+  }
+}
+
+.fault {
+  .title {
+    color: #c4fdff;
+  }
+
+  .value {
+    // color: #FFB212;
+    color: #61ddb1;
+  }
+}
+</style>

+ 342 - 0
src/views/vent/monitorManager/beltTunMonitor/components/beltTunFireHome.vue

@@ -0,0 +1,342 @@
+<template>
+  <a-spin tip="Loading..." :spinning="loading">
+    <div class="monitor-container">
+      <div class="lr left-box vent-margin-t-10">
+        <div class="monitor-info item-box">
+          <div class="fire-analysis ">
+            <div class="analysis-item warning3">
+              <div class="title">火灾风险预警</div>
+              <div class="value">高风险</div>
+            </div>
+          </div>
+          <ventBox1 class="vent-margin-t-20">
+            <template #title>
+              <div>光纤测温监测与分析<a class="a-detail">(详情)</a></div>
+            </template>
+            <template #container>
+              <div class="temperature-box">
+                <div class="temperature-group">
+                    <div class="light-group">
+                      <div class="light-bg"></div>
+                      <div class="light-item">
+                        <SvgIcon class="icon" size="25" name="aveg-temperature" />
+                        <div class="light">
+                          <div class="light-icon"></div>
+                          <div class="light-title">平均温度</div>
+                          <div class="light-val-box">
+                            <div class="light-val-icon"></div>
+                            <div class="light-val">56.99</div>
+                          </div>
+                        </div>
+                      </div>
+                      <div class="light-item">
+                        <SvgIcon class="icon" size="25" name="max-temperature" />
+                        <div class="light">
+                          <div class="light-icon"></div>
+                          <div class="light-title">最高温度</div>
+                          <div class="light-val-box">
+                            <div class="light-val-icon"></div>
+                            <div class="light-val">56.99</div>
+                          </div>
+                        </div>
+                      </div>
+                      <div class="light-item">
+                        <SvgIcon class="icon" size="25" name="min-temperature" />
+                        <div class="light">
+                          <div class="light-icon"></div>
+                          <div class="light-title">最低温度</div>
+                          <div class="light-val-box">
+                            <div class="light-val-icon"></div>
+                            <div class="light-val">56.99</div>
+                          </div>
+                        </div>
+                      </div>
+                    </div>
+              
+                </div>
+                <div class="vent-flex-row vent-margin-t-10 vent-margin-l-5">
+                  <div class="vent-flex-row ">
+                    <SvgIcon class="icon vent-margin-r-5" size="13" name="alarm-fire" />
+                    <span>是否报警:</span>
+                  </div>
+                  <div class="vent-flex-row vent-margin-l-10">
+                    <div class="vent-breathe-zc vent-margin-r-8"></div>
+                    <div>正常</div>
+                  </div>
+                </div>
+                <div class="warning-state-detail">
+                  最大值产生于 <span class="state-color">2013-05-24 15:52:42</span> 时刻 <span class="state-color">15212胶运顺槽600m</span> 处
+                </div>
+              </div>
+            </template>
+          </ventBox1>
+          <ventBox1 class="vent-margin-t-20">
+            <template #title>
+              <div>CO传感器监测与分析<a class="a-detail">(详情)</a></div>
+            </template>
+            <template #container>
+              <div class="CO-box ">
+                <div class="co-param">
+                  <div class="light-group">
+                    <div class="param-item">
+                      <div class="param">
+                        <div class="param-icon">
+                          <SvgIcon class="icon" size="30" name="CO-aveg" />
+                          <div class="param-unit">平均(%)</div>
+                        </div>
+
+                        <div class="param-val-box">
+                          <div class="param-val-icon"></div>
+                          <div class="param-val">56.99</div>
+                        </div>
+                      </div>
+                    </div>
+                    <div class="param-item">
+                      <div class="param">
+                        <div class="param-icon">
+                          <SvgIcon class="icon" size="30" name="CO-top" />
+                          <div class="param-unit">最大(%)</div>
+                        </div>
+                        <div class="param-val-box">
+                          <div class="param-val-icon"></div>
+                          <div class="param-val">56.99</div>
+                        </div>
+                      </div>
+                    </div>
+                    <div class="param-item">
+                      <div class="param">
+                        <div class="param-icon">
+                          <SvgIcon class="icon" size="30" name="CO-low" />
+                          <div class="param-unit">最小(%)</div>
+                        </div>
+                        <div class="param-val-box">
+                          <div class="param-val-icon"></div>
+                          <div class="param-val">56.99</div>
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+                <div class="vent-flex-row vent-margin-l-5">
+                  <div class="vent-flex-row ">
+                    <SvgIcon class="icon vent-margin-r-5" size="13" name="alarm-CO" />
+                    <span>是否报警:</span>
+                  </div>
+                  <div class="vent-flex-row vent-margin-l-10">
+                    <div class="vent-breathe-zc vent-margin-r-8"></div>
+                    <div>正常</div>
+                  </div>
+                </div>
+                <div class="warning-state-detail">
+                  最大值产生于 <span class="state-color">2013-05-24 15:52:42</span> 时刻 <span class="state-color">CO传感器1</span>
+                </div>
+              </div>
+            </template>
+          </ventBox1>
+        </div>
+      </div>
+      <div class="lr right-box">
+        <ventBox1 class="vent-margin-t-20">
+          <template #title>
+            <div>烟雾传感器监测与分析<a class="a-detail">(详情)</a></div>
+          </template>
+          <template #container>
+            <div class="">
+              <div class="vent-flex-row vent-margin-l-5">
+                <div class="vent-flex-row">
+                  <SvgIcon class="icon vent-margin-r-5" size="13" name="alarm-smoke" />
+                  <span>是否报警:</span>
+                </div>
+                <div class="vent-flex-row vent-margin-l-10">
+                  <div class="vent-breathe-zc vent-margin-r-8"></div>
+                  <div>正常</div>
+                </div>
+              </div>
+            </div>
+          </template>
+        </ventBox1>
+        <ventBox1 class="vent-margin-t-20">
+          <template #title>
+            <div>温度传感器监测与分析<a class="a-detail">(详情)</a></div>
+          </template>
+          <template #container>
+            <div class="">
+              <div class="vent-flex-row vent-margin-l-5">
+                <div class="vent-flex-row ">
+                  <SvgIcon class="icon vent-margin-r-5" size="13" name="alarm-temperature" />
+                  <span>是否报警:</span>
+                </div>
+                <div class="vent-flex-row vent-margin-l-10">
+                  <div class="vent-breathe-yc vent-margin-r-8"></div>
+                  <div>正常</div>
+                </div>
+              </div>
+              <div class="warning-state-detail">
+                报警产生于 <span class="state-color">2013-05-24 15:52:42</span> 时刻 <span class="state-color">温度传感器1</span>
+              </div>
+            </div>
+          </template>
+        </ventBox1>
+        <ventBox1 class="vent-margin-t-20">
+          <template #title>
+            <div>喷淋/喷雾远程监测与控制</div>
+          </template>
+          <template #container>
+            <a-table :columns="sprayColumns" :data-source="sprayDataSource" :pagination="false" size="small"
+              maxWidth="340" :scroll="{ x: 'max-content', y: 180 }">
+              <template #bodyCell="{ column, record }">
+                <template v-if="column.dataIndex === 'warnFlag'">
+                  <span v-if="record['warnFlag'] == 0" style="color: #00ff00;">正常</span>
+                  <span v-else style="color: #ff0000;"> {{ record.warnDes }}</span>
+                </template>
+                <template v-if="column.dataIndex === 'action'">
+                  <a class="action-link" @click="toDetail">启停</a>
+                </template>
+              </template>
+            </a-table>
+          </template>
+        </ventBox1>
+      </div>
+    </div>
+  </a-spin>
+</template>
+
+<script setup lang="ts">
+
+import { onBeforeMount, ref, onMounted, onUnmounted, reactive, defineProps } from 'vue';
+import { list } from '../beltTun.api';
+import ventBox1 from '/@/components/vent/ventBox1.vue'
+import { sprayColumns } from '../beltTun.data'
+import { SvgIcon } from '/@/components/Icon';
+
+const props = defineProps({
+  deviceId: {
+    type: String,
+    require: true
+  }
+})
+
+const loading = ref(false)
+
+// 默认初始是第一行
+const workFaceSource = ref({});
+const workFaceHistorySource = ref([])
+const sprayDataSource = ref([]);
+const pulpingDataSource = ref([]);
+
+// 监测数据
+const selectData = reactive({});
+
+// https获取监测数据
+let timer: null | NodeJS.Timeout = null;
+function getMonitor(flag?) {
+  if (Object.prototype.toString.call(timer) === '[object Null]') {
+    timer = setTimeout(async () => {
+      if (props.deviceId) {
+        const data = await getDataSource(props.deviceId)
+        Object.assign(selectData, data);
+      }
+      if (timer) {
+        timer = null;
+      }
+      await getMonitor();
+      loading.value = false
+    }, flag ? 0 : 1000);
+  }
+};
+
+async function getDataSource(systemID) {
+  const res = await list({ devicetype: 'sys', systemID });
+  const result = res.msgTxt;
+  result.forEach(item => {
+    if (item.type.startsWith('spray_auto')) {
+      // 喷淋
+      sprayDataSource.value = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+    }
+    if (item.type === 'pulping_auto') {
+      // 注浆
+      pulpingDataSource.value = Object.assign(item['datalist'][0], item['datalist'][0]['readData'])
+    }
+    if (item.type === 'sys') {
+      workFaceSource.value = Object.assign(item['datalist'][0], item['datalist'][0].readData);
+    }
+    if (item.type === 'surface_history') {
+      workFaceHistorySource.value = item['datalist'][0]
+    }
+    loading.value = false;
+  })
+}
+
+function toDetail() {
+
+}
+
+function changeType(e: Event, item) {
+  item.value = e.target?.value
+}
+
+function handlerDevice(param: string | Object) {
+
+}
+// 喷粉操作
+function handleSpray() {
+  //
+}
+
+onBeforeMount(() => {
+
+});
+
+onMounted(async () => {
+  loading.value = true;
+  timer = null
+  await getMonitor(true)
+});
+onUnmounted(() => {
+  if (timer) {
+    clearTimeout(timer);
+    timer = undefined;
+  }
+});
+</script>
+<style lang="less" scoped>
+@ventSpace: zxm;
+@import '/@/design/vent/modal.less';
+@import '../../comment/less/workFace.less';
+
+.fire-analysis {
+  display: flex;
+  justify-content: center;
+  .analysis-item {
+    width: 321px;
+    height: 104px;
+    text-align: center;
+    background: url('/@/assets/images/vent/alarm/1.png');
+    color: #ffffffdd;
+    margin: 0 4px;
+
+    .title {
+      margin-top: 46px;
+    }
+
+    .value {
+      margin-top: 7px;
+    }
+  }
+
+  .warning1 {
+    background: url('/@/assets/images/vent/alarm/21.png');
+  }
+
+  .warning2 {
+    background: url('/@/assets/images/vent/alarm/31.png');
+  }
+
+  .warning3 {
+    background: url('/@/assets/images/vent/alarm/41.png');
+  }
+}
+</style>

+ 327 - 0
src/views/vent/monitorManager/beltTunMonitor/components/beltTunGasHome.vue

@@ -0,0 +1,327 @@
+<template>
+  <a-spin tip="Loading..." :spinning="loading">
+    <div class="monitor-container">
+      <div class="lr left-box">
+        <ventBox1>
+          <template #title>
+            <div>工作面瓦斯监控</div>
+          </template>
+          <template #container>
+            <div class="data-group">
+              <div class="data-item" v-for="(item, index) in gasMonitor" :key="index">
+                <div class="title">{{ item.title }}</div>
+                <div class="value">-</div>
+              </div>
+            </div>
+          </template>
+        </ventBox1>
+        <ventBox1 class="vent-margin-t-10"> 
+          <template #title>
+            <div>当前抽采地质测定 (<span class="param-set"> 参数设定 </span> ) </div>
+          </template>
+          <template #container>
+            <div class="data-group">
+              <div class="data-item" v-for="(item, index) in currentGasMonitor" :key="index">
+                <div class="title">{{ item.title }}</div>
+                <div class="value">-</div>
+              </div>
+            </div>
+          </template>
+        </ventBox1>
+        <ventBox1 class="vent-margin-t-10"> 
+          <template #title>
+            <div>工作面瓦斯抽采基础属性参数</div>
+          </template>
+          <template #container>
+            <div class="data-group">
+              <div class="data-item" v-for="(item, index) in gasParamData" :key="index">
+                <div class="title">{{ item.title }}</div>
+                <div class="value">-</div>
+              </div>
+            </div>
+          </template>
+        </ventBox1>
+        
+      </div>
+      <div class="lr right-box">
+        <div class="item-box sensor-container">
+          <ventBox1>
+            <template #title>
+              <div>瓦斯抽采监测与控制</div>
+            </template>
+            <template #container>
+              <div class="parameter-title group-parameter-title"><SvgIcon class="icon" size="42" name="alarm-icon"/><span>抽采泵监测与控制</span></div>
+              <div class="vent-margin-b-10 vent-padding-lr-5">
+                <div class="vent-flex-row-between vent-padding-lr-5 gas-pump-item" v-for="(item, index) in gasPump" :key="index">
+                  <div class="title">{{ item.title }}</div>
+                  <div><span class="signal-round vent-margin-r-8" :class="{ 'signal-round-gry': item.value == '0', 'signal-round-blue': item.value == '1' }"></span>{{ item.value == '0' ? '关闭' : '开启' }}</div>
+                  <a-switch v-model:checked="gasPumpCtr[item.ctrCode]" checked-children="开启" un-checked-children="关闭" checkedValue="1" unCheckedValue="0" />
+                </div>
+              </div>
+              <div class="parameter-title group-parameter-title vent-margin-t-15"><SvgIcon class="icon" size="42" name="alarm-icon"/><span>阀门开度管理</span></div>
+              <div class="input-box">
+                <div v-for="(item, index) in gasPumpValve" :key="index" class="input-item">
+                  <div class="">{{ item.title }}</div>
+                  <div class="value">-</div>
+                  <a-input class="input-value" v-model="item.inputNum" placeholder="" />
+                  <span class="btn btn1">保存</span>
+                </div>
+              </div>
+              <div class="parameter-title group-parameter-title vent-margin-t-15"><SvgIcon class="icon" size="42" name="alarm-icon"/><span>高负压管路监测与控制</span></div>
+              <div  v-for="num in highTensionNum" :key="num">
+                <div class="vent-flex-row-between">
+                  <span class="base-title">抽采单元{{ num }}</span>
+                  <div class="detail">详情</div>
+                </div>
+                <div class="data-group vent-padding-lr-5">
+                  <div class="data-item" v-for="(item, index) in gasExtractionUnit" :key="index">
+                    <div class="title">{{ item.title }}</div>
+                    <div class="value">-</div>
+                  </div>
+                </div>
+              </div>
+              <div class="parameter-title group-parameter-title"><SvgIcon class="icon" size="42" name="alarm-icon"/><span>低负压管路监测与控制</span></div>
+              <div v-for="num in lowTensionNum" :key="num">
+                <div class="vent-flex-row-between">
+                  <span class="base-title">抽采单元{{ num }}</span>
+                  <span class="detail">详情</span>
+                </div>
+                <div class="data-group vent-padding-lr-5">
+                  <div class="data-item" v-for="(item, index) in gasExtractionUnit" :key="index">
+                    <div class="title">{{ item.title }}</div>
+                    <div class="value">-</div>
+                  </div>
+                </div>
+              </div>
+            </template>
+          </ventBox1>
+        </div>
+      </div>
+    </div>
+  </a-spin>
+</template>
+
+<script setup lang="ts">
+
+import { onBeforeMount, ref, onMounted, onUnmounted, reactive, defineProps } from 'vue';
+import { ArrowRightOutlined } from '@ant-design/icons-vue';
+import ventBox1 from '/@/components/vent/ventBox1.vue'
+import { SvgIcon } from '/@/components/Icon';
+import { list } from '../beltTun.api';
+import { gasMonitor, gasParamData, currentGasMonitor, gasPumpValve, gasPump, gasExtractionUnit, highTensionNum, lowTensionNum, gasPumpCtr } from '../beltTun.data'
+
+const props = defineProps({
+  deviceId: {
+    type: String,
+    require: true
+  }
+})
+
+const loading = ref(false)
+
+// 默认初始是第一行
+const beltTunSource = ref({});
+const beltTunHistorySource = ref([])
+const gateDataSource = ref([]);
+const windowDataSource = ref([]);
+const windDataSource = ref([]);
+const temperatureDataSource = ref([]);
+const fireDataSource = ref([]);
+
+
+// 监测数据
+const selectData = reactive({});
+
+// https获取监测数据
+let timer: null | NodeJS.Timeout = null;
+function getMonitor(flag?) {
+  if (Object.prototype.toString.call(timer) === '[object Null]') {
+    timer = setTimeout(async () => {
+      if (props.deviceId) {
+        const data = await getDataSource(props.deviceId)
+        Object.assign(selectData, data);
+      }
+      if (timer) {
+        timer = null;
+      }
+      await getMonitor();
+      loading.value = false
+    }, flag ? 0 :1000);
+  }
+};
+
+async function getDataSource(systemID) {
+  const res = await list({ devicetype: 'sys', systemID });
+  const result = res.msgTxt;
+  result.forEach(item => {
+    // ''.startsWith
+    if (item.type.startsWith('gate')) {
+      // 风门
+      gateDataSource.value = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+
+    }
+    if (item.type.startsWith('window')) {
+      // 风窗
+      windowDataSource.value = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+    }
+    if (item.type.startsWith('windrect')) {
+      // 测风
+      windDataSource.value = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+    }
+    if (item.type === 'modelsensor_temperature') {
+      // 温度
+      temperatureDataSource.value = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+    }
+    if (item.type === 'modelsensor_fire') {
+      // 火焰
+      fireDataSource.value = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+    }
+    if (item.type === 'sys') {
+      beltTunSource.value = Object.assign(item['datalist'][0], item['datalist'][0].readData);
+    }
+    if (item.type === 'surface_history') {
+      beltTunHistorySource.value = item['datalist'][0]
+    }
+    loading.value = false;
+  })
+}
+
+function toDetail() {
+
+}
+
+
+onBeforeMount(() => {
+
+});
+
+onMounted(async () => {
+  loading.value = true;
+  timer = null
+  await getMonitor(true)
+});
+onUnmounted(() => {
+  if (timer) {
+    clearTimeout(timer);
+    timer = undefined;
+  }
+});
+</script>
+
+<style lang="less">
+  @import '/@/design/vent/modal.less';
+
+  .@{ventSpace}-select-dropdown {
+    background: transparent !important;
+    border-bottom: 1px solid rgba(236, 236, 236, 0.4);
+    backdrop-filter: blur(10px);
+    .@{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;
+  @import '/@/design/vent/modal.less';
+  @import '../../comment/less/workFace.less';
+
+  .left-box{
+    width: 360px;
+  }
+  .gas-pump-item{
+    padding: 3px 0;
+  }
+
+  .param-set{
+    color: #45d3fd;
+    cursor: pointer;
+    &:hover{
+      color: #38a6c8;
+    }
+  }
+
+  .input-item{
+    margin: 3px 0 !important;
+    .value{
+      width: 80px;
+      text-align: center;
+    }
+  }
+  .data-group{
+    display: flex;
+    flex-wrap: wrap;
+    justify-content: space-between;
+    padding-bottom: 8px;
+    .data-item{
+      width: calc(50% - 10px);
+      display: flex;
+      justify-content: space-between;
+      line-height: 24px;
+      background-image: linear-gradient(to right, #39A3FF00, #39A3FF10, #39A3FF02);
+      margin: 4px 0;
+    }
+    .value{
+      color: #00eefffe;
+    }
+    .data-item1{
+      width: 100%;
+      line-height: 24px;
+      background-image: linear-gradient(to right, #39A3FF00, #39A3FF10, #39A3FF02);
+      margin: 4px 0;
+    }
+  }
+
+  .base-title{
+    line-height: 26px;
+    position: relative;
+    padding-left: 15px;
+    color: #9bf2ff;
+    &::after{
+      content: '';
+      position: absolute;
+      display: block;
+      width: 4px;
+      height: 12px;
+      top: 8px;
+      left: 5px;
+      background: #45d3fd;
+      border-radius: 4px;
+    }
+  }
+
+  .detail{
+    border: 1px solid #9bf2ff88;
+    padding: 0 5px;
+    background-color: #ffffff11;
+    margin-right: 4px;
+    &:hover{
+      background-color: #ffffff05;
+    }
+  }
+  
+</style>

+ 40 - 0
src/views/vent/monitorManager/beltTunMonitor/components/beltTunHandleHistory.vue

@@ -0,0 +1,40 @@
+<template>
+  <div class="handle-history">
+    <HandlerHistoryTable v-if="refresh" columns-type="operatorhistory" :device-type="type" :sys-id="deviceId"
+      designScope="caimei_history" />
+  </div>
+</template>
+<script setup lang="ts">
+import { watch, ref, nextTick } from 'vue'
+import HandlerHistoryTable from '../../comment/WorkFaceHandlerHistoryTable.vue';
+
+const props = defineProps({
+  deviceType: {
+    type: String,
+    required: true,
+  },
+  deviceId: {
+    type: String,
+    required: true,
+  }
+})
+
+const type = ref(props.deviceType)
+
+const refresh = ref(true)
+
+watch(() => props.deviceType, (newVal) => {
+  type.value = newVal
+  refresh.value = false
+  nextTick(() => {
+    refresh.value = true
+  })
+})
+
+
+</script>
+<style lang="less" scoped>
+.handle-history {
+  pointer-events: auto;
+}
+</style>

+ 28 - 0
src/views/vent/monitorManager/beltTunMonitor/components/beltTunHistory.vue

@@ -0,0 +1,28 @@
+<template>
+  <div class="history-box">
+    <HistoryTable :columns-type="`${deviceType}`" :device-type="deviceType" :sysId="deviceId"
+      :device-list-api="getTableList.bind(null, { strtype: deviceType, sysId: deviceId })" designScope="pressurefan_history" />
+  </div>
+</template>
+<script setup lang="ts">
+import { ref, defineProps } from 'vue'
+import HistoryTable from '../../comment/HistoryTable.vue';
+import { getTableList } from '../beltTun.api'
+
+const props = defineProps({
+  deviceType: {
+    type: String,
+    required: true,
+  },
+  deviceId: {
+    type: String,
+    required: true,
+  }
+})
+
+</script>
+<style lang="less" scoped>
+.history-box {
+  pointer-events: auto;
+}
+</style>

+ 325 - 0
src/views/vent/monitorManager/beltTunMonitor/components/beltTunHome.vue

@@ -0,0 +1,325 @@
+<template>
+  <a-spin tip="Loading..." :spinning="loading">
+    <div class="monitor-container">
+      <div class="lr left-box">
+        <ventBox1>
+          <template #title>
+            <div>通防综合监测</div>
+          </template>
+          <template #container>
+            <div class="vent-param">
+              <div class="light-group">
+                <div class="param-item">
+                  <div class="param">
+                    <div class="param-icon">
+                      <div class="param-title">总风量</div>
+                      <div class="param-unit">(m³/min)</div>
+                    </div>
+
+                    <div class="param-val-box">
+                      <div class="param-val-icon"></div>
+                      <div class="param-val">4104</div>
+                    </div>
+                  </div>
+                </div>
+                <div class="param-item">
+                  <div class="param">
+                    <div class="param-icon">
+                      <div class="param-title">风速</div>
+                      <div class="param-unit">(m/s)</div>
+                    </div>
+                    <div class="param-val-box">
+                      <div class="param-val-icon"></div>
+                      <div class="param-val">3.8</div>
+                    </div>
+                  </div>
+                </div>
+              </div>
+            </div>
+            <div class="item-container">
+              <BarAndLineCustom xAxisPropType="time" :chartData="beltTunHistorySource" height="170px"
+                :propTypeArr="['m3', 'va']" :option="echartsOption" />
+            </div>
+          </template>
+        </ventBox1>
+        <ventBox1 class="vent-margin-t-10"> 
+          <template #title>
+            <div>预警报警实时监测</div>
+          </template>
+          <template #container>
+            <div class="warning-monitor">
+              <div class="warning-item">
+                <div class="title">通风</div>
+                <div class="state-box">
+                  <span class="signal-round signal-round-blue"></span><span class="state vent-margin-l-8">正常</span>
+                </div>
+              </div>
+              <div class="warning-item">
+                <div class="title">火灾</div>
+                <div class="state-box">
+                  <span class="signal-round signal-round-blue"></span><span class="state vent-margin-l-8">正常</span>
+                </div>
+              </div>
+              <div class="warning-item">
+                <div class="title">粉尘</div>
+                <div class="state-box">
+                  <span class="signal-round signal-round-blue"></span><span class="state vent-margin-l-8">正常</span>
+                </div>
+              </div>
+              <div class="warning-item">
+                <div class="title">瓦斯</div>
+                <div class="state-box">
+                  <span class="signal-round signal-round-blue"></span><span class="state vent-margin-l-8">正常</span>
+                </div>
+              </div>
+            </div>
+            <div style="height: 180px; overflow-y: auto; position: relative; top: -10px;">
+              <dv-scroll-board ref="scrollBoard" :config="warningConfig" style="width: 100%; height: 220px; overflow-y: auto; " />
+            </div>
+          </template>
+        </ventBox1>
+      </div>
+      <div class="lr right-box">
+        <div class="item-box sensor-container">
+          <ventBox1>
+            <template #title>
+              <div>主运巷火灾应急管控</div>
+            </template>
+            <template #container>
+              <div class="input-box">
+                <div class="input-item vent-flex-row">
+                  <div>决策模式:</div>
+                  <a-radio-group v-model:value="controlMode" name="radioGroup"
+                    @change="changeType(controlMode)">
+                    <a-radio value="1">人工决策</a-radio>
+                    <a-radio value="2">智能决策</a-radio>
+                  </a-radio-group>
+                </div>
+                <div v-for="(item, index) in disasterParam" class="input-item vent-flex-row control" :key="index">
+                  <div class="title" style="width: 200px;">{{ item.title }}:</div>
+                  <template v-if="item.type == 'input'">
+                    <a-input-number class="input-value" v-model="item.value" placeholder="" />
+                  </template>
+                  <template v-if="item.type == 'select'">
+                    <a-select
+                      class="input-value"
+                      v-model:value="item.value"
+                      style="width: 100%"
+                      :options="item.options"
+                      @change="handleChange"
+                    ></a-select>
+                  </template>
+                </div>
+                <div class="btn-box vent-right vent-margin-t-10 vent-margin-b-10">
+                  <span class="btn btn1 disaster-btn">保存</span>
+                </div>
+              </div>
+            </template>
+          </ventBox1>
+          <ventBox1 class="vent-margin-t-10">
+            <template #title>
+              <div>风门监测与控制</div>
+            </template>
+            <template #container>
+              <a-table :columns="gateColumns" :data-source="gateDataSource" :pagination="false" size="small"
+                maxWidth="340" :scroll="{ x: 'max-content', y: 140 }">
+                <template #bodyCell="{ column, record }">
+                  <template v-if="column.dataIndex === 'frontGateOpen'">
+                    <span v-if="record['frontGateOpen'] == 0" >关闭</span>
+                    <span v-else style="color: #00ff00;"> 打开 </span>
+                  </template>
+                  <template v-if="column.dataIndex === 'rearGateOpen'">
+                    <span v-if="record['rearGateOpen'] == 0" >关闭</span>
+                    <span v-else style="color: #00ff00;"> 打开 </span>
+                  </template>
+                  <template v-if="column.dataIndex === 'action'">
+                    <a class="action-link" @click="toDetail">开启</a>
+                    <a-divider type="vertical" style="background-color: #c2c2c288" />
+                    <a class="action-link" @click="toDetail">关闭</a>
+                  </template>
+                </template>
+              </a-table>
+            </template>
+          </ventBox1>
+          <ventBox1 class="vent-margin-t-10">
+            <template #title>
+              <div>风窗监测与控制</div>
+            </template>
+            <template #container>
+              <a-table :columns="windowColumns" :data-source="windowDataSource" :pagination="false" size="small"
+                maxWidth="340" :scroll="{ x: 'max-content', y: 140 }">
+                <template #bodyCell="{ column }">
+                  <template v-if="column.dataIndex === 'action'">
+                    <a class="action-link" @click="toDetail">开启</a>
+                    <a-divider type="vertical" style="background-color: #c2c2c288"/>
+                    <a class="action-link" @click="toDetail">恢复</a>
+                  </template>
+                </template>
+
+              </a-table>
+            </template>
+          </ventBox1>
+        </div>
+      </div>
+    </div>
+  </a-spin>
+</template>
+
+<script setup lang="ts">
+
+import { onBeforeMount, ref, onMounted, onUnmounted, reactive, defineProps } from 'vue';
+import { list } from '../beltTun.api';
+import ventBox1 from '/@/components/vent/ventBox1.vue'
+import { ScrollBoard as DvScrollBoard } from '@kjgl77/datav-vue3';
+import { echartsOption, warningConfig, disasterParam, windowColumns, gateColumns } from '../beltTun.data'
+import BarAndLineCustom from '/@/components/chart/BarAndLineCustom.vue';
+
+const props = defineProps({
+  deviceId: {
+    type: String,
+    require: true
+  }
+})
+
+const loading = ref(false)
+
+// 默认初始是第一行
+const controlMode = ref('1')
+const beltTunSource = ref({});
+const beltTunHistorySource = ref([])
+const gateDataSource = ref([]);
+const windowDataSource = ref([]);
+const windDataSource = ref([]);
+
+// 监测数据
+const selectData = reactive({});
+
+// https获取监测数据
+let timer: null | NodeJS.Timeout = null;
+function getMonitor(flag?) {
+  if (Object.prototype.toString.call(timer) === '[object Null]') {
+    timer = setTimeout(async () => {
+      if (props.deviceId) {
+        const data = await getDataSource(props.deviceId)
+        Object.assign(selectData, data);
+      }
+      if (timer) {
+        timer = null;
+      }
+      await getMonitor();
+      loading.value = false
+    }, flag ? 0 : 1000);
+  }
+};
+
+async function getDataSource(systemID) {
+  const res = await list({ devicetype: 'sys', systemID });
+  const result = res.msgTxt;
+  result.forEach(item => {
+    // ''.startsWith
+    if (item.type.startsWith('gate')) {
+      // 风门
+      gateDataSource.value = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+    }
+    else if (item.type.startsWith('window')) {
+      // 风窗
+      windowDataSource.value = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+    }
+    else if (item.type.startsWith('windrect')) {
+      // 测风
+      windDataSource.value = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+    }
+    else if (item.type === 'sys') {
+      beltTunSource.value = Object.assign(item['datalist'][0], item['datalist'][0].readData);
+    }
+
+    else if (item.type === 'surface_history') {
+      beltTunHistorySource.value = item['datalist'][0]
+    }
+
+    loading.value = false;
+  })
+}
+
+/** 智能决策控制 */
+function changeType(mode) {
+
+}
+
+function handleChange(value) {
+  const disasterParamVal = disasterParam.value.filter(item => {
+    if (item.title === '烟雾报警持续时间(s)') {
+      item.value = value
+    }
+    return item
+  })
+  disasterParam.value = disasterParamVal
+}
+
+function toDetail() {
+
+}
+
+
+onBeforeMount(() => {
+
+});
+
+onMounted(async () => {
+  loading.value = true;
+  timer = null
+  await getMonitor(true)
+});
+onUnmounted(() => {
+  if (timer) {
+    clearTimeout(timer);
+    timer = undefined;
+  }
+});
+</script>
+
+<style lang="less">
+  @import '/@/design/vent/modal.less';
+
+  .@{ventSpace}-select-dropdown {
+    background: transparent !important;
+    border-bottom: 1px solid rgba(236, 236, 236, 0.4);
+    backdrop-filter: blur(10px);
+    .@{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>
+  @import '../../comment/less/workFace.less';
+  @ventSpace: zxm;
+
+  .warning-monitor{
+    .warning-item{
+      .state-box {
+        position: relative;
+        top: -5px;
+      }
+    }
+  }
+  
+</style>

+ 174 - 0
src/views/vent/monitorManager/beltTunMonitor/components/beltTunVentHome.vue

@@ -0,0 +1,174 @@
+<template>
+  <a-spin tip="Loading..." :spinning="loading">
+    <div class="monitor-container">
+      <div class="lr left-box vent-margin-t-10">
+        <ventBox1 class="vent-margin-t-10">
+          <template #title>
+            <div>风门监测与控制</div>
+          </template>
+          <template #container>
+            <a-table :columns="gateColumns" :data-source="gateDataSource" :pagination="false" size="small"
+              maxWidth="340" :scroll="{ x: 'max-content', y: 140 }">
+              <template #bodyCell="{ column, record }">
+                <template v-if="column.dataIndex === 'frontGateOpen'">
+                  <span v-if="record['frontGateOpen'] == 0" >关闭</span>
+                  <span v-else style="color: #00ff00;"> 打开 </span>
+                </template>
+                <template v-if="column.dataIndex === 'action'">
+                  <a class="action-link" @click="toDetail">详情</a>
+                </template>
+              </template>
+            </a-table>
+          </template>
+        </ventBox1>
+        <ventBox1 class="vent-margin-t-10">
+          <template #title>
+            <div>风窗监测与控制</div>
+          </template>
+          <template #container>
+            <a-table :columns="windowColumns" :data-source="windowDataSource" :pagination="false" size="small"
+              maxWidth="340" :scroll="{ x: 'max-content', y: 140 }">
+              <template #bodyCell="{ column }">
+                <template v-if="column.dataIndex === 'action'">
+                  <a class="action-link" @click="toDetail">详情</a>
+                </template>
+              </template>
+
+            </a-table>
+          </template>
+        </ventBox1>
+      </div>
+      <div class="lr right-box">
+        
+      </div>
+    </div>
+  </a-spin>
+</template>
+
+<script setup lang="ts">
+
+import { onBeforeMount, ref, onMounted, onUnmounted, reactive, defineProps } from 'vue';
+import { list } from '../beltTun.api';
+import ventBox1 from '/@/components/vent/ventBox1.vue'
+import { gateColumns, windowColumns, } from '../beltTun.data'
+
+const props = defineProps({
+  deviceId: {
+    type: String,
+    require: true
+  }
+})
+
+const loading = ref(false)
+
+// 默认初始是第一行
+const beltTunSource = ref({});
+const beltTunHistorySource = ref([])
+const gateDataSource = ref([]);
+const windowDataSource = ref([]);
+const windDataSource = ref([]);
+const temperatureDataSource = ref([]);
+const fireDataSource = ref([]);
+
+// 监测数据
+const selectData = reactive({});
+
+// https获取监测数据
+let timer: null | NodeJS.Timeout = null;
+function getMonitor() {
+  if (Object.prototype.toString.call(timer) === '[object Null]') {
+    timer = setTimeout(async () => {
+      if (props.deviceId) {
+        const data = await getDataSource(props.deviceId)
+        Object.assign(selectData, data);
+      }
+      if (timer) {
+        timer = null;
+      }
+      await getMonitor();
+      loading.value = false
+    }, 1000);
+  }
+};
+
+async function getDataSource(systemID) {
+  const res = await list({ devicetype: 'sys', systemID });
+  const result = res.msgTxt;
+  result.forEach(item => {
+    // ''.startsWith
+    if (item.type.startsWith('gate')) {
+      // 风门
+      gateDataSource.value = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+
+    }
+    if (item.type.startsWith('window')) {
+      // 风窗
+      windowDataSource.value = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+    }
+    if (item.type.startsWith('windrect')) {
+      // 测风
+      windDataSource.value = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+    }
+    if (item.type === 'modelsensor_temperature') {
+      // 温度
+      temperatureDataSource.value = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+    }
+    if (item.type === 'modelsensor_fire') {
+      // 火焰
+      fireDataSource.value = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+    }
+    if (item.type === 'sys') {
+      beltTunSource.value = Object.assign(item['datalist'][0], item['datalist'][0].readData);
+    }
+    if (item.type === 'surface_history') {
+      beltTunHistorySource.value = item['datalist'][0]
+    }
+    loading.value = false;
+  })
+}
+
+function toDetail() {
+
+}
+
+onBeforeMount(() => {
+
+});
+
+onMounted(async () => {
+  loading.value = true;
+  timer = null
+  await getMonitor()
+});
+onUnmounted(() => {
+  if (timer) {
+    clearTimeout(timer);
+    timer = undefined;
+  }
+});
+</script>
+<style lang="less" scoped>
+@ventSpace: zxm;
+@import '/@/design/vent/modal.less';
+@import '../../comment/less/workFace.less';
+
+:deep(.@{ventSpace}-tabs-tabpane-active) {
+  overflow: auto;
+}
+
+</style>

+ 358 - 0
src/views/vent/monitorManager/beltTunMonitor/index.vue

@@ -0,0 +1,358 @@
+<template>
+  <div
+    v-show="activeKey == 'monitor' && !loading" 
+    class="bg"
+    style="width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; overflow: hidden">
+    <a-spin :spinning="loading" />
+    <div
+        id="beltTun3DCSS"
+        class="threejs-Object-CSS"
+        v-show="!loading"
+        style="width: 100%; height: 100%; position: absolute; pointer-events: none; overflow: hidden; z-index: 1; top: 0"
+      >
+    </div>
+    <div id="beltTun3D" style="width: 100%; height: 100%; position: absolute; overflow: hidden"> </div>
+  </div>
+  <div class="scene-box">
+    <customHeader :fieldNames="{ label: 'strinstallpos', value: 'deviceID', options: 'children' }" :options = 'options' @change="getSelectRow" :optionValue="optionValue">皮带巷智能管控</customHeader>
+    <div class="center-container">
+      <template v-if="activeKey == 'monitor'">
+        <div class="monitor-nav">
+          <template  v-for="(nav, index) in monitorNavData" :key="index">
+            <div class="nav-item" :class="{'nav-item-active': nav.isShow}" @click="changeMonitor(nav)">{{ nav.title }} </div>
+            <a-divider v-if="index !== monitorNav.length - 1" type="vertical" style="height: 10px; background-color: #00e1ff;" />
+          </template>
+        </div>
+        <beltTunHome v-if="monitorActive == 0" :deviceId = 'optionValue' />
+        <beltTunVentHome v-if="monitorActive == 1" :deviceId = 'optionValue' />
+        <beltTunFireHome v-if="monitorActive == 2" :deviceId = 'optionValue'/>
+        <beltTunDustHome v-if="monitorActive == 3" :deviceId = 'optionValue'/>
+        <beltTunGasHome v-if="monitorActive == 4" :deviceId = 'optionValue'/>
+      </template>
+      <div v-else class="history-group">
+        <div class="device-button-group" v-if="deviceList.length > 0 && activeKey !== 'faultRecord'">
+          <div class="device-button" :class="{ 'device-active': deviceActive == device.deviceType }" v-for="(device, index) in deviceList" :key="index" @click="deviceChange(index)">{{ device.deviceName }}</div>
+        </div>
+        <div class="history-container">
+          <beltTunHistory v-if="activeKey == 'monitor_history'" ref="historyTable" class="vent-margin-t-20" :deviceId = 'optionValue' :device-type="deviceType"/>
+          <beltTunHandleHistory v-if="activeKey == 'handler_history'" ref="alarmHistoryTable" class="vent-margin-t-20" :deviceId = 'optionValue' :device-type="deviceType" />
+          <beltTunAlarmHistory v-if="activeKey == 'faultRecord'" ref="handlerHistoryTable" class="vent-margin-t-20" :deviceId = 'optionValue' :device-type="deviceType"/>
+        </div>
+      </div>
+    </div>
+    <BottomMenu @change="changeActive"/>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { onBeforeMount, ref, onMounted, onUnmounted, reactive, toRaw } from 'vue';
+import { mountedThree, destroy, setModelType, refreshModal } from './beltTun.threejs';
+import { list, getTableList } from './beltTun.api';
+import { monitorNav } from './beltTun.data'
+import customHeader from '/@/views/vent/comment/components/customHeader.vue';
+import BottomMenu from '/@/views/vent/comment/components/bottomMenu.vue';
+import beltTunVentHome from './components/beltTunVentHome.vue';
+import beltTunHome from './components/beltTunHome.vue';
+import beltTunFireHome from './components/beltTunFireHome.vue'
+import beltTunDustHome from './components/beltTunDustHome.vue';
+import beltTunGasHome from './components/beltTunGasHome.vue';
+import beltTunHistory from './components/beltTunHistory.vue';
+import beltTunHandleHistory from './components/beltTunHandleHistory.vue';
+import beltTunAlarmHistory from './components/beltTunAlarmHistory.vue';
+import { useRouter } from 'vue-router';
+
+type DeviceType = { deviceType: string, deviceName: string, datalist: any[] };
+
+const { currentRoute } = useRouter();
+const activeKey = ref('monitor');
+const loading = ref(false);
+
+const monitorNavData = ref(monitorNav)
+const monitorActive = ref(0)
+
+const historyTable = ref()
+const alarmHistoryTable = ref()
+const handlerHistoryTable = ref()
+
+//关联设备
+const deviceList = ref<DeviceType[]>([])
+const deviceActive = ref('')
+const deviceType = ref('')
+
+const options = ref()
+// 默认初始是第一行
+const selectRowIndex = ref(0);
+const dataSource = ref([])
+
+const optionValue = ref('')
+
+// 监测数据
+const selectData = reactive({});
+
+function changeActive(activeValue) {
+  activeKey.value = activeValue
+  loading.value = true
+  if(activeKey.value === 'monitor'){
+    // refreshModal()
+    setModelType('beltTun')
+    setTimeout(() =>{
+      loading.value = false
+    }, 600)
+    
+  }else{
+    loading.value = false
+  }
+}
+
+function deviceChange(index) {
+  deviceActive.value = deviceType.value = deviceList.value[index].deviceType
+}
+
+// 查询关联设备列表
+async function getDeviceList() {
+  const res = await list({ devicetype: 'sys', systemID: optionValue.value });
+  const result = res.msgTxt;
+  const deviceArr = <DeviceType[]>[]
+  result.forEach(item => {
+    const data = item['datalist'].filter((data: any) => {
+      const readData = data.readData;
+      return Object.assign(data, readData);
+    })
+    if (item.type != 'sys') {
+      deviceArr.unshift({ deviceType: item.type, deviceName: item['typeName'] ? item['typeName'] : item['datalist'][0]['typeName'], datalist: data })
+    }
+  })
+  deviceList.value = deviceArr
+  deviceActive.value = deviceArr[0].deviceType
+  deviceChange(0)
+};
+
+async function getSysDataSource() {
+  const res = await list({ devicetype: 'sys_maintunnel_leather', pagetype: 'normal' });
+  dataSource.value = res.msgTxt[0].datalist || [];
+  dataSource.value.forEach((data: any) => {
+    const readData = data.readData;
+    data = Object.assign(data, readData);
+  });
+
+  if (!options.value) {
+    // 初始时选择第一条数据
+    options.value = dataSource.value
+    if (!optionValue.value) {
+      optionValue.value = dataSource.value[0]['deviceID']
+      Object.assign(selectData, dataSource.value[0])
+    } else {
+      const currentData = dataSource.value.find(item => item['deviceID'] === optionValue.value) || {}
+      Object.assign(selectData, currentData)
+    }
+  }
+  const data: any = toRaw(dataSource.value[selectRowIndex.value]); //maxarea
+  return data;
+};
+
+// 切换检测数据
+async function getSelectRow(deviceID) {
+  const currentData = dataSource.value.find((item: any) => {
+    return item.deviceID == deviceID
+  })
+  if (currentData) {
+    optionValue.value = currentData['deviceID']
+    Object.assign(selectData, currentData)
+    await getDeviceList()
+  }
+}
+
+function changeMonitor(nav) {
+  nav.isShow = true
+  monitorNav.forEach((item, index) => {
+    if(item.title !== nav.title) {
+      item.isShow = false
+    }else{
+      monitorActive.value = index
+    }
+  })
+}
+
+onBeforeMount(() => {
+
+});
+
+onMounted(async() => {
+  if (currentRoute.value['query'] && currentRoute.value['query']['id']) optionValue.value = currentRoute.value['query']['id']
+  await getSysDataSource()
+  await getDeviceList()
+  
+  loading.value = true;
+  mountedThree().then(async () => {
+    setModelType('beltTun')
+    loading.value = false;
+  });
+});
+
+onUnmounted(() => {
+  destroy();
+});
+
+</script>
+<style lang="less" scoped>
+@import '/@/design/vent/modal.less';
+@ventSpace: zxm;
+
+:deep(.@{ventSpace}-tabs-tabpane-active) {
+  overflow: auto;
+}
+.scene-box{
+  width: 100%;
+  height: 100%;
+}
+.monitor-nav{
+  width: 860px;
+  height: 42px;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  // border: 1px solid #73e8fe;
+  color: #fff;
+  position: absolute;
+  top: 88px;
+  left: 50% !important;
+  transform: translateX(-50%) !important;
+  pointer-events: auto;
+  background: linear-gradient(45deg, #96c5ca38, #156c7d4a);
+  clip-path: polygon(
+    14px 0,
+    calc(100% - 14px) 0,
+    100% 14px,
+    100% calc(100% - 14px),
+    calc(100% - 14px) 100%,
+    14px 100%,
+    0 calc(100% - 14px),
+    0 14px
+  );
+  // background: url('/@/assets/images/vent/wokeFaca-nav.png') no-repeat !important;
+
+  .nav-item{
+    padding: 1px 10px;
+    cursor: pointer;
+    
+  }
+  .nav-item-active{
+    color: #00fbff;
+  }
+}
+
+.history-group{
+  padding: 0 20px;
+  .history-container{
+    position: relative;
+    background: #6195af1a;
+    width: calc(100% + 10px);
+    top: 0px;
+    left: -10px;
+    border: 1px solid #00fffd22;
+    padding: 10px 0;
+    box-shadow: 0 0 20px #44b4ff33 inset;
+  }
+}
+.device-button-group{
+  // margin: 0 20px;
+  display: flex;
+  pointer-events: auto;
+  position: relative;
+  margin-top: 90px;
+  &::after{
+    position:absolute;
+    content: '';
+    width: calc(100% + 10px);
+    height: 2px;
+    top: 30px;
+    left: -10px;
+    border-bottom: 1px solid #0efcff;
+  }
+  .device-button{
+    padding: 4px 15px;
+    position: relative;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    font-size: 14px;
+    
+    color: #fff;
+    cursor: pointer;
+    margin: 0 3px;
+
+    &::before{
+      content: '';
+      position: absolute;
+      top: 0;
+      right: 0;
+      bottom: 0;
+      left: 0;
+      border: 1px solid #6176AF;
+      transform: skewX(-38deg);
+      background-color: rgba(0, 77, 103,85%);
+      z-index: -1;
+    }
+  }
+  .device-active{
+    // color: #0efcff;
+    &::before{
+      border-color: #0efcff;
+      box-shadow: 1px 1px 3px 1px #0efcff inset;
+    }
+  }
+}
+
+.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;
+}
+.monitor-msg-box {
+  width: 170px;
+  margin-top: 100px;
+
+  .monitor-msg-container {
+    width: 170px;
+    height: 150px;
+    box-shadow: rgba(128, 128, 128, 0.3) 0px 0px 40px inset;
+    border: 1px solid rgba(128, 128, 128, 0.3);
+    background-color: transparent;
+  }
+
+  .errorColor {
+    box-shadow: #F73B2440 0px 0px 40px inset;
+    border: 1px solid #F73B2440;
+  }
+
+  .warningColor {
+    box-shadow: #FF9B1740 0px 0px 40px inset;
+    border: 1px solid #FF9B1740;
+  }
+
+  .monitor-item {
+    padding: 10px 10px 0px 10px;
+    color: #fff;
+    letter-spacing: 2px;
+
+    .item-title {
+      color: #73e8fe;
+    }
+
+    .num {
+      color: #FFA500;
+    }
+  }
+}
+</style>

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

@@ -81,21 +81,8 @@ class ChamberBase {
     // });
   }
 
-  addChamberText(selectData) {
-    //
-  }
-
   mountedThree() {
     return new Promise((resolve) => {
-      // this.model.setFBXModel(['chamber1']).then((gltf) => {
-      //   this.group = gltf[0];
-      //   if (this.group) {
-      //     this.group?.scale.set(0.1, 0.1, 0.1);
-      //     this.group.position.y += 40;
-      //     resolve(null);
-      //     this.addLight();
-      //   }
-      // });
       this.model.setGLTFModel([this.modelName]).then((gltf) => {
         this.group = gltf[0];
         if (this.group) {

+ 322 - 253
src/views/vent/monitorManager/chamberMonitor/components/chamberHome.vue

@@ -3,50 +3,12 @@
     <div class="monitor-container">
       <div class="lr left-box">
         <div class="monitor-info item-box">
-          <ventBox1>
+          <ventBox1 class="vent-margin-t-10">
             <template #title>
-              <div>光纤测温实时监测</div>
+              <div>通风监测</div>
             </template>
             <template #container>
-              <div class="temperature-group">
-                <div class="light-group">
-                  <div class="light-bg"></div>
-                  <div class="temperature-item">
-                    <SvgIcon class="icon" size="25" name="aveg-temperature" />
-                    <div class="temperature">
-                      <div class="temperature-icon"></div>
-                      <div class="temperature-title">平均温度</div>
-                      <div class="temperature-val-box">
-                        <div class="temperature-val-icon"></div>
-                        <div class="temperature-val">56.99</div>
-                      </div>
-                    </div>
-                  </div>
-                  <div class="temperature-item">
-                    <SvgIcon class="icon" size="25" name="max-temperature" />
-                    <div class="temperature">
-                      <div class="temperature-icon"></div>
-                      <div class="temperature-title">最高温度</div>
-                      <div class="temperature-val-box">
-                        <div class="temperature-val-icon"></div>
-                        <div class="temperature-val">56.99</div>
-                      </div>
-                    </div>
-                  </div>
-                  <div class="temperature-item">
-                    <SvgIcon class="icon" size="25" name="min-temperature" />
-                    <div class="temperature">
-                      <div class="temperature-icon"></div>
-                      <div class="temperature-title">最低温度</div>
-                      <div class="temperature-val-box">
-                        <div class="temperature-val-icon"></div>
-                        <div class="temperature-val">56.99</div>
-                      </div>
-                    </div>
-                  </div>
-                </div>
-              
-              </div>
+          
             </template>
           </ventBox1>
         </div>
@@ -120,11 +82,57 @@
         <div class="item-box sensor-container">
           <ventBox1>
             <template #title>
+              <div>光纤测温实时监测</div>
+            </template>
+            <template #container>
+              <div class="temperature-group">
+                <div class="light-group">
+                  <div class="light-bg"></div>
+                  <div class="light-item">
+                    <SvgIcon class="icon" size="25" name="aveg-temperature" />
+                    <div class="light">
+                      <div class="light-icon"></div>
+                      <div class="light-title">平均温度</div>
+                      <div class="light-val-box">
+                        <div class="light-val-icon"></div>
+                        <div class="light-val">56.99</div>
+                      </div>
+                    </div>
+                  </div>
+                  <div class="light-item">
+                    <SvgIcon class="icon" size="25" name="max-temperature" />
+                    <div class="light">
+                      <div class="light-icon"></div>
+                      <div class="light-title">最高温度</div>
+                      <div class="light-val-box">
+                        <div class="light-val-icon"></div>
+                        <div class="light-val">56.99</div>
+                      </div>
+                    </div>
+                  </div>
+                  <div class="light-item">
+                    <SvgIcon class="icon" size="25" name="min-temperature" />
+                    <div class="light">
+                      <div class="light-icon"></div>
+                      <div class="light-title">最低温度</div>
+                      <div class="light-val-box">
+                        <div class="light-val-icon"></div>
+                        <div class="light-val">56.99</div>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+            
+              </div>
+            </template>
+          </ventBox1>
+          <ventBox1 class="vent-margin-t-10">
+            <template #title>
               <div>烟雾传感器实时监测</div>
             </template>
             <template #container>
               <a-table :columns="sensorColumns" :data-source="smokeDataSource" :pagination="false" size="small" maxWidth="340"
-                :scroll="{ x: 'max-content', y: 240 }">
+                :scroll="{ x: 'max-content', y: 180 }">
                 <template #bodyCell="{ column, record }">
                   <template v-if="column.dataIndex === 'warnFlag'">
                     <span v-if="record['warnFlag'] == 0" style="color: #00ff00;">正常</span>
@@ -152,11 +160,12 @@
                 </template>
               </a-table>
             </template>
-          </ventBox1>        
+          </ventBox1>
+          
         </div>
-        <div class="item-box" >
+        <!-- <div class="item-box" >
           <LivePlayer id="fm-player1" style="height: 250px;" ref="player1" :videoUrl="flvURL1()" muted live loading controls />
-        </div>
+        </div> -->
       </div>
     </div>
   </a-spin>
@@ -305,235 +314,295 @@ onUnmounted(() => {
 </script>
 <style lang="less" scoped>
 @import '/@/design/vent/modal.less';
+@import '../../comment/less/workFace.less';
 @ventSpace: zxm;
 
-.monitor-container {
+.warning-group {
+  padding: 10px 0;
+}
+.monitor-box {
   width: 100%;
-  height: 100%;
-  // height: 550px;
-  // border: 1px solid #fff;
-  margin-top: 20px;
-  padding-top: 20px;
-  display: flex;
-  justify-content: space-between;
-
-  .lr {
-    width: 350px;
-    height: 100%;
-    display: flex;
-    flex-direction: column;
+  margin-bottom: 20px;
+  .parameter-title{
+    position: relative;
+    width: 100%;
+    height: 16px;
     margin-top: 10px;
-    pointer-events: auto;
-
+    margin-bottom: 5px;
+    .icon, span{
+      position: absolute;
+      top: -10px;
+    }
   }
-
-  .right-box {
-    width: 320px;
+  .group-parameter-title{
+    // background-image: linear-gradient(to right, #39a3ff50, #39a3ff00);
+    .icon{
+      left: -12px;
+      top: -20px;
+    }
+    span{
+      left: 20px;
+    }
   }
+  .item-group{
+    display: flex;
+    flex-wrap: wrap;
+    .item-col{
+      width: calc(50% - 5px);
+      background-image: linear-gradient(to right, #39A3FF00, #39A3FF10);
+      position: relative;
+      // display: flex;
+      // align-items: center;
+      &:nth-child(even){
+        margin-left: 10px;
+      }
+      padding: 2px 0;
+      margin: 3px 0;
+      .title{
+        margin-left: 5px;
+      }
+      .value{
+        position: absolute;
+        right: 10px;
+        top: 5px;
+      }
+    }
+  }
+}
+.alarm-box{
+  margin-top: 10px;
+}
+
 
-  .left-box {
-    margin-top: 30px;
-
-    .monitor-info {
-      .temperature-group {
-        width: 100%;
-        margin-top: 10px;
-        .light-group{
-          display: flex;
-          flex-direction: row;
-          justify-content: space-between;
-          position: relative;
-          .light-bg{
-            width: 331px;
-            height: 42px;
-            background: url('/@/assets/images/vent/plane-bg.png') no-repeat;
-            background-size: contain;
-            position: absolute;
-            z-index: -1;
-            top: 44px;
-          }
-          .temperature-item {
-            width: 120px;
-            display: flex;
-            flex-direction: column;
-            justify-content: center;
-            align-items: center;
-            position: reactive;
-            .icon {
-              display: block;
-              position: absolute;
-              top: -5px;
-            }
-
-            .temperature {
-              display: flex;
-              flex-direction: column;
-              justify-content: center;
-              align-items: center;
-              .temperature-icon{
-                width: 90px;
-                height: 58px;
-                background: url('/@/assets/images/vent/ligth-q.png');
-              }
-              .temperature-title{
-                position: relative;
-                top: -15px;
-              }
+// .monitor-container {
+//   width: 100%;
+//   height: 100%;
+//   // height: 550px;
+//   // border: 1px solid #fff;
+//   margin-top: 20px;
+//   padding-top: 20px;
+//   display: flex;
+//   justify-content: space-between;
+
+//   .lr {
+//     width: 350px;
+//     height: 100%;
+//     display: flex;
+//     flex-direction: column;
+//     margin-top: 10px;
+//     pointer-events: auto;
+
+//   }
+
+//   .right-box {
+//     width: 320px;
+//   }
+
+//   .left-box {
+//     margin-top: 30px;
+
+//     .monitor-info {
+//       .temperature-group {
+//         width: 100%;
+//         margin-top: 10px;
+//         .light-group{
+//           display: flex;
+//           flex-direction: row;
+//           justify-content: space-between;
+//           position: relative;
+//           .light-bg{
+//             width: 331px;
+//             height: 42px;
+//             background: url('/@/assets/images/vent/plane-bg.png') no-repeat;
+//             background-size: contain;
+//             position: absolute;
+//             z-index: -1;
+//             top: 44px;
+//           }
+//           .temperature-item {
+//             width: 120px;
+//             display: flex;
+//             flex-direction: column;
+//             justify-content: center;
+//             align-items: center;
+//             position: reactive;
+//             .icon {
+//               display: block;
+//               position: absolute;
+//               top: -5px;
+//             }
+
+//             .temperature {
+//               display: flex;
+//               flex-direction: column;
+//               justify-content: center;
+//               align-items: center;
+//               .temperature-icon{
+//                 width: 90px;
+//                 height: 58px;
+//                 background: url('/@/assets/images/vent/ligth-q.png');
+//               }
+//               .temperature-title{
+//                 position: relative;
+//                 top: -15px;
+//               }
               
-              .temperature-val-box{
-                display: flex;
-                flex-direction: column;
-                justify-content: center;
-                align-items: center;
-                position: relative;
-                top: -10px;
-                .temperature-val-icon{
-                  width: 2px;
-                  height: 18px;
-                  background: #00d8ff;
-                  position: relative;
-                  &::after{
-                    content: '';
-                    display: block;
-                    position: absolute;
-                    width: 6px;
-                    height: 6px;
-                    border-radius: 3px;
-                    background: #00d8ff;
-                    bottom: -2px;
-                    left: -2px;
-                  }
-
-                }
-                .temperature-val{
-                  position: relative;
-                  font-family: 'douyuFont';
-                  color: #20dbfd;
-                  text-shadow: 0 0 25px #00d8ff;
-                  font-size: 13px;
-                  border: 1px solid #40B7F3;
-                  padding: 5px 8px 2px 8px;
-                  top: 2px;
-                  &::after{
-                    width: calc(100% - 4px);
-                    height: calc(100% - 4px);
-                    content: '';
-                    position: absolute;
-                    top: 2px;
-                    left: 2px;
-                    display: block;
-                    border: 1px solid #006EA6;
-                  }
-                }
-              }
+//               .temperature-val-box{
+//                 display: flex;
+//                 flex-direction: column;
+//                 justify-content: center;
+//                 align-items: center;
+//                 position: relative;
+//                 top: -10px;
+//                 .temperature-val-icon{
+//                   width: 2px;
+//                   height: 18px;
+//                   background: #00d8ff;
+//                   position: relative;
+//                   &::after{
+//                     content: '';
+//                     display: block;
+//                     position: absolute;
+//                     width: 6px;
+//                     height: 6px;
+//                     border-radius: 3px;
+//                     background: #00d8ff;
+//                     bottom: -2px;
+//                     left: -2px;
+//                   }
+
+//                 }
+//                 .temperature-val{
+//                   position: relative;
+//                   font-family: 'douyuFont';
+//                   color: #20dbfd;
+//                   text-shadow: 0 0 25px #00d8ff;
+//                   font-size: 13px;
+//                   border: 1px solid #40B7F3;
+//                   padding: 5px 8px 2px 8px;
+//                   top: 2px;
+//                   &::after{
+//                     width: calc(100% - 4px);
+//                     height: calc(100% - 4px);
+//                     content: '';
+//                     position: absolute;
+//                     top: 2px;
+//                     left: 2px;
+//                     display: block;
+//                     border: 1px solid #006EA6;
+//                   }
+//                 }
+//               }
               
-            }
-          }
-        }
+//             }
+//           }
+//         }
 
         
-      }
-
-    }
-    .warning-group {
-      padding: 10px 0;
-    }
-    .monitor-box {
-      width: 100%;
-      margin-bottom: 20px;
-      .parameter-title{
-        position: relative;
-        width: 100%;
-        height: 16px;
-        margin-top: 10px;
-        margin-bottom: 5px;
-        .icon, span{
-          position: absolute;
-          top: -10px;
-        }
-      }
-      .group-parameter-title{
-        background-image: linear-gradient(to right, #39a3ff50, #39a3ff00);
+//       }
+
+//     }
+//     .warning-group {
+//       padding: 10px 0;
+//     }
+//     .monitor-box {
+//       width: 100%;
+//       margin-bottom: 20px;
+//       .parameter-title{
+//         position: relative;
+//         width: 100%;
+//         height: 16px;
+//         margin-top: 10px;
+//         margin-bottom: 5px;
+//         .icon, span{
+//           position: absolute;
+//           top: -10px;
+//         }
+//       }
+//       .group-parameter-title{
+//         background-image: linear-gradient(to right, #39a3ff50, #39a3ff00);
         
-        .icon{
-          left: -12px;
-          top: -20px;
-        }
-        span{
-          left: 20px;
-        }
+//         .icon{
+//           left: -12px;
+//           top: -20px;
+//         }
+//         span{
+//           left: 20px;
+//         }
         
-      }
-      .item-group{
-        display: flex;
-        flex-wrap: wrap;
-        .item-col{
-          width: calc(50% - 5px);
-          background-image: linear-gradient(to right, #39A3FF00, #39A3FF10);
-          position: relative;
-          // display: flex;
-          // align-items: center;
-          &:nth-child(even){
-            margin-left: 10px;
-          }
-          padding: 2px 0;
-          margin: 3px 0;
-          .title{
-            margin-left: 5px;
-          }
-          .value{
-            position: absolute;
-            right: 10px;
-            top: 5px;
-          }
-        }
-      }
+//       }
+//       .item-group{
+//         display: flex;
+//         flex-wrap: wrap;
+//         .item-col{
+//           width: calc(50% - 5px);
+//           background-image: linear-gradient(to right, #39A3FF00, #39A3FF10);
+//           position: relative;
+//           // display: flex;
+//           // align-items: center;
+//           &:nth-child(even){
+//             margin-left: 10px;
+//           }
+//           padding: 2px 0;
+//           margin: 3px 0;
+//           .title{
+//             margin-left: 5px;
+//           }
+//           .value{
+//             position: absolute;
+//             right: 10px;
+//             top: 5px;
+//           }
+//         }
+//       }
       
       
       
-    }
-    .alarm-box{
-      margin-top: 10px;
-    }
-  }
-  .box-title{
-    color: #fff;
-    margin-bottom: 8px;
-    padding-left: 10px;
-    position: relative;
-    font-size: 16px;
-    &::after{
-      content: '';
-      position: absolute;
-      display: block;
-      width: 4px;
-      height: 12px;
-      top: 7px;
-      left: 0px;
-      background: #45d3fd;
-      border-radius: 4px;
-    }
-  }
-
-}
+//     }
+//     .alarm-box{
+//       margin-top: 10px;
+//     }
+//   }
+//   .box-title{
+//     color: #fff;
+//     margin-bottom: 8px;
+//     padding-left: 10px;
+//     position: relative;
+//     font-size: 16px;
+//     &::after{
+//       content: '';
+//       position: absolute;
+//       display: block;
+//       width: 4px;
+//       height: 12px;
+//       top: 7px;
+//       left: 0px;
+//       background: #45d3fd;
+//       border-radius: 4px;
+//     }
+//   }
+
+// }
 
 :deep(.@{ventSpace}-tabs-tabpane-active) {
   overflow: auto;
 }
 
-.input-box {
-  display: flex;
-  align-items: center;
-  padding-left: 10px;
+// .input-box {
+//   display: flex;
+//   align-items: center;
+//   padding-left: 10px;
 
-  .input-title {
-    color: #73e8fe;
-    width: auto;
-  }
+//   .input-title {
+//     color: #73e8fe;
+//     width: auto;
+//   }
 
-  .@{ventSpace}-input-number {
-    border-color: #ffffff88 !important;
-  }
+//   .@{ventSpace}-input-number {
+//     border-color: #ffffff88 !important;
+//   }
+
+//   margin-right: 10px;
+// }
 
-  margin-right: 10px;
-}</style>
+</style>

+ 6 - 5
src/views/vent/monitorManager/comment/AlarmHistoryTable.vue

@@ -11,10 +11,7 @@
   import { useListPage } from '/@/hooks/system/useListPage';
   import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
   import { defHttp } from '/@/utils/http/axios';
-import { prefetchApps } from 'qiankun';
-
-  const list = (params) => defHttp.get({ url: '/safety/ventanalyAlarmLog/list', params });
-
+  
   const props = defineProps({
     columnsType: {
       type: String,
@@ -37,6 +34,10 @@ import { prefetchApps } from 'qiankun';
     scroll: {
       type: Object,
       default: () => { }
+    },
+    list: {
+      type: Function,
+      default: (params) => defHttp.get({ url: '/safety/ventanalyAlarmLog/list', params })
     }
   });
   const alarmHistory = ref()
@@ -71,7 +72,7 @@ import { prefetchApps } from 'qiankun';
   // 列表页面公共参数、方法
   const { tableContext } = useListPage({
     tableProps: {
-      api: list,
+      api: props.list,
       columns: columns,
       canResize: true,
       showTableSetting: false,

+ 12 - 13
src/views/vent/monitorManager/comment/HandlerHistoryTable.vue

@@ -49,7 +49,6 @@
     },
     (newVal) => {
       const column = getTableHeaderColumns(newVal)
-      debugger
       if (column && column.length < 1) {
         const arr = newVal.split('_')
         const columnKey = arr.reduce((prev, cur, index) => {
@@ -102,17 +101,17 @@
               valueFormat: 'YYYY-MM-DD HH:mm:ss',
             },
           },
-          {
-            label: '查询设备',
-            field: 'gdeviceid',
-            component: 'ApiSelect',
-            componentProps: {
-              api: props.deviceListApi,
-              resultField: 'records',
-              labelField: 'strname',
-              valueField: 'id',
-            },
-          },
+          // {
+          //   label: '查询设备',
+          //   field: 'gdeviceid',
+          //   component: 'ApiSelect',
+          //   componentProps: {
+          //     api: props.deviceListApi,
+          //     resultField: 'records',
+          //     labelField: 'strname',
+          //     valueField: 'id',
+          //   },
+          // },
         ],
         fieldMapToTime: [['createTime', ['createTime_begin', 'createTime_end'], '']],
       },
@@ -125,7 +124,7 @@
         pageSizeOptions: ['5', '10', '20'],
       },
       beforeFetch(params) {
-        params.gdevicetype = props.deviceType + '*';
+        params.devicetype = props.deviceType + '*';
         if (props.sysId) {
           params.sysId = props.sysId;
         }

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

@@ -50,6 +50,7 @@
     return props.columnsType;
   },
   (newVal) => {
+    debugger
     const column = getTableHeaderColumns(newVal + '_history')
     if (column && column.length < 1) {
       const arr = newVal.split('_')

+ 167 - 0
src/views/vent/monitorManager/comment/WorkFaceAlarmHistoryTable.vue

@@ -0,0 +1,167 @@
+<template>
+  <div class="alarm-history-table">
+    <BasicTable ref="alarmHistory" @register="registerTable" />
+  </div>
+</template>
+
+<script lang="ts" name="system-user" setup>
+  //ts语法
+  import { watch, ref, defineExpose } 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 props = defineProps({
+    columnsType: {
+      type: String,
+      required: true,
+    },
+    deviceType: {
+      type: String,
+      required: true,
+    },
+    deviceListApi: {
+      type: Function,
+      required: true,
+    },
+    designScope: {
+      type: String,
+    },
+    sysId: {
+      type: String,
+    },
+    scroll: {
+      type: Object,
+      default: () => { }
+    },
+    list: {
+      type: Function,
+      default: (params) => defHttp.get({ url: '/safety/ventanalyAlarmLog/list', params })
+    }
+  });
+  const alarmHistory = ref()
+  const columns = ref([])
+
+  watch(
+    () => {
+      return props.columnsType;
+    },
+    (newVal) => {
+      const column = getTableHeaderColumns(newVal + '_history')
+      if (column && column.length < 1) {
+        const arr = newVal.split('_')
+        const columnKey = arr.reduce((prev, cur, index) => {
+          if (index !== arr.length - 2) {
+            return prev + '_' + cur
+          } else {
+            return prev
+          }
+        })
+        columns.value = getTableHeaderColumns(arr[0] + '_history');
+      } else {
+        columns.value = column
+      }
+      if (alarmHistory.value) reload()
+    },
+    {
+      immediate: true
+    }
+  );
+
+  // 列表页面公共参数、方法
+  const { tableContext } = useListPage({
+    tableProps: {
+      api: props.list,
+      columns: columns,
+      canResize: true,
+      showTableSetting: false,
+      showActionColumn: false,
+      bordered: false,
+      size: 'small',
+      scroll: props.scroll,
+      formConfig: {
+        labelAlign: 'left',
+        showAdvancedButton: false,
+        // autoAdvancedCol: 2,
+        schemas: [
+          {
+            label: '时间范围',
+            field: 'createTime',
+            component: 'RangePicker',
+            componentProps: {
+              valueFormat: 'YYYY-MM-DD HH:mm:ss',
+            },
+          },
+          {
+            label: '查询设备',
+            field: 'deviceId',
+            component: 'ApiSelect',
+            componentProps: {
+              api: props.deviceListApi,
+              resultField: 'records',
+              labelField: 'strname',
+              valueField: 'id',
+            },
+          },
+        ],
+        fieldMapToTime: [['createTime', ['starttime', 'endtime'], '']],
+      },
+      fetchSetting: {
+        listField: 'records',
+      },
+      pagination: {
+        current: 1,
+        pageSize: 10,
+        pageSizeOptions: ['5', '10', '20'],
+      },
+      beforeFetch(params) {
+        params.devicetype = props.deviceType + '*';
+        if (props.sysId) {
+          params.sysId = props.sysId;
+        }
+      },
+    },
+  });
+  //注册table数据
+  const [registerTable, { reload, setLoading }] = tableContext;
+  defineExpose({ setLoading })
+</script>
+
+<style scoped lang="less">
+  @ventSpace: zxm;
+
+  :deep(.ventSpace-table-body) {
+    height: auto !important;
+  }
+  :deep(.zxm-picker){
+      height: 30px !important;
+  }
+  .alarm-history-table {
+    width: 100%;
+    :deep(.jeecg-basic-table-form-container) {
+      .@{ventSpace}-form {
+        padding: 0 !important;
+        border: none !important;
+        margin-bottom: 0 !important;
+        .@{ventSpace}-picker,
+        .@{ventSpace}-select-selector {
+          width: 100% !important;
+          background: #00000017;
+          border: 1px solid #b7b7b7;
+          input,
+          .@{ventSpace}-select-selection-item,
+          .@{ventSpace}-picker-suffix {
+            color: #fff;
+          }
+          .@{ventSpace}-select-selection-placeholder {
+            color: #ffffffaa;
+          }
+        }
+      }
+      .@{ventSpace}-table-title {
+        min-height: 0 !important;
+      }
+    }
+  }
+</style>

+ 175 - 0
src/views/vent/monitorManager/comment/WorkFaceHandlerHistoryTable.vue

@@ -0,0 +1,175 @@
+<template>
+  <div class="handler-history-table">
+    <BasicTable ref="handlerHistory" @register="registerTable" />
+  </div>
+</template>
+
+<script lang="ts" name="system-user" setup>
+  //ts语法
+  import { watch, ref, defineExpose } 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({
+    columnsType: {
+      type: String,
+      required: true,
+    },
+    deviceType: {
+      type: String,
+      required: true,
+    },
+    deviceListApi: {
+      type: Function,
+    },
+    designScope: {
+      type: String,
+    },
+    sysId: {
+      type: String,
+    },
+    scroll: {
+      type: Object,
+      default: () => {}
+    }
+  });
+  
+  const handlerHistory = ref()
+  const columns = ref([])
+
+  watch(
+    () => {
+      return props.columnsType;
+    },
+    (newVal) => {
+      const column = getTableHeaderColumns(newVal)
+      if (column && column.length < 1) {
+        const arr = newVal.split('_')
+        const columnKey = arr.reduce((prev, cur, index) => {
+          if (index !== arr.length - 2) {
+            return prev + '_' + cur
+          } else {
+            return prev
+          }
+        })
+        columns.value = getTableHeaderColumns(arr[0] + '_history');
+      } else {
+        columns.value = column
+      }
+      if (handlerHistory.value) reload()
+    },
+    {
+      immediate: true
+    }
+  );
+
+  // 列表页面公共参数、方法
+  const { tableContext } = useListPage({
+    tableProps: {
+      api: list,
+      columns: columns,
+      canResize: true,
+      showTableSetting: false,
+      showActionColumn: false,
+      bordered: false,
+      size: 'small',
+      scroll: props.scroll,
+      formConfig: {
+        labelAlign: 'left',
+        showAdvancedButton: false,
+        baseColProps: {
+          // offset: 0.5,
+          xs: 24,
+          sm: 24,
+          md: 24,
+          lg: 9,
+          xl: 7,
+          xxl: 4,
+        },
+        schemas: [
+          {
+            label: '时间范围',
+            field: 'createTime',
+            component: 'RangePicker',
+            componentProps: {
+              valueFormat: 'YYYY-MM-DD HH:mm:ss',
+            },
+          },
+          // {
+          //   label: '查询设备',
+          //   field: 'gdeviceid',
+          //   component: 'ApiSelect',
+          //   componentProps: {
+          //     api: props.deviceListApi,
+          //     resultField: 'records',
+          //     labelField: 'strname',
+          //     valueField: 'id',
+          //   },
+          // },
+        ],
+        fieldMapToTime: [['createTime', ['createTime_begin', 'createTime_end'], '']],
+      },
+      fetchSetting: {
+        listField: 'records',
+      },
+      pagination: {
+        current: 1,
+        pageSize: 10,
+        pageSizeOptions: ['5', '10', '20'],
+      },
+      beforeFetch(params) {
+        params.devicetype = props.deviceType + '*';
+        if (props.sysId) {
+          params.sysId = props.sysId;
+        }
+      },
+    },
+  });
+  //注册table数据
+  const [registerTable, { reload, setLoading }] = tableContext;
+  defineExpose({ setLoading })
+</script>
+
+<style scoped lang="less">
+  @ventSpace: zxm;
+
+  // :deep(.@{ventSpace}-table-body) {
+  //   height: auto !important;
+  // }
+  :deep(.zxm-picker){
+      height: 30px !important;
+  }
+  .handler-history-table {
+    width: 100%;
+    :deep(.jeecg-basic-table-form-container) {
+      .@{ventSpace}-form {
+        padding: 0 !important;
+        border: none !important;
+        margin-bottom: 0 !important;
+        .@{ventSpace}-picker,
+        .@{ventSpace}-select-selector {
+          width: 100% !important;
+          height: 100%;
+          background: #00000017;
+          border: 1px solid #b7b7b7;
+          input,
+          .@{ventSpace}-select-selection-item,
+          .@{ventSpace}-picker-suffix {
+            color: #fff;
+          }
+          .@{ventSpace}-select-selection-placeholder {
+            color: #ffffffaa;
+          }
+        }
+      }
+      .@{ventSpace}-table-title {
+        min-height: 0 !important;
+      }
+    }
+  }
+</style>

+ 649 - 0
src/views/vent/monitorManager/comment/less/workFace.less

@@ -0,0 +1,649 @@
+
+
+.monitor-container {
+  width: 100%;
+  height: 100%;
+  margin-top: 40px;
+  display: flex;
+  justify-content: space-between;
+  position: relative;
+
+  .lr {
+    width: 380px;
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+    margin-top: 10px;
+    pointer-events: auto;
+
+  }
+
+  .right-box {
+    width: 340px;
+    .disaster-btn {
+      padding: 4px 10px !important;
+      margin-right: 8px;
+    }
+  }
+
+  .left-box {
+    margin-top: 30px;
+  }
+
+  .warning-monitor {  
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+
+    .warning-item {
+      display: flex;
+      flex-direction: column;
+      justify-content: center;
+      align-items: center;
+    }
+
+    .state-box {
+      width: 79px;
+      height: 47px;
+      background: url('/@/assets/images/vent/param-bg.png');
+      display: flex;
+      justify-content: center;
+      align-items: center;
+
+      .title {
+        text-align: center;
+        color: #73e8fe;
+      }
+
+      span {
+        display: inline-block;
+      }
+
+      .value {
+        width: 20px;
+      }
+    }
+  }
+
+  .vent-param {
+    width: 100%;
+    margin-top: 10px;
+
+    .light-group {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      position: relative;
+
+      .param-item {
+        width: 120px;
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        align-items: center;
+        position: reactive;
+
+        .icon {
+          display: block;
+          position: absolute;
+          top: -5px;
+        }
+
+        .param {
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+          align-items: center;
+
+          .param-icon {
+            width: 79px;
+            height: 48px;
+            background: url('/@/assets/images/vent/workFace-param-bg.png');
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            align-items: center;
+            position: relative;
+            top: -20px;
+            margin-top: 10px;
+
+            .param-title {
+              position: relative;
+              top: -4px;
+            }
+
+            .param-unit {
+              position: relative;
+              top: -2px;
+              font-size: 12px;
+            }
+          }
+
+          .param-val-box {
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            align-items: center;
+            position: relative;
+            top: -20px;
+
+            .param-val-icon {
+              width: 2px;
+              height: 15px;
+              background: #00d8ff;
+              position: relative;
+
+              &::after {
+                content: '';
+                display: block;
+                position: absolute;
+                width: 6px;
+                height: 6px;
+                border-radius: 3px;
+                background: #00d8ff;
+                bottom: -2px;
+                left: -2px;
+              }
+
+            }
+
+            .param-val {
+              position: relative;
+              font-family: 'douyuFont';
+              // color: #20dbfd;
+              text-shadow: 0 0 25px #00d8ff;
+              font-size: 13px;
+              border: 1px solid #40B7F3;
+              padding: 5px 8px 2px 8px;
+              top: 2px;
+
+              &::after {
+                width: calc(100% - 4px);
+                height: calc(100% - 4px);
+                content: '';
+                position: absolute;
+                top: 2px;
+                left: 2px;
+                display: block;
+                border: 1px solid #006EA6;
+              }
+            }
+          }
+
+        }
+      }
+    }
+  }
+
+  .data-group {
+    display: flex;
+    flex-wrap: wrap;
+    justify-content: space-between;
+    padding-bottom: 8px;
+
+    .data-item {
+      width: calc(50% - 10px);
+      display: flex;
+      justify-content: space-between;
+      line-height: 24px;
+      background-image: linear-gradient(to right, #39A3FF00, #39A3FF10, #39A3FF02);
+      margin: 4px 0;
+    }
+
+    .value {
+      color: #00eefffe;
+    }
+
+    .data-item1 {
+      width: 100%;
+      line-height: 24px;
+      background-image: linear-gradient(to right, #39A3FF00, #39A3FF10, #39A3FF02);
+      margin: 4px 0;
+    }
+  }
+
+  .input-box {
+    display: flex;
+    flex-direction: column;
+    padding: 0 5px;
+  }
+  .input-item {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 2px 8px;
+    margin: 4px 0;
+    background-image: linear-gradient(to right, #39deff15, #3977e500);
+
+    .title {
+      width: 200px;
+    }
+
+    .title-auto {
+      width: auto;
+    }
+
+    .input-value {
+      width: 80px;
+      height: 28px;
+      line-height: 28px !important;
+      background: transparent !important;
+      border-color: #228DA2 !important;
+      color: #fff !important;
+    }
+
+    .value {
+      width: 80px;
+      color: #00d8ff;
+      padding-right: 20px;
+    }
+
+    .unit {
+      width: 80px;
+    }
+  }
+
+  .warning-state-detail {
+    position: relative;
+    padding-left: 10px;
+    font-size: 13px;
+    margin-bottom: 15px;
+    margin-top: 5px;
+    margin-left: 8px;
+
+    &::before {
+      content: '';
+      position: absolute;
+      width: 6px;
+      height: 6px;
+      border: 1px solid #1bf5fd;
+      background: #00d8ff;
+      border-radius: 3px;
+      left: -1px;
+      top: 8px;
+    }
+
+    .state-color {
+      color: #4afffdbf;
+    }
+  }
+
+  .temperature-group {
+    width: 100%;
+    margin-top: 20px;
+
+    .light-group {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      position: relative;
+
+      .light-bg {
+        width: 331px;
+        height: 42px;
+        background: url('/@/assets/images/vent/plane-bg.png') no-repeat;
+        background-size: contain;
+        position: absolute;
+        z-index: -1;
+        top: 44px;
+        opacity: 0.6;
+      }
+
+      .light-item {
+        width: 120px;
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        align-items: center;
+        position: reactive;
+
+        .icon {
+          display: block;
+          position: absolute;
+          top: -5px;
+        }
+
+        .light {
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+          align-items: center;
+
+          .light-icon {
+            width: 90px;
+            height: 58px;
+            background: url('/@/assets/images/vent/ligth-q.png');
+            opacity: 0.8;
+          }
+
+          .light-title {
+            position: relative;
+            top: -15px;
+          }
+
+          .light-val-box {
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            align-items: center;
+            position: relative;
+            top: -10px;
+
+            .light-val-icon {
+              width: 2px;
+              height: 18px;
+              background: #00d8ff;
+              position: relative;
+
+              &::after {
+                content: '';
+                display: block;
+                position: absolute;
+                width: 6px;
+                height: 6px;
+                border-radius: 3px;
+                background: #00d8ff;
+                bottom: -2px;
+                left: -2px;
+              }
+
+            }
+
+            .light-val {
+              position: relative;
+              font-family: 'douyuFont';
+              // color: #20dbfd;
+              text-shadow: 0 0 25px #00d8ff;
+              font-size: 13px;
+              border: 1px solid #40B7F3;
+              padding: 5px 8px 2px 8px;
+              top: 2px;
+
+              &::after {
+                width: calc(100% - 4px);
+                height: calc(100% - 4px);
+                content: '';
+                position: absolute;
+                top: 2px;
+                left: 2px;
+                display: block;
+                border: 1px solid #006EA6;
+              }
+            }
+          }
+
+        }
+      }
+    }
+  }
+
+  .state-item {
+    display: flex;
+    flex-direction: row;
+    padding: 4px;
+
+    .item-col {
+      width: calc(50% - 5px);
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      padding-right: 4px;
+      background-image: linear-gradient(to right, #39f5ff00, #39f5ff08);
+
+      &:first-child {
+        margin-right: 10px;
+      }
+
+      .state-title {
+        color: #ffffffcc;
+        flex: 9;
+        font-size: 14px;
+      }
+
+      .state-val {
+        flex: 1;
+        color: #00eefffe;
+        margin-right: 5px;
+        text-align: right;
+        font-size: 14px;
+      }
+    }
+  }
+
+  .co-param {
+    width: 100%;
+    margin-top: 20px;
+
+    .light-group {
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      position: relative;
+
+      .param-item {
+        width: 120px;
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        align-items: center;
+        position: reactive;
+
+        .icon {
+          display: block;
+          position: absolute;
+          top: -5px;
+        }
+
+        .param {
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+          align-items: center;
+
+          .param-icon {
+            width: 79px;
+            height: 48px;
+            background: url('/@/assets/images/vent/workFace-param-bg.png');
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            align-items: center;
+            position: relative;
+            top: -20px;
+            margin-top: 10px;
+
+            .icon {
+              position: relative;
+              top: -3px;
+            }
+
+            .param-unit {
+              position: relative;
+              top: -3px;
+              font-size: 13px;
+            }
+          }
+
+          .param-val-box {
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            align-items: center;
+            position: relative;
+            top: -20px;
+
+            .param-val-icon {
+              width: 2px;
+              height: 18px;
+              background: #00d8ff;
+              position: relative;
+
+              &::after {
+                content: '';
+                display: block;
+                position: absolute;
+                width: 6px;
+                height: 6px;
+                border-radius: 3px;
+                background: #00d8ff;
+                bottom: -2px;
+                left: -2px;
+              }
+
+            }
+
+            .param-val {
+              position: relative;
+              font-family: 'douyuFont';
+              // color: #20dbfd;
+              text-shadow: 0 0 25px #00d8ff;
+              font-size: 13px;
+              border: 1px solid #40B7F3;
+              padding: 5px 8px 2px 8px;
+              top: 2px;
+
+              &::after {
+                width: calc(100% - 4px);
+                height: calc(100% - 4px);
+                content: '';
+                position: absolute;
+                top: 2px;
+                left: 2px;
+                display: block;
+                border: 1px solid #006EA6;
+              }
+            }
+          }
+
+        }
+      }
+    }
+  }
+
+  .btn {
+    padding: 2px 12px;
+    position: relative;
+    border-radius: 2px;
+    color: #fff;
+    cursor: pointer;
+
+    &::before {
+      position: absolute;
+      display: block;
+      content: '';
+      width: calc(100% - 4px);
+      height: calc(100% - 4px);
+      top: 2px;
+      left: 2px;
+      border-radius: 2px;
+      z-index: -1;
+    }
+  }
+
+  .btn1 {
+    border: 1px solid #5cfaff;
+
+    &::before {
+      background-image: linear-gradient(#2effee92, #0cb1d592);
+    }
+
+    &:hover {
+      border: 1px solid #5cfaffaa;
+
+      &::before {
+        background-image: linear-gradient(#2effee72, #0cb1d572);
+      }
+    }
+  }
+
+  .btn2 {
+    border: 1px solid #e91927;
+    margin-left: 10px;
+
+    &::before {
+      background-image: linear-gradient(#b02533, #a31f2e);
+    }
+
+    &:hover {
+      &::before {
+        background-image: linear-gradient(#bd2e3ccc, #a31f2ecc);
+      }
+    }
+  }
+}
+
+.parameter-title {
+  position: relative;
+  width: 100%;
+  height: 16px;
+  margin-top: 10px;
+  margin-bottom: 5px;
+  display: flex;
+  align-items: center;
+  top: -2px;
+  .icon,
+  span {
+    position: absolute;
+  }
+}
+
+.group-parameter-title {
+  background-image: linear-gradient(to right, #39a3ff50, #39a3ff00);
+  .icon {
+    left: 0px;
+    top: -4px;
+  }
+  span {
+    left: 20px;
+    top: -8px;
+  }
+  &::before{
+    position: absolute;
+    content: '';
+    width: 100%;
+    height: 100%;
+    top: 4px;
+    background-image: linear-gradient(to right, #3df6ff40, #3df6ff00);
+  }
+}
+
+.detail {
+  align-self: flex-end;
+  color: #66e8fc;
+  cursor: pointer;
+  &:hover {
+    color: #1bf5fddd;
+  }
+}
+
+.a-detail{
+  font-size: 12px;
+  padding-left: 5px;
+  cursor: pointer;
+}
+
+:deep(.@{ventSpace}-tabs-tabpane-active) {
+  overflow: 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;
+    }
+  }
+
+  .@{ventSpace}-select-arrow {
+    color: #fff !important;
+  }
+}
+
+:deep(.zxm-select-dropdown) {
+  background: transparent !important;
+}

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


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


+ 1109 - 0
src/views/vent/monitorManager/deviceMonitor/components/device/index.vue

@@ -0,0 +1,1109 @@
+<template>
+  <div class="scene-box">
+    <div class="select-node" :class="{ 'node-select-show': !treeShow, 'node-select-hide': treeShow, }"
+      @click="showTree('treeShow', true)">
+      <SvgIcon class="is-expansion-icon put-away-icon" size="38" name="expansion" />
+      <span class="title">{{ treeNodeTitle }}</span>
+    </div>
+    <div class="device-select" :class="{ 'device-select-show': treeShow, 'device-select-hide': !treeShow, }">
+      <SvgIcon class="is-expansion-icon expansion-icon" size="28" name="put-away" @click="showTree('treeShow', false)" />
+      <div class="device-select-box">
+        <a-tree :show-line="true" :tree-data="treeData" v-model:selectedKeys="selectedKeys"
+          :autoExpandParent ="true"
+          v-model:expandedKeys = "expandedKeys" @select="onSelect">
+        </a-tree>
+      </div>
+    </div>
+    <div class="location-icon"
+      :class="{ 'location-btn-show': !locationSettingShow, 'location-btn-hide': locationSettingShow, }"
+      @click="showTree('location', true)">
+      <SvgIcon size="18" name="put-away" />
+      <span class="location-text">定位图标显示</span>
+    </div>
+    <div class="location-select"
+      :class="{ 'location-select-show': locationSettingShow, 'location-select-hide': !locationSettingShow, }">
+      <div class="location-select-box">
+        <div class="location-top-title" @click="showTree('location', false)">
+          <SvgIcon class="is-expansion-icon location-expansion-icon" size="28" name="expansion" />
+          <div class="title">定位图标显示</div>
+        </div>
+        <div class="location-container">
+          <template v-for="location in locationList" :key="location.deviceType">
+            <div class="location-item">
+              <div class="item-title">{{ location.title }}&nbsp;:</div>
+              <div>
+                <a-radio-group v-model:value="location.Visible" :name="location.deviceType">
+                  <a-radio :value="1">是</a-radio>
+                  <a-radio :value="0">否</a-radio>
+                </a-radio-group>
+              </div>
+            </div>
+          </template>
+          <div class="location-bottom-btn">
+            <span @click="setLocation">提交</span>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div>
+      <div class="bottom-tabs-box" @mousedown="setDivHeight($event, 250, scroll)" id="monitorBox">
+        <div class="to-small" @click="toHome"></div>
+        <div class="device-button-group" v-if="deviceList.length > 0">
+          <div class="device-button" :class="{ 'device-active': deviceActive == device.deviceType }"
+            v-for="(device, index) in deviceList" :key="index" @click="monitorChange(index)">{{ device.deviceName }}</div>
+          <div class="enter-detail" @click="goDetail()">
+            <send-outlined />
+            {{ treeNodeTitle }}详情
+          </div>
+        </div>
+
+        <a-tabs class="tabs-box" v-model:activeKey="activeKey" @change="tabChange">
+          <a-tab-pane key="1" tab="实时监测">
+            <template v-if="deviceType == 'fan' && activeKey == '1' && isRefresh">
+              <GroupMonitorTable :dataSource="dataSource" :columnsType="`${deviceType}_monitor`" />
+            </template>
+            <template v-else-if="activeKey == '1' && isRefresh">
+              <MonitorTable ref="monitorTable" :columnsType="`${deviceType}_monitor`" :dataSource="dataSource"
+                design-scope="device_monitor" :isShowPagination="false" :isShowActionColumn="true" title="设备监测"
+                :scroll="scroll">
+                <template #action="{ record }">
+                  <TableAction :actions="[
+                    {
+                      label: '详情',
+                      onClick: goDetail.bind(null, record),
+                    },
+                    {
+                      label: '定位',
+                      onClick: goLocation.bind(null, record),
+                    },
+                  ]" />
+                </template>
+                <template #filterCell="{ column, record }">
+                  <template v-if="deviceType.startsWith('gate')">
+                    <template v-if="record.frontGateOpenCtrl">
+                      <a-tag
+                        v-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == 0 && record.frontGateClose == 0"
+                        color="red">正在打开</a-tag>
+                      <a-tag v-else-if="column.dataIndex === 'frontGateOpen'" color="processing">打开</a-tag>
+                    </template>
+                    <template v-else>
+                      <a-tag
+                        v-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == 0 && record.frontGateClose == 0"
+                        color="red">正在关闭</a-tag>
+                      <a-tag
+                        v-else-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == 0 && record.frontGateClose == 1"
+                        color="default">关闭</a-tag>
+                      <a-tag
+                        v-else-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == 1 && record.frontGateClose == 0"
+                        color="default">打开</a-tag>
+                    </template>
+                    <template v-if="record.rearGateOpenCtrl">
+                      <a-tag
+                        v-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == 0 && record.rearGateClose == 0"
+                        color="red">正在打开</a-tag>
+                      <a-tag v-else-if="column.dataIndex === 'rearGateOpen'" color="processing">打开</a-tag>
+                    </template>
+                    <template v-else>
+                      <a-tag
+                        v-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == 0 && record.rearGateClose == 0"
+                        color="red">正在关闭</a-tag>
+                      <a-tag
+                        v-else-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == 0 && record.rearGateClose == 1"
+                        color="default">关闭</a-tag>
+                      <a-tag
+                        v-else-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == 1 && record.rearGateClose == 0"
+                        color="default">打开</a-tag>
+                    </template>
+                  </template>
+                  <template v-if="deviceType.startsWith('windrect')">
+                    <a-tag v-if="column.dataIndex === 'sign'"
+                      :color="record.sign == 0 ? '#95CF65' : record.sign == 1 ? '#4590EA' : '#9876AA'"> {{
+                        record.sign == 0 ? '高位' : record.sign == 1 ? '中位' : '低位'
+                      }}</a-tag>
+                    <template v-if="record && column && column.dataIndex === 'isRun' && record.isRun">
+                      <a-tag v-if="record.isRun == -2 || record.isRun == -1"
+                        :color="record.isRun == -2 ? '#95CF65' : '#ED5700'">{{
+                          record.isRun == -2 ? '空闲' : '等待'
+                        }}</a-tag>
+                      <a-tag v-else-if="record.isRun == 100" color="#4693FF">完成</a-tag>
+                      <Progress v-else :percent="Number(record.isRun)" size="small" status="active" />
+                    </template>
+                  </template>
+                  <a-tag v-if="column.dataIndex === 'warnFlag'"
+                    :color="record.warnFlag == 0 ? 'green' : record.warnFlag == 1 ? '#FF5812' : 'gray'"> {{
+                      record.warnFlag == 0 ? '正常' : record.warnFlag == 1 ? '报警' : record.warnFlag == 2 ? '断开' : '未监测'
+                    }}</a-tag>
+                  <a-tag v-if="column.dataIndex === 'netStatus'" :color="record.netStatus == 0 ? 'default' : 'green'">{{
+                    record.netStatus == 0 ? '断开' : '连接'
+                  }}</a-tag>
+                </template>
+              </MonitorTable>
+            </template>
+          </a-tab-pane>
+          <a-tab-pane key="2" tab="历史数据">
+            <div class="tab-item">
+              <HistoryTable ref="historyTable" v-if="activeKey == '2' && isRefresh" :sysId="systemID"
+                :columns-type="`${deviceType}`" :device-type="deviceType"
+                :device-list-api="getDeviceList.bind(null, { strtype: deviceType, sysId: systemID })"
+                designScope="device-history" :scroll="scroll" />
+            </div>
+          </a-tab-pane>
+          <a-tab-pane key="3" tab="报警历史">
+            <div class="tab-item">
+              <AlarmHistoryTable ref="alarmHistoryTable" v-if="activeKey == '3' && isRefresh" :sysId="systemID"
+                columns-type="alarm" :device-type="deviceType"
+                :device-list-api="getDeviceList.bind(null, { strtype: deviceType, sysId: systemID })" :scroll="scroll"
+                designScope="alarm-history" />
+            </div>
+          </a-tab-pane>
+          <a-tab-pane key="4" tab="操作历史">
+            <div class="tab-item">
+              <HandlerHistoryTable ref="handlerHistoryTable" v-if="activeKey == '4' && isRefresh" :sysId="systemID"
+                columns-type="operatorhistory" :device-type="deviceType"
+                :device-list-api="getDeviceList.bind(null, { strtype: deviceType, sysId: systemID })" :scroll="scroll"
+                designScope="operator-history" />
+            </div>
+          </a-tab-pane>
+        </a-tabs>
+
+      </div>
+    </div>
+    <component v-if="modalVisible" :is="currentModal" v-model:visible="modalVisible" :dataSource="dataSource"
+      :activeID="activeID" />
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted, onUnmounted, ComponentOptions, shallowRef, nextTick, watch, reactive, defineProps } from 'vue'
+import { SendOutlined } from '@ant-design/icons-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 { TreeProps, message, Progress } from 'ant-design-vue';
+import { TableAction } from '/@/components/Table';
+import FiberModal from './modal/fiber.modal.vue';
+import BundleModal from './modal/bundle.modal.vue'
+import DustModal from './modal/dust.modal.vue'
+import { SvgIcon } from '/@/components/Icon';
+import { getActions } from '/@/qiankun/state';
+import { useRouter } from 'vue-router';
+import { setDivHeight } from '/@/utils/event';
+
+
+type DeviceType = { deviceType: string, deviceName: string, datalist: any[] };
+
+const props = defineProps({
+  pageData: {
+    type: Object,
+    default: () => {}
+  }
+})
+
+const router = useRouter()
+
+const actions = getActions();
+// actions.setGlobalState({ pageObj: { pageType: 'home' } });
+
+const monitorTable = ref()
+const historyTable = ref()
+const alarmHistoryTable = ref()
+const handlerHistoryTable = ref()
+
+// const routerParam = ref('home') // 默认进来时首页
+
+// 模态框
+const currentModal = shallowRef<Nullable<ComponentOptions>>(null); //模态框
+const modalVisible = ref<Boolean>(false); // 模态框是否可见
+
+// const drawerHeight = ref(240) // 监测框最小高度
+const treeShow = ref(true) //是否显示树形菜单
+const locationSettingShow = ref(false) //是否显示树形菜单
+const treeNodeTitle = ref('') // 选中的树形标题
+
+const locationList = ref([]) //巷道定位图标显示列表
+const deviceList = ref<DeviceType[]>([]) //关联设备列表
+const deviceActive = ref('')
+const activeKey = ref('1'); // tab key
+const dataSource = shallowRef([]) // 实时监测数据
+const activeID = ref('') // 打开详情modal时监测的设备id
+const deviceType = ref('') // 监测设备类型
+const systemType = ref('')
+const systemID = ref('') // 系统监测时,系统id
+const selectedKeys = ref<string[]>([]);
+const expandedKeys = ref<string[]>(['0-0-0-1']);
+const isRefresh = ref(true)
+const scroll = reactive({
+  y: 240
+})
+const treeData = ref<TreeProps['treeData']>([]);
+
+//树形菜单选择事件
+const onSelect: TreeProps['onSelect'] = (keys, e) => {
+  deviceType.value = ''
+  systemID.value = ''
+  deviceList.value = []
+  if (e.node.parent && (e.node.parent.node.type.toString()).startsWith('sys')) {
+    systemType.value = e.node.parent.node.type
+    deviceType.value = e.node.parent.node.type
+    systemID.value = e.node.type
+    // 传递工作面id信息,用于定位
+    actions.setGlobalState({ locationObj: { pageType: deviceType.value, deviceid: systemID.value }, pageObj: null });
+  } else {
+    systemType.value = e.node.type
+    deviceType.value = e.node.type
+  }
+  selectedKeys.values = keys
+  treeNodeTitle.value = e.node.title
+  if (timer) clearTimeout(timer)
+  timer = undefined
+  if (monitorTable.value) monitorTable.value.setLoading(true)
+  nextTick(() => {
+    setTimeout(() => {
+      timer = null
+      getMonitor()
+    }, 0)
+  })
+
+};
+
+function tabChange(activeKeyVal) {
+  activeKey.value = activeKeyVal;
+};
+
+function showTree(flag, value) {
+  if (flag == 'treeShow') treeShow.value = value
+  if (flag == 'location') locationSettingShow.value = value
+}
+
+async function getDeviceType() {
+  if(treeData.value?.length > 0) return
+  const result = await getDeviceTypeList({})
+  if (result.length > 0) {
+    const dataSource = <TreeProps['treeData']>[]
+    let key = '0'
+    const getData = (resultList, dataSourceList, keyVal) => {
+      resultList.forEach((item, index) => {
+        if (item.children && item.children.length > 0) {
+          const children = getData(item.children, [], `${keyVal}-${index}`)
+          dataSourceList.push({
+            children: children,
+            title: item.itemText,
+            key: `${keyVal}-${index}`,
+            type: item.itemValue,
+            parentKey: `${keyVal}`
+          });
+
+        } else {
+          dataSourceList.push({
+            children: [],
+            title: item.itemText,
+            key: `${keyVal}-${index}`,
+            type: item.itemValue,
+            parentKey: `${keyVal}`
+          });
+        }
+      });
+      return dataSourceList
+    }
+    treeData.value = getData(result, dataSource, key)
+  }
+}
+
+// https获取监测数据
+let timer: null | NodeJS.Timeout = undefined;
+function getMonitor() {
+  if (deviceType.value) {
+    if (timer) timer = null
+    if (Object.prototype.toString.call(timer) === '[object Null]') {
+      timer = setTimeout(async () => {
+        await getDataSource()
+        if (timer) {
+          getMonitor();
+        }
+      }, 1000);
+    }
+  }
+};
+
+async function getDataSource() {
+  if (deviceType.value && deviceType.value.startsWith('sys') && systemID.value) {
+    const res = await list({ devicetype: 'sys', systemID: systemID.value });
+    const result = res.msgTxt;
+    const deviceArr = <DeviceType[]>[]
+    result.forEach(item => {
+      const data = item['datalist'].filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      })
+      if (item.type != 'sys') {
+        deviceArr.unshift({ deviceType: item.type, deviceName: item['typeName'] ? item['typeName'] : item['datalist'][0]['typeName'], datalist: data })
+      }
+    })
+
+    deviceList.value = deviceArr
+    if (deviceArr.length > 0) {
+      if (deviceArr[1]) {
+        deviceActive.value = deviceArr[1].deviceType
+        monitorChange(1)
+      } else {
+        deviceActive.value = deviceArr[0].deviceType
+        monitorChange(0)
+      }
+    }
+  } else {
+    const res = await list({ devicetype: deviceType.value, pagetype: 'normal' })
+    if (res.msgTxt[0]) {
+      dataSource.value = res.msgTxt[0].datalist || [];
+      dataSource.value.filter((data: any) => {
+        const readData = data.readData;
+        return Object.assign(data, readData);
+      });
+    }
+  }
+}
+
+function goLocation(record) {
+  actions.setGlobalState({ locationId: record.deviceID, locationObj: null, pageObj: null });
+}
+
+function goDetail(record?) {
+
+  if (record) {
+    if (deviceType.value.startsWith('fiber')) {
+      activeID.value = record.deviceID
+      currentModal.value = FiberModal
+      modalVisible.value = true;
+    } else if (deviceType.value.startsWith('dusting')) { //bundletube
+      activeID.value = record.deviceID
+      currentModal.value = DustModal
+      modalVisible.value = true;
+    } else if (deviceType.value.startsWith('bundletube')) {
+      activeID.value = record.deviceID
+      currentModal.value = BundleModal
+      modalVisible.value = true;
+    } else if (deviceType.value.indexOf("gate") != -1) {
+      const newPage = router.resolve({ path: '/monitorChannel/monitor-gate' })
+      window.open(newPage.href, '_blank')
+    } else if (deviceType.value.indexOf("window") != -1) {
+      const newPage = router.resolve({ path: '/monitorChannel/monitor-window' })
+      window.open(newPage.href, '_blank')
+    } else if (deviceType.value.indexOf("windrect") != -1) {
+      const newPage = router.resolve({ path: '/monitorChannel/monitor-windrect' })
+      window.open(newPage.href, '_blank')
+    } else if (deviceType.value.indexOf("fanmain") != -1) {
+      const newPage = router.resolve({ path: '/monitorChannel/monitor-fan-main' })
+      window.open(newPage.href, '_blank')
+    } else if (deviceType.value.indexOf("fanlocal") != -1) {
+      const newPage = router.resolve({ path: '/monitorChannel/monitor-fan-local' })
+      window.open(newPage.href, '_blank')
+    } else if (deviceType.value.indexOf("nitrogen") != -1) {
+      const newPage = router.resolve({ path: '/compressor-home' })
+      window.open(newPage.href, '_blank')
+    } else if (deviceType.value.indexOf("pulping") != -1) {
+      const newPage = router.resolve({ path: '/grout-home' })
+      window.open(newPage.href, '_blank')
+    } else if (deviceType.value.indexOf("pressurefan") != -1) {
+      const newPage = router.resolve({ path: '/nitrogen/home' })
+      window.open(newPage.href, '_blank')
+    } else if (deviceType.value.indexOf("chamber") != -1) {
+      const newPage = router.resolve({ path: '/chamber-home' })
+      window.open(newPage.href, '_blank')
+    } else {
+      message.info('待开发。。。')
+    }
+  } else {
+    if (systemType.value.indexOf("sys_dongshi") != -1) {
+      const newPage = router.resolve({ path: '/chamber-home', query: { id: systemID.value } })
+      window.open(newPage.href, '_blank')
+    } else {
+      message.info('待开发。。。')
+    }
+  }
+
+}
+
+function toHome() {
+  deviceList.value = []
+  if (timer) clearTimeout(timer)
+  timer = undefined
+  deviceType.value = ''
+  actions.setGlobalState({ pageObj: { pageType: 'home' } });
+}
+
+async function findTreeDataValue(obj) {
+  const findDeviceType = (data: [], obj) => {
+    let type = ''
+    if (obj.deviceid) {
+      type = obj.deviceid
+    } else {
+      type = obj.deviceType
+    }
+    data.find((item: any) => {
+      if (item.children.length > 0) {
+        findDeviceType(item.children, obj)
+      }
+
+      if (item.type == type) {
+        deviceType.value = obj.deviceid ? 'sys' : item.type
+        if (obj.deviceid) systemID.value = obj.deviceid
+        selectedKeys.value = [item.key]
+        expandedKeys.value = [item.key]
+        treeNodeTitle.value = item.title
+        return true
+      }
+      return false
+    })
+  }
+  
+  findDeviceType(treeData.value, obj)
+  
+  if (timer === undefined) {
+    timer = null
+    await getDataSource()
+    getMonitor()
+  }
+}
+
+function monitorChange(index) {
+  dataSource.value = []
+  deviceActive.value = deviceType.value = deviceList.value[index].deviceType
+
+  if (activeKey.value == '1' && monitorTable.value) {
+    monitorTable.value.setLoading(true)
+    dataSource.value = deviceList.value[index].datalist
+  }
+  if (activeKey.value == '2' && historyTable.value) {
+    historyTable.value.setLoading(true)
+  }
+  if (activeKey.value == '3' && alarmHistoryTable.value) {
+    alarmHistoryTable.value.setLoading(true)
+  }
+  if (activeKey.value == '4' && handlerHistoryTable.value) {
+    handlerHistoryTable.value.setLoading(true)
+  }
+}
+/**
+ * 设置巷道设备定位图标的显示与隐藏
+ */
+function setLocation() {
+  let locationStr = ''
+  locationList.value.forEach((item: any) => {
+    if (item.Visible) {
+      locationStr = locationStr ? locationStr + ',' + item.value : item.value
+    }
+  })
+  actions.setGlobalState({ locationId: null, locationObj: null, pageObj: null, locationPlane: locationStr });
+  setTimeout(() => {
+    message.success('设置成功')
+  }, 600)
+}
+
+watch(() => scroll.y, () => {
+  isRefresh.value = false
+  nextTick(() => {
+    isRefresh.value = true
+  })
+})
+
+onMounted(async () => {
+  await getDeviceType()
+
+  const pageObj = props.pageData
+  if (pageObj.deviceid) {
+    findTreeDataValue({ deviceid: pageObj.deviceid })
+  } else {
+    findTreeDataValue({ deviceType: pageObj.pageType })
+  }
+  // 定位
+  const posShowData = pageObj.locationPlane
+  if (posShowData) {
+    locationList.value = posShowData
+  }
+})
+
+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;
+}
+
+.select-node {
+  position: fixed;
+  top: 60px;
+  left: 10px;
+  color: #fff;
+  display: flex;
+  justify-content: center;
+  font-size: 22px;
+
+  .title {
+    margin-left: 10px;
+  }
+}
+
+.expansion-icon {
+  background: url('/@/assets/images/vent/home/tree-icon-bg.png') no-repeat;
+  background-size: contain;
+  position: absolute;
+  left: 190px;
+  top: 25px;
+
+  &:hover {
+    background: url('/@/assets/images/vent/home/tree-icon-hover-bg.png') no-repeat;
+    background-size: contain;
+  }
+}
+
+.device-select {
+  width: 250px;
+  height: 500px;
+  background: url('/@/assets/images/vent/home/tree-bg.png') no-repeat;
+  position: fixed;
+  top: 60px;
+  left: 10px;
+  background-size: contain;
+  pointer-events: auto;
+  padding: 20px 10px 30px 10px;
+
+}
+
+.is-expansion-icon {
+  padding: 5px;
+  pointer-events: auto;
+  z-index: 999;
+}
+
+.device-select-show {
+  left: 10px;
+  animation-name: treeShow;
+  /* 持续时间 */
+  animation-duration: 1s;
+  transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
+
+}
+
+.device-select-hide {
+  left: -250px;
+  animation-name: treeHide;
+  /* 持续时间 */
+  animation-duration: 1s;
+  transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
+}
+
+.node-select-show {
+  width: 276px;
+  height: 44px;
+  background: url('/@/assets/images/vent/home/tree-expansion-bg.png') no-repeat;
+  left: 10px;
+  animation-name: treeShow;
+  /* 持续时间 */
+  animation-duration: 1s;
+  transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
+  display: flex;
+  align-items: center;
+  margin-left: 0;
+  justify-content: flex-start;
+  pointer-events: auto;
+
+  &:hover {
+    background: url('/@/assets/images/vent/home/tree-expansion-hover-bg.png') no-repeat;
+  }
+
+  .put-away-icon {
+    position: relative;
+    display: inline-block;
+    left: 4px;
+  }
+}
+
+.node-select-hide {
+  left: -400px;
+  animation-name: treeHide;
+  /* 持续时间 */
+  animation-duration: 1s;
+  transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
+}
+
+.device-select-box {
+  width: 208px;
+  height: 450px;
+  overflow-y: auto;
+  color: #fff;
+
+  :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: #00b1c855;
+    }
+
+    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;
+    height: 100px;
+  }
+
+  &::-webkit-scrollbar-thumb {
+    -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
+    background: #4288A444;
+  }
+}
+
+.location-icon {
+  width: 46px;
+  height: 178px;
+  position: absolute;
+  top: 60px;
+  // right: 0;
+  background: url('/@/assets/images/vent/home/location-bg.png') no-repeat;
+  background-size: contain;
+  writing-mode: vertical-lr;
+  line-height: 46px;
+  color: #fff;
+  padding-top: 10px;
+  pointer-events: auto;
+  cursor: pointer;
+
+  &:hover {
+    background: url('/@/assets/images/vent/home/location-hover-bg.png') no-repeat;
+  }
+
+  .location-text {
+    padding-top: 20px;
+    letter-spacing: 3px;
+    font-size: 16px;
+  }
+}
+
+.location-select {
+  position: fixed;
+  top: 60px;
+  // right: 240px;
+  pointer-events: auto;
+
+  .location-select-box {
+    width: 100%;
+    height: 100%;
+    position: relative;
+
+    &::before {
+      content: "";
+      position: absolute;
+      width: 230px;
+      height: 500px;
+      top: 0;
+      left: 0;
+      background: url('/@/assets/images/vent/home/tree-bg.png') no-repeat;
+      background-size: contain;
+      transform: rotateY(180deg);
+      z-index: -1;
+      // &:hover {
+      //   background: url('/@/assets/images/vent/home/tree-icon-hover-bg.png') no-repeat;
+      //   background-size: contain;
+      // }
+    }
+
+    .location-top-title {
+      color: #fff;
+      position: absolute;
+      width: 225px;
+      height: 68px;
+      background: url('/@/assets/images/vent/home/turn-location-top-bg.png') no-repeat;
+      background-size: contain;
+      top: 5px;
+      left: 5px;
+      display: flex;
+      flex-direction: row;
+      justify-content: space-between;
+      align-items: flex-end;
+
+      .title {
+        font-size: 18px;
+        position: relative;
+        top: -14px;
+        right: 15px;
+      }
+    }
+
+    .location-expansion-icon {
+      background: url('/@/assets/images/vent/home/tree-icon-cover-bg.png') no-repeat;
+      background-size: contain;
+      position: relative;
+      left: 10px;
+      top: -15px;
+      padding: 5px;
+
+      &:hover {
+        background: url('/@/assets/images/vent/home/tree-icon-cover-hover-bg.png') no-repeat;
+        background-size: contain;
+      }
+    }
+  }
+
+  .location-container {
+    width: 200px;
+    height: 390px;
+    position: absolute;
+    display: flex;
+    flex-direction: column;
+    top: 80px;
+    left: 18px;
+    overflow-y: auto;
+
+    .location-item {
+      color: #fff;
+      line-height: 30px;
+      display: flex;
+      justify-content: space-between;
+      background-image: linear-gradient(to left, #39f5ff05, #39f5ff10);
+      margin: 3px 0;
+
+      .item-title {
+        width: 80px;
+        text-align: right;
+        color: #87f1ff;
+      }
+    }
+
+    .location-bottom-btn {
+      width: 100%;
+      color: #fff;
+      display: flex;
+      justify-content: flex-end;
+      margin-top: 20px;
+
+      span {
+        display: inline-block;
+        width: 100%;
+        background: #00709955;
+        border-radius: 3px;
+        border: 1px solid rgba(174, 243, 255, 0.3);
+        text-align: center;
+        padding: 2px 0;
+        cursor: pointer;
+
+        &:hover {
+          background: #00557422;
+        }
+      }
+    }
+  }
+}
+
+.location-select-show {
+  right: 240px;
+  animation-name: locationShow;
+  /* 持续时间 */
+  animation-duration: 1s;
+  transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
+}
+
+.location-select-hide {
+  right: -2px;
+  animation-name: locationHide;
+  /* 持续时间 */
+  animation-duration: 1s;
+  transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
+}
+
+.location-btn-show {
+  right: -0px;
+  animation-name: locationBtnShow;
+  /* 持续时间 */
+  animation-duration: 1s;
+  transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
+}
+
+.location-btn-hide {
+  right: -240px;
+  animation-name: locationBtnHide;
+  /* 持续时间 */
+  animation-duration: 1s;
+  transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
+}
+
+.bottom-tabs-box {
+
+  position: relative;
+
+  .to-small {
+    width: 60px;
+    height: 60px;
+    background: url('/@/assets/images/vent/home/tosmall.png') no-repeat center;
+    background-size: auto;
+    position: absolute;
+    top: -62px;
+    right: 36px;
+    border-radius: 10px;
+    padding: 8px;
+    backdrop-filter: blur(10px);
+    background-color: rgba(45, 86, 137, 0.418);
+
+    &:hover {
+      background-color: rgba(79, 104, 134, 0.418);
+    }
+  }
+
+  .device-button-group {
+    position: absolute;
+    top: -27px;
+    left: 30px;
+    display: flex;
+    width: 100%;
+
+    .device-button {
+      height: 26px;
+      padding: 0 20px;
+      background: linear-gradient(45deg, #04e6fb55, #0c5cab55);
+      clip-path: polygon(10px 0,
+          0 50%,
+          10px 100%,
+          100% 100%,
+          calc(100% - 10px) 50%,
+          100% 0);
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      color: #FFF;
+      position: relative;
+      cursor: pointer;
+
+      &:nth-child(1) {
+        left: calc(-6px * 1);
+      }
+
+      &:nth-child(2) {
+        left: calc(-6px * 2);
+      }
+
+      &:nth-child(3) {
+        left: calc(-6px * 3);
+      }
+
+      &:nth-child(4) {
+        left: calc(-6px * 4);
+      }
+
+      &:nth-child(5) {
+        left: calc(-6px * 5);
+      }
+
+      &:nth-child(6) {
+        left: calc(-6px * 6);
+      }
+
+      &:nth-child(7) {
+        left: calc(-6px * 7);
+      }
+
+      &:nth-child(8) {
+        left: calc(-6px * 8);
+      }
+
+      &:nth-child(9) {
+        left: calc(-6px * 9);
+      }
+
+      &:nth-child(10) {
+        left: calc(-6px * 10);
+      }
+
+      &:nth-child(11) {
+        left: calc(-6px * 11);
+      }
+
+      &:nth-child(12) {
+        left: calc(-6px * 12);
+      }
+
+      &:nth-child(13) {
+        left: calc(-6px * 13);
+      }
+
+      &:nth-child(14) {
+        left: calc(-6px * 14);
+      }
+
+      &:nth-child(15) {
+        left: calc(-6px * 15);
+      }
+
+      &:first-child {
+        clip-path: polygon(0 0,
+            10px 50%,
+            0 100%,
+            100% 100%,
+            calc(100% - 10px) 50%,
+            100% 0);
+      }
+
+    }
+
+    .device-active {
+      background: linear-gradient(45deg, #04e6fb, #0c5cab);
+
+      &::before {
+        border-color: #0efcff;
+        box-shadow: 1px 1px 3px 1px #0efcff inset;
+      }
+    }
+  }
+
+  .enter-detail {
+    color: #fff;
+    cursor: pointer;
+    position: absolute;
+    right: 120px;
+    top: -6px;
+    padding: 5px;
+    border-radius: 5px;
+    margin-left: 8px;
+    margin-right: 8px;
+    width: auto;
+    height: 33px !important;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    color: #fff;
+    padding: 5px 15px 5px 15px;
+    cursor: pointer;
+
+    &:hover {
+      background: linear-gradient(#2cd1ff55, #1eb0ff55);
+    }
+
+    &::before {
+      width: calc(100% - 6px);
+      height: 27px;
+      content: '';
+      position: absolute;
+      top: 3px;
+      right: 0;
+      left: 3px;
+      bottom: 0;
+      z-index: -1;
+      border-radius: inherit;
+      /*important*/
+      background: linear-gradient(#1fa6cb, #127cb5);
+    }
+  }
+}
+
+@keyframes treeShow {
+  0% {
+    left: -400px;
+    opacity: 0;
+  }
+
+  100% {
+    left: 10px;
+    opacity: 1;
+  }
+}
+
+@keyframes treeHide {
+  0% {
+    left: 10px;
+    opacity: 1;
+  }
+
+  100% {
+    left: -400px;
+    opacity: 0;
+  }
+}
+
+@keyframes locationShow {
+  0% {
+    right: 0px;
+    opacity: 0;
+  }
+
+  100% {
+    right: 240px;
+    opacity: 1;
+  }
+}
+
+@keyframes locationHide {
+  0% {
+    right: 240px;
+    opacity: 1;
+  }
+
+  100% {
+    right: 0;
+    opacity: 0;
+  }
+}
+
+@keyframes locationBtnShow {
+  0% {
+    right: -240px;
+    opacity: 0;
+  }
+
+  100% {
+    right: -2px;
+    opacity: 1;
+  }
+}
+
+@keyframes locationBtnHide {
+  0% {
+    right: -2px;
+    opacity: 1;
+  }
+
+  100% {
+    right: -240px;
+    opacity: 0;
+  }
+}
+
+:deep(.@{ventSpace}-tabs-tabpane-active) {
+  // overflow: auto;
+  height: 100%;
+}
+
+:deep(.zxm-select-dropdown) {
+  left: 0 !important;
+}</style>

+ 0 - 0
src/views/vent/monitorManager/deviceMonitor/modal/bundle.modal.vue → src/views/vent/monitorManager/deviceMonitor/components/device/modal/bundle.modal.vue


+ 0 - 0
src/views/vent/monitorManager/deviceMonitor/modal/dust.modal.vue → src/views/vent/monitorManager/deviceMonitor/components/device/modal/dust.modal.vue


+ 0 - 0
src/views/vent/monitorManager/deviceMonitor/modal/fiber.modal.vue → src/views/vent/monitorManager/deviceMonitor/components/device/modal/fiber.modal.vue


+ 990 - 0
src/views/vent/monitorManager/deviceMonitor/components/network/index.vue

@@ -0,0 +1,990 @@
+<template>
+  <div class="zl-box">
+    <div class="zl-container-box">
+      <div class="top-box">
+        <transition
+          enter-active-class="animate__animated  animate__slideInLeft"
+          leave-active-class="animate__animated  animate__slideOutLeft"
+        >
+          <div class="left-box lr-box" v-show="show">
+            <div class="analysis-box">
+              <div class="item-top-title">通风网络分析</div>
+              <BorderBox1 class="border-bg" backgroundColor="#00bfff15" >
+                <div class="pie-group">
+                  <div class="item-pie">
+                    <div class="pie">
+                      <div class="qiu qiu1">
+                        <p>{{ pageData.totalEnterNum }}</p>
+                      </div>
+                    </div>
+                    <div class="pie-data">
+                      <span class="data-text">总进风量</span>
+                    </div>
+                  </div>
+                  <div class="item-pie">
+                    <div class="pie">
+                      <div class="qiu qiu2">
+                        <p>{{ pageData.totalToNum }}</p>
+                      </div>
+                    </div>
+                    <div class="pie-data">
+                      <span class="data-text">总回风量</span>
+                    </div>
+                  </div>
+                </div>
+                <div class="detail-data-group">
+                  <div class="container-item" v-for="(data, index) in analysisDetailDataList" :key="index">
+                    <div class="item-icon">
+                      <SvgIcon class="icon-style" size="18" :name="data.icon" />
+                    </div>
+                    <div class="item-name">{{ data.name }}</div>
+                    <div v-if="data.code !== 'level' && data.code !== 'resistance'" class="item-value">{{ pageData[data.code] }}
+                    </div>
+                    <div v-if="data.code == 'level'" class="item-value">
+                      <span class="signal-round signal-round-run"></span>
+                    </div>
+                    <div v-if="data.code == 'resistance'" class="item-value">{{ totalPa }}</div>
+                  </div>
+                </div>
+                <div class="feature-group">
+                  <div class="feature-item">
+                    <div class="pie">
+                      <Progress type="circle" :width="50" :stroke-color="{
+                        '0%': '#FC9C1D',
+                        '100%': '#1FF8FB',
+                      }" :percent="Number(rate1)"></Progress>
+                    </div>
+                    <div class="data">可靠度</div>
+                  </div>
+                  <div class="feature-item">
+                    <div class="pie">
+                      <Progress type="circle" :width="50" :stroke-color="{
+                        '0%': '#A02EFF',
+                        '100%': '#1FF8FB',
+                      }" :percent="Number(rate2)"></Progress>
+                    </div>
+                    <div class="data">风阻合理度</div>
+                  </div>
+                  <div class="feature-item">
+                    <div class="pie">
+                      <Progress type="circle" :width="50" :stroke-color="{
+                        '0%': '#108ee9',
+                        '100%': '#1FF8FB',
+                      }" :percent="Number(rate3)"></Progress>
+                    </div>
+                    <div class="data">有效风量率</div>
+                  </div>
+                </div>
+              </BorderBox1>
+            </div>
+
+          </div>
+        </transition>
+        <transition
+          enter-active-class="animate__animated  animate__slideInRight"
+          leave-active-class="animate__animated  animate__slideOutRight"
+        >
+        <div class="right-box lr-box" v-show="show">
+          <div class="sensor-box">
+            <div class="item-top-title">传感器实时数据</div>
+            <BorderBox1 class="table-box border-bg" backgroundColor="#00bfff15">
+              <div class="table-container">
+                <a-table :columns="sensorColumns" :data-source="pageData.sensorDataList" :pagination="false" size="small" />
+              </div>
+            </BorderBox1>
+          </div>
+          <div class="warning-box">
+            <div class="item-top-title">预警报警信息</div>
+            <BorderBox1 class="table-box border-bg" backgroundColor="#00bfff15">
+              <div class="table-container">
+                <a-table :columns="warningColumns" :data-source="pageData.warningDataList" :pagination="false" size="small">
+                  <template #bodyCell="{ column, record }">
+                    <div v-if="column.dataIndex == 'level'">
+                      <span class="signal-round"
+                        :class="{ 'signal-round-red': record['level'] == 1, 'signal-round-orange': record['level'] == 2, 'signal-round-yellow': record['level'] == 3 }"></span>
+                    </div>
+                  </template>
+                </a-table>
+              </div>
+            </BorderBox1>
+          </div>
+        </div>
+      </transition>
+      </div>
+      <transition
+            enter-active-class="animate__animated  animate__slideInUp"
+            leave-active-class="animate__animated  animate__slideOutDown"
+          >
+        <div class="bottom-box" v-show="show">
+          <div class="to-small" @click="toHome"></div>
+          <div class="bottom-left bottom-lr-box">
+            <BorderBox11 class="border-bg" title="实时网络解算" :color="['#00FFFF']" backgroundColor="#00bfff15">
+              <div class="network-top">
+                <div class="network-top-left">
+                  <div>
+                    准确率:
+                    <span class="accuracy-rate">95%</span>
+                  </div>
+                  <div>
+                    迭代误差:
+                    <span class="error-rate">0.0941%</span>
+                  </div>
+                </div>
+                <div class="network-top-right">
+                  本次解算时间:
+                  <span class="time">{{ pageData.currentTime }}</span>
+                </div>
+              </div>
+              <div class="table-container">
+                <a-table :columns="networkColumns" :data-source="pageData.networkDataList" :pagination="false" size="small" />
+              </div>
+            </BorderBox11>
+          </div>
+          <div class="bottom-right bottom-lr-box">
+            <BorderBox11 class="border-bg" title="最大阻力路线" backgroundColor="#00bfff15">
+              <div class="zl-top">
+                <div>
+                  <span class="btn active">1号回风斜井</span>
+                  <span class="btn">2号回风斜井</span>
+                </div>
+                <div>
+                  路线阻力
+                  <span class="data">{{ totalPa }}</span>
+                  Pa
+                </div>
+              </div>
+              <div class="zl-container">
+                <div class="zl-path-item position1">
+                  <div class="title">副平硐</div>
+                </div>
+                <div class="zl-path-item position2">
+                  <div class="title">5煤组盘区辅运巷</div>
+                </div>
+                <div class="zl-path-item position3">
+                  <div class="title">1521辅运顺槽</div>
+                </div>
+                <div class="zl-path-item position4">
+                  <div class="title">15212综采工作面</div>
+                </div>
+                <div class="zl-path-item position5">
+                  <div class="title">15211辅运顺槽</div>
+                </div>
+                <div class="zl-path-item position6">
+                  <div class="title">15212胶运顺槽</div>
+                </div>
+                <div class="zl-path-item position7">
+                  <div class="title">15212回风顺槽回风联巷</div>
+                </div>
+                <div class="zl-path-item position8">
+                  <div class="title">5煤组盘曲回风大巷</div>
+                </div>
+                <div class="zl-path-item position9">
+                  <div class="title">回风斜井联络巷</div>
+                </div>
+                <div class="zl-path-item position10">
+                  <div class="title">1盘曲回风斜井</div>
+                </div>
+              </div>
+            </BorderBox11>
+          </div>
+        </div>
+      </transition>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+import { ref, onMounted, onUnmounted, defineEmits, defineProps, watch, reactive } from 'vue';
+import { Icon as SvgIcon } from '/@/components/Icon';
+import { Progress } from 'ant-design-vue';
+import { BorderBox11, BorderBox1 } from '@kjgl77/datav-vue3';
+import { sensorColumns, networkColumns, warningColumns } from './network.data'
+import dayjs from 'dayjs'
+
+type SensorType = {
+  strinstallpos: string, 
+  va: string
+}
+type NetworkType = {
+  nTunID: string,
+  strName: string,
+  dV: string,
+  dQ: string,
+  dHTotal: string,
+  fcoff: string,
+  fArea: string,
+  lmd: string
+}
+const emit = defineEmits(['changePageType'])
+const props = defineProps({
+  pageResult: {
+    type: Object,
+    default: () => {}
+  }
+})
+
+const show = ref(false)
+
+let count = 0;
+
+const pageData = reactive({
+  currentTime: dayjs(new Date('2022-10-11 15:03:11').getTime() + count).format('YYYY-MM-DD HH:mm:ss'),
+  totalEnterNum: '23855',
+  totalToNum: '244436',
+  totallength: '2343544', // 总长
+  level: '21000',
+  hole: '11.27',
+  sensorDataList: <SensorType[]>[],
+  networkDataList: <NetworkType[]>[],
+  warningDataList: []
+})
+
+const totalPa = ref(1640 + '')
+const rate1 = ref(95 + '')
+const rate2 = ref(95 + '')
+const rate3 = ref(95 + '')
+
+
+const analysisDetailDataList = ref([
+  {
+    code: 'totallength',
+    name: '通风巷道规模(m)',
+    icon: 'path-icon1'
+  },
+  {
+    code: 'level',
+    name: '通风难易程度',
+    icon: 'path-icon2'
+  },
+  // {
+  //   code: 'resistance',
+  //   name: '总阻力',
+  //   value: totalPa.value,
+  //   icon: 'path-icon3'
+  // },
+  {
+    code: 'hole',
+    name: '等积孔(㎡)',
+    icon: 'path-icon4'
+  },
+])
+
+function toHome() {
+  show.value = false
+  setTimeout(() => {
+    emit('changePageType', 'model3D')
+  }, 1200)
+}
+
+function analyzePageResult(result){
+  pageData.currentTime = result['time'];
+  pageData.totalEnterNum = result['info'][0]['sysdata']['zongfengliang'] != null ? Number(result['info'][0]['sysdata']['zongfengliang']).toFixed(2) : '-';
+  pageData.totalToNum = result['info'][0]['sysdata']['zonghuifeng'] != null ? Number(result['info'][0]['sysdata']['zonghuifeng']).toFixed(2) : '-';
+  pageData.totallength = result['info'][0]['sysinfo']['totallength'] != null ? Number(result['info'][0]['sysinfo']['totallength']).toFixed(2) : '-';
+  const sensorDataList = <SensorType[]>[];
+  const networkDataList = <NetworkType[]>[]
+  if(result['monitors'] && result['monitors'].length > 0){
+   result['monitors'].forEach((item => {
+      item = {
+        strinstallpos: item.strinstallpos,
+        va: item['readData']['va'] != null ? Number(item['readData']['va']).toFixed(2) : '-',
+      }
+      sensorDataList.push(item)
+    }))
+  }
+  if (result['solutionresult'] && result['solutionresult'].length > 0) {
+    result['solutionresult'].forEach((item => {
+      item = {
+        nTunID: item['nTunID'],
+        strName: item['strName'],
+        dV: item['dV'] != null ? item['dV'].toFixed(2): '-', //风速 
+        dQ: item['dQ'] != null? item['dQ'].toFixed(2) : '-', //风量
+        dHTotal: item['dHTotal'] != null ? item['dHTotal'].toFixed(2) : '-', //阻力
+        fcoff: item['fcoff'] != null ? item['fcoff'].toFixed(2) : '-', //阻力系数
+        fArea: item['fArea'] != null ? item['fArea'].toFixed(2) : '-', //面积
+        lmd: Number(Math.random() * 0.2).toFixed(2),
+      }
+      networkDataList.push(item)
+    }))
+  }
+  pageData.sensorDataList = sensorDataList
+  pageData.warningDataList = result['warns']
+  pageData.networkDataList = networkDataList
+}
+
+watch(() => props.pageResult, (newData) => {
+  analyzePageResult(newData)
+}, {immediate: false})
+
+onMounted(() => {
+  show.value = true
+});
+
+onUnmounted(() => {
+  
+});
+</script>
+<style scoped lang="less">
+@ventSpace: zxm;
+
+.vent-home-header {
+  width: 100%;
+  height: 100px;
+  position: fixed;
+  top: 0;
+  background: url('/@/assets/images/vent/new-home/header-bg.png') no-repeat;
+  background-size: contain;
+  display: flex;
+  justify-content: center;
+  z-index: 99;
+
+  .header-icon {
+    margin-top: 45px;
+  }
+
+  .header-text {
+    position: fixed;
+    top: 18px;
+    color: #fff;
+    font-size: 26px;
+  }
+}
+
+.zl-box {
+  width: 100%;
+  height: calc(100%);
+  top: 50px;
+  position: relative;
+  overflow: hidden;
+  color: #fff;
+  background-position: center;
+  background-size: cover;
+
+  .modal-box {
+    position: relative;
+    width: 100%;
+    height: 100%;
+    top: 0;
+    left: 0;
+  }
+}
+
+.zl-container-box {
+  width: 100%;
+  height: 100%;
+  top: 10px;
+  position: absolute;
+  z-index: 99;
+  pointer-events: none;
+
+  .top-box {
+    display: flex;
+    justify-content: space-between;
+    height: calc(70% - 20px);
+
+    .lr-box {
+      width: 374px;
+      margin-top: 10px;
+    }
+
+    .left-box {
+      .analysis-box {
+        position: relative;
+
+        .pie-group {
+          display: flex;
+          flex-direction: row;
+          padding-top: 30px;
+
+          .item-pie {
+            flex: 1;
+            padding: 5px;
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            align-items: center;
+
+            .pie {
+              width: 140px;
+              height: 80px;
+              background: url('/@/assets/images/vent/path/di.png') no-repeat;
+              background-size: contain;
+              display: flex;
+              justify-content: center;
+
+              .qiu1 {
+                background: url('/@/assets/images/vent/path/cicle01.png') no-repeat center;
+              }
+
+              .qiu2 {
+                background: url('/@/assets/images/vent/path/cicle04.png') no-repeat center;
+              }
+
+              .qiu {
+                position: relative;
+                width: 60px;
+                height: 60px;
+                background-size: 100%;
+                display: flex;
+                justify-content: center;
+                padding-top: 18px;
+
+                &::before {
+                  content: '';
+                  display: block;
+                  width: 60px;
+                  height: 60px;
+                  position: absolute;
+                  left: 50%;
+                  top: 50%;
+                  transform: translate(-50%, -50%);
+                  border-radius: 50%;
+                  border: 3px solid rgba(255, 255, 255, 0.5);
+                  animation: scale 2s linear infinite;
+                }
+              }
+            }
+
+            .pie-data {
+              width: 140px;
+              height: 20px;
+              display: flex;
+              justify-content: center;
+              position: relative;
+              background: url('/@/assets/images/vent/path/pie-line.png');
+
+              .data-text {
+                display: block;
+                position: absolute;
+                top: -8px;
+              }
+            }
+          }
+        }
+
+        .detail-data-group {
+          width: 100%;
+          ;
+          display: flex;
+          flex-direction: column;
+          align-items: center;
+          margin-top: 15px;
+
+          .container-item {
+            width: 307px;
+            height: 63px;
+            display: flex;
+            position: relative;
+            background: url('/@/assets/images/vent/plane-bottom.png') no-repeat;
+            background-size: auto;
+            background-position: bottom;
+            padding: 10px 30px;
+
+            &::before {
+              content: '';
+              display: block;
+              width: 100%;
+              height: 5px;
+              position: absolute;
+              top: 62px;
+              left: 0;
+              background-color: #73f4ff66;
+              backdrop-filter: blur(5px);
+            }
+
+            .item-icon {
+              width: 60px;
+              height: 45px;
+              background: url('/@/assets/images/vent/plane-icon-bg.png') no-repeat;
+              background-size: cover;
+
+              .icon-style {
+                margin: 10px 0 0 18px;
+              }
+            }
+
+            .item-name {
+              width: 180px;
+              line-height: 60px;
+              margin-left: 5px;
+              text-align: left;
+            }
+
+            .item-value {
+              position: relative;
+              height: 26px;
+              line-height: 24px;
+              margin: 15px 0;
+              text-align: center;
+              width: 80px;
+              border: 1px solid #00f5fe;
+              border-radius: 13px;
+              background: linear-gradient(to right, #00f5fe44, #0090ff44);
+
+              &::before {
+                width: 6px;
+                height: 6px;
+                content: '';
+                position: absolute;
+                left: -3px;
+                top: 8px;
+                background: #ffa500;
+                border-radius: 3px;
+              }
+            }
+          }
+        }
+
+        .feature-group {
+          display: flex;
+          flex-direction: row;
+          padding: 20px;
+          margin-top: 15px;
+
+          .feature-item {
+            width: 108px;
+            height: 120px;
+            background: url('/@/assets/images/vent/path/path-feature-bg.png');
+            display: flex;
+            flex-direction: column;
+            // justify-content: center;
+
+            .pie {
+              display: flex;
+              justify-content: center;
+            }
+
+            .data {
+              margin-top: 15px;
+              font-size: 12px;
+              scale: 0.9;
+              text-align: center;
+            }
+          }
+        }
+      }
+    }
+
+    .right-box {
+      display: flex;
+      flex-direction: column;
+
+      .sensor-box,
+      .warning-box {
+        position: relative;
+
+        // min-height: 220px;
+        // max-height: 250px;
+        .table-box {
+          height: 280px;
+          width: 100%;
+          position: relative;
+
+          .table-container {
+            width: calc(100% - 40px);
+            margin: 25px 20px 20px;
+            height: 250px;
+            position: absolute;
+          }
+        }
+      }
+
+      .sensor-box {
+        .item-top-title {
+          &::after {
+            left: 110px;
+          }
+
+          &::before {
+            left: 265px;
+          }
+        }
+      }
+
+      .warning-box {
+        margin-top: 10px;
+      }
+    }
+  }
+
+  .bottom-box {
+    width: 100%;
+    height: calc(30% - 20px);
+    display: flex;
+    justify-content: space-between;
+    margin-top: 0px;
+    position: relative;
+    top: -20px;
+    pointer-events: auto;
+    .to-small {
+      width: 60px;
+      height: 60px;
+      background: url('/@/assets/images/vent/home/tosmall.png') no-repeat center;
+      background-size: auto;
+      position: absolute;
+      top: -95px;
+      right: 400px;
+      border-radius: 10px;
+      padding: 8px;
+      backdrop-filter: blur(10px);
+      background-color: rgba(45, 86, 137, 0.418);
+
+      &:hover {
+        background-color: rgba(79, 104, 134, 0.418);
+      }
+    }
+    .bottom-lr-box {
+      flex: 1;
+      display: flex;
+      justify-content: center;
+
+    }
+
+    .bottom-left {
+      margin-right: 10px;
+
+      .network-top {
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        position: relative;
+        top: 55px;
+        padding: 0 30px;
+
+        .network-top-left {
+          display: flex;
+
+          div {
+            margin-right: 20px;
+          }
+
+          span {
+            font-family: 'douyuFont';
+            font-size: 15px;
+          }
+
+          .accuracy-rate {
+            color: #FFA500;
+          }
+
+          .error-rate {
+            color: #00f5fe;
+          }
+        }
+
+        .time {
+          color: #949494;
+        }
+      }
+
+      .table-container {
+        height: 150px;
+        margin-top: 55px;
+        margin-left: 15px;
+        margin-right: 10px;
+      }
+    }
+
+    .bottom-right {
+      margin-left: 10px;
+
+      .zl-top {
+        width: calc(100% - 30px);
+        padding: 0 20px;
+        display: flex;
+        flex-direction: row;
+        justify-content: space-between;
+        position: relative;
+        top: 35px;
+        z-index: 99;
+        margin: 10px;
+        border-bottom: 1px solid #00f5fe88;
+
+        .btn {
+          padding: 3px 10px;
+          border-top: 1px solid #c6c6c6;
+          background-image: linear-gradient(#c2c2c2aa, #b3b3b388 20%, #5a5a5a88);
+          cursor: pointer;
+          margin-right: 5px;
+
+          &:hover,
+          &:active {
+            border-top: 1px solid #00f5fe;
+            background-image: linear-gradient(#00f5feaa, #1adce288 20%, #00848988);
+          }
+        }
+
+        .active {
+          border-top: 1px solid #00f5fe;
+          background-image: linear-gradient(#00f5feaa, #1adce288 20%, #00848988);
+        }
+
+        .data {
+          font-family: 'douyuFont';
+          color: #FFA500;
+          font-size: 15px;
+        }
+      }
+
+      .zl-container {
+        width: 100%;
+        height: 100%;
+        margin: 0 15px;
+        background: url('/@/assets/images/vent/path/zl-bg1.png') no-repeat;
+        background-size: 920px 190px;
+        position: relative;
+
+        &::after {
+          content: '';
+          display: block;
+          position: absolute;
+          width: 100%;
+          height: 100%;
+          top: 85px;
+          background: url('/@/assets/images/vent/path/zl-bg2.png') no-repeat;
+          background-size: 920px 100px;
+        }
+      }
+
+      .zl-path-item {
+        height: 67px;
+        background: url('/@/assets/images/vent/path/zl-path-item-bg.png') no-repeat;
+        background-size: auto;
+        background-position: center bottom;
+        position: absolute;
+        scale: 0.9;
+
+        .title {
+          position: relative;
+          top: -20px;
+          text-align: center;
+          font-size: 12px;
+          background: #00f5fe33;
+          padding: 3px 5px;
+          backdrop-filter: blur(5px);
+        }
+      }
+
+      .position10 {
+        top: 130px;
+        left: 0px;
+      }
+
+      .position9 {
+        top: 52px;
+        left: 100px;
+      }
+
+      .position8 {
+        top: 132px;
+        left: 220px;
+      }
+
+      .position7 {
+        top: 128px;
+        left: 420px;
+      }
+
+      .position6 {
+        top: 60px;
+        left: 320px;
+      }
+
+      .position5 {
+        top: 120px;
+        left: 580px;
+      }
+
+      .position4 {
+        top: 123px;
+        left: 690px;
+      }
+
+      .position3 {
+        top: 103px;
+        left: 830px;
+      }
+
+      .position2 {
+        top: 90px;
+        left: 740px;
+      }
+
+      .position1 {
+        top: 80px;
+        left: 535px;
+      }
+    }
+  }
+}
+
+.item-top-title {
+  width: 374px;
+  height: 32px;
+  text-align: center;
+  line-height: 34px;
+  font-size: 15px;
+  font-weight: 600;
+  color: #fafafa;
+  position: absolute;
+  padding-top: 0px;
+  top: -9px;
+
+  &::before {
+    content: '';
+    display: block;
+    width: 40px;
+    height: 1px;
+    position: absolute;
+    left: 255px;
+    top: 50%;
+    transform: translateY(-50%);
+    -webkit-transform: translate(-50%, -50%);
+    background-color: #00d4fe88;
+  }
+
+  &::after {
+    content: '';
+    display: block;
+    width: 40px;
+    height: 1px;
+    position: absolute;
+    left: 120px;
+    top: 50%;
+    transform: translateY(-50%);
+    -webkit-transform: translate(-50%, -50%);
+    background-color: #00d4fe88;
+  }
+}
+
+.signal-round {
+  display: inline-block;
+  width: 4px;
+  height: 4px;
+  border-radius: 50%;
+  position: relative;
+  top: -3px;
+
+  &::after {
+    display: block;
+    content: '';
+    position: absolute;
+    width: 8px;
+    height: 8px;
+    top: -2px;
+    left: -2px;
+    border-radius: 50%;
+    background-color: #daffc044;
+    box-shadow: 0 0 1px 1px #c6ff7722;
+  }
+}
+
+.signal-round-run {
+  background-color: #67fc00;
+
+  &::after {
+    background-color: #daffc044;
+    box-shadow: 0 0 1px 1px #c6ff7722;
+  }
+}
+
+.signal-round-red {
+  background-color: #FF3823;
+
+  &::after {
+    background-color: #FF382344;
+    box-shadow: 0 0 1px 1px #FF382333;
+  }
+}
+
+.signal-round-orange {
+  background-color: #FF9B17;
+
+  &::after {
+    background-color: #FF9B1744;
+    box-shadow: 0 0 1px 1px #FF9B1733;
+  }
+}
+
+.signal-round-yellow {
+  background-color: #FFFF00;
+
+  &::after {
+    background-color: #FFFF0044;
+    box-shadow: 0 0 1px 1px #FFFF0033;
+  }
+}
+
+.table-container {
+  overflow-y: auto;
+  overflow-x: hidden;
+  pointer-events: auto;
+
+  &::-webkit-scrollbar {
+    width: 4px;
+    height: 8px;
+    background-color: #f5f5f500;
+  }
+
+  &::-webkit-scrollbar-track {
+    background-color: #ffffff33;
+    border-radius: 10px;
+  }
+
+  &::-webkit-scrollbar-thumb {
+    background-color: #cccccc44;
+    border-radius: 10px;
+  }
+}
+
+.border-bg{
+  backdrop-filter: blur(5px);
+}
+
+@keyframes scale {
+  0% {
+    transform: translate(-50%, -50%) scale(0.9);
+    opacity: 1;
+  }
+
+  100% {
+    transform: translate(-50%, -50%) scale(1.5);
+    opacity: 0;
+  }
+}
+
+:deep(.@{ventSpace}-progress-text) {
+  color: #fff !important;
+}
+
+:deep(.@{ventSpace}-table-thead) {
+  background-color: transparent !important;
+
+  &>tr {
+    border: 1px solid #00f5fe !important;
+  }
+
+  &>tr>th {
+    // border: none !important;
+    color: #00f5fe !important;
+    border-top: 1px solid #00f5fe !important;
+    border-bottom: 1px solid #00f5fe !important;
+    border-left: none !important;
+    border-right: none !important;
+    font-size: 13px;
+  }
+}
+
+:deep(.@{ventSpace}-table-tbody) {
+  &>tr>td {
+    font-size: 13px;
+  }
+}
+
+:deep(.@{ventSpace}-table-small) {
+  border: none !important;
+}
+
+:deep(.@{ventSpace}-layout) {
+  background: transparent !important;
+}</style>

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio