Browse Source

[Feat 0000] 新增了三种风门模型

hongrunxia 1 day ago
parent
commit
cf77164fb3

+ 2 - 0
package.json

@@ -170,6 +170,8 @@
     "ts-node": "^10.9.1",
     "typescript": "^4.9.5",
     "unocss": "^0.55.3",
+    "video.js": "^8.23.4",
+    "videojs-flvjs-es6": "^1.0.1",
     "vite": "^4.4.9",
     "vite-plugin-compression": "^0.5.1",
     "vite-plugin-html": "^3.2.0",

+ 172 - 0
pnpm-lock.yaml

@@ -447,6 +447,12 @@ importers:
       unocss:
         specifier: ^0.55.3
         version: 0.55.7(postcss@8.5.6)(rollup@3.29.5)(vite@4.5.14(@types/node@20.19.25)(less@4.4.2)(terser@5.44.1))
+      video.js:
+        specifier: ^8.23.4
+        version: 8.23.4
+      videojs-flvjs-es6:
+        specifier: ^1.0.1
+        version: 1.0.1
       vite:
         specifier: ^4.4.9
         version: 4.5.14(@types/node@20.19.25)(less@4.4.2)(terser@5.44.1)
@@ -2229,6 +2235,19 @@ packages:
     peerDependencies:
       vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0
 
+  '@videojs/http-streaming@3.17.2':
+    resolution: {integrity: sha512-VBQ3W4wnKnVKb/limLdtSD2rAd5cmHN70xoMf4OmuDd0t2kfJX04G+sfw6u2j8oOm2BXYM9E1f4acHruqKnM1g==}
+    engines: {node: '>=8', npm: '>=5'}
+    peerDependencies:
+      video.js: ^8.19.0
+
+  '@videojs/vhs-utils@4.1.1':
+    resolution: {integrity: sha512-5iLX6sR2ownbv4Mtejw6Ax+naosGvoT9kY+gcuHzANyUZZ+4NpeNdKMUhb6ag0acYej1Y7cmr/F2+4PrggMiVA==}
+    engines: {node: '>=8', npm: '>=5'}
+
+  '@videojs/xhr@2.7.0':
+    resolution: {integrity: sha512-giab+EVRanChIupZK7gXjHy90y3nncA2phIOyG3Ne5fvpiMJzvqYwiTOnEVW2S4CoYcuKJkomat7bMXA/UoUZQ==}
+
   '@vitejs/plugin-legacy@2.3.1':
     resolution: {integrity: sha512-J5KaGBlSt2tEYPVjM/C8dA6DkRzkFkbPe+Xb4IX5G+XOV5OGbVAfkMjKywdrkO3gGynO8S98i71Lmsff4cWkCQ==}
     engines: {node: ^14.18.0 || >=16.0.0}
@@ -2349,6 +2368,10 @@ packages:
       vue:
         optional: true
 
+  '@xmldom/xmldom@0.8.11':
+    resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==}
+    engines: {node: '>=10.0.0'}
+
   '@zxcvbn-ts/core@3.0.4':
     resolution: {integrity: sha512-aQeiT0F09FuJaAqNrxynlAwZ2mW/1MdXakKWNmGM1Qp/VaY6CnB/GfnMS2T8gB2231Esp1/maCWd8vTG4OuShw==}
 
@@ -2402,6 +2425,9 @@ packages:
     resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==}
     engines: {node: '>=0.8'}
 
+  aes-decrypter@4.0.2:
+    resolution: {integrity: sha512-lc+/9s6iJvuaRe5qDlMTpCFjnwpkeOXp8qP3oiZ5jsj1MRg+SBVUmmICrhxHvc8OELSmc+fEyyxAuppY6hrWzw==}
+
   agent-base@6.0.2:
     resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
     engines: {node: '>= 6.0.0'}
@@ -3575,6 +3601,9 @@ packages:
   dom-serializer@2.0.0:
     resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
 
+  dom-walk@0.1.2:
+    resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==}
+
   dom-zindex@1.0.6:
     resolution: {integrity: sha512-FKWIhiU96bi3xpP9ewRMgANsoVmMUBnMnmpCT6dPMZOunVYJQmJhSRruoI0XSPoHeIif3kyEuiHbFrOJwEJaEA==}
 
@@ -4369,6 +4398,9 @@ packages:
     resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==}
     engines: {node: '>=6'}
 
+  global@4.4.0:
+    resolution: {integrity: sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==}
+
   globals@13.24.0:
     resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
     engines: {node: '>=8'}
@@ -4737,6 +4769,9 @@ packages:
     resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==}
     engines: {node: '>=12'}
 
+  is-function@1.0.2:
+    resolution: {integrity: sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==}
+
   is-generator-fn@2.1.0:
     resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==}
     engines: {node: '>=6'}
@@ -5442,6 +5477,9 @@ packages:
     resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==}
     engines: {node: '>=12'}
 
+  m3u8-parser@7.2.0:
+    resolution: {integrity: sha512-CRatFqpjVtMiMaKXxNvuI3I++vUumIXVVT/JpCpdU/FynV/ceVw1qpPyyBNindL+JlPMSesx+WX1QJaZEJSaMQ==}
+
   magic-string@0.25.9:
     resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==}
 
@@ -5560,6 +5598,9 @@ packages:
     resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
     engines: {node: '>=12'}
 
+  min-document@2.19.2:
+    resolution: {integrity: sha512-8S5I8db/uZN8r9HSLFVWPdJCvYOejMcEC82VIzNUc6Zkklf/d1gg2psfE79/vyhWOj4+J8MtwmoOz3TmvaGu5A==}
+
   min-indent@1.0.1:
     resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
     engines: {node: '>=4'}
@@ -5627,6 +5668,10 @@ packages:
   mousetrap@1.6.5:
     resolution: {integrity: sha512-QNo4kEepaIBwiT8CDhP98umTetp+JNfQYBWvC1pc6/OAibuXtRcxZ58Qz8skvEHYvURne/7R8T5VoOI7rDsEUA==}
 
+  mpd-parser@1.3.1:
+    resolution: {integrity: sha512-1FuyEWI5k2HcmhS1HkKnUAQV7yFPfXPht2DnRRGtoiiAAW+ESTbtEXIDpRkwdU+XyrQuwrIym7UkoPKsZ0SyFw==}
+    hasBin: true
+
   mri@1.2.0:
     resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
     engines: {node: '>=4'}
@@ -5654,6 +5699,11 @@ packages:
     resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==}
     engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
 
+  mux.js@7.1.0:
+    resolution: {integrity: sha512-NTxawK/BBELJrYsZThEulyUMDVlLizKdxyAsMuzoCD1eFj97BVaA8D/CvKsKu6FOLYkFojN5CbM9h++ZTZtknA==}
+    engines: {node: '>=8', npm: '>=5'}
+    hasBin: true
+
   nanoid@3.3.11:
     resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
     engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -6010,6 +6060,10 @@ packages:
     resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
     engines: {node: '>= 6'}
 
+  pkcs7@1.0.4:
+    resolution: {integrity: sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==}
+    hasBin: true
+
   pkg-dir@4.2.0:
     resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
     engines: {node: '>=8'}
@@ -6142,6 +6196,10 @@ packages:
   process-nextick-args@2.0.1:
     resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
 
+  process@0.11.10:
+    resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==}
+    engines: {node: '>= 0.6.0'}
+
   prompts@2.4.2:
     resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
     engines: {node: '>= 6'}
@@ -7281,6 +7339,24 @@ packages:
   vditor@3.11.2:
     resolution: {integrity: sha512-8QguQQUPWbBFocnfQmWjz4jiykQnvsmCuhOomGIVVK7vc+dQq2h8w9qQQuEjUTZpnZT5fEdYbj4aLr1NGdAZaA==}
 
+  video.js@8.23.4:
+    resolution: {integrity: sha512-qI0VTlYmKzEqRsz1Nppdfcaww4RSxZAq77z2oNSl3cNg2h6do5C8Ffl0KqWQ1OpD8desWXsCrde7tKJ9gGTEyQ==}
+
+  videojs-contrib-quality-levels@4.1.0:
+    resolution: {integrity: sha512-TfrXJJg1Bv4t6TOCMEVMwF/CoS8iENYsWNKip8zfhB5kTcegiFYezEA0eHAJPU64ZC8NQbxQgOwAsYU8VXbOWA==}
+    engines: {node: '>=16', npm: '>=8'}
+    peerDependencies:
+      video.js: ^8
+
+  videojs-flvjs-es6@1.0.1:
+    resolution: {integrity: sha512-wAI5ff2tZVW+uftTLyPmS38F4SHmMlxqBFOgXEBqMs2X0N4uIVQK0iCCv5XACXH+oc+mP70D23mJmT8KsoHx0g==}
+
+  videojs-font@4.2.0:
+    resolution: {integrity: sha512-YPq+wiKoGy2/M7ccjmlvwi58z2xsykkkfNMyIg4xb7EZQQNwB71hcSsB3o75CqQV7/y5lXkXhI/rsGAS7jfEmQ==}
+
+  videojs-vtt.js@0.15.5:
+    resolution: {integrity: sha512-yZbBxvA7QMYn15Lr/ZfhhLPrNpI/RmCSCqgIff57GC2gIrV5YfyzLfLyZMj0NnZSAz8syB4N0nHXpZg9MyrMOQ==}
+
   vite-plugin-compression@0.5.1:
     resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==}
     peerDependencies:
@@ -10050,6 +10126,28 @@ snapshots:
     transitivePeerDependencies:
       - rollup
 
+  '@videojs/http-streaming@3.17.2(video.js@8.23.4)':
+    dependencies:
+      '@babel/runtime': 7.28.4
+      '@videojs/vhs-utils': 4.1.1
+      aes-decrypter: 4.0.2
+      global: 4.4.0
+      m3u8-parser: 7.2.0
+      mpd-parser: 1.3.1
+      mux.js: 7.1.0
+      video.js: 8.23.4
+
+  '@videojs/vhs-utils@4.1.1':
+    dependencies:
+      '@babel/runtime': 7.28.4
+      global: 4.4.0
+
+  '@videojs/xhr@2.7.0':
+    dependencies:
+      '@babel/runtime': 7.28.4
+      global: 4.4.0
+      is-function: 1.0.2
+
   '@vitejs/plugin-legacy@2.3.1(terser@5.44.1)(vite@4.5.14(@types/node@20.19.25)(less@4.4.2)(terser@5.44.1))':
     dependencies:
       '@babel/standalone': 7.28.5
@@ -10224,6 +10322,8 @@ snapshots:
     optionalDependencies:
       vue: 3.5.24(typescript@4.9.5)
 
+  '@xmldom/xmldom@0.8.11': {}
+
   '@zxcvbn-ts/core@3.0.4':
     dependencies:
       fastest-levenshtein: 1.0.16
@@ -10265,6 +10365,13 @@ snapshots:
 
   adler-32@1.3.1: {}
 
+  aes-decrypter@4.0.2:
+    dependencies:
+      '@babel/runtime': 7.28.4
+      '@videojs/vhs-utils': 4.1.1
+      global: 4.4.0
+      pkcs7: 1.0.4
+
   agent-base@6.0.2:
     dependencies:
       debug: 4.4.3
@@ -11540,6 +11647,8 @@ snapshots:
       domhandler: 5.0.3
       entities: 4.5.0
 
+  dom-walk@0.1.2: {}
+
   dom-zindex@1.0.6: {}
 
   domelementtype@1.3.1: {}
@@ -12479,6 +12588,11 @@ snapshots:
       kind-of: 6.0.3
       which: 1.3.1
 
+  global@4.4.0:
+    dependencies:
+      min-document: 2.19.2
+      process: 0.11.10
+
   globals@13.24.0:
     dependencies:
       type-fest: 0.20.2
@@ -12877,6 +12991,8 @@ snapshots:
 
   is-fullwidth-code-point@4.0.0: {}
 
+  is-function@1.0.2: {}
+
   is-generator-fn@2.1.0: {}
 
   is-generator-function@1.1.2:
@@ -14001,6 +14117,12 @@ snapshots:
 
   luxon@3.7.2: {}
 
+  m3u8-parser@7.2.0:
+    dependencies:
+      '@babel/runtime': 7.28.4
+      '@videojs/vhs-utils': 4.1.1
+      global: 4.4.0
+
   magic-string@0.25.9:
     dependencies:
       sourcemap-codec: 1.4.8
@@ -14136,6 +14258,10 @@ snapshots:
 
   mimic-fn@4.0.0: {}
 
+  min-document@2.19.2:
+    dependencies:
+      dom-walk: 0.1.2
+
   min-indent@1.0.1: {}
 
   minimatch@3.1.2:
@@ -14198,6 +14324,13 @@ snapshots:
 
   mousetrap@1.6.5: {}
 
+  mpd-parser@1.3.1:
+    dependencies:
+      '@babel/runtime': 7.28.4
+      '@videojs/vhs-utils': 4.1.1
+      '@xmldom/xmldom': 0.8.11
+      global: 4.4.0
+
   mri@1.2.0: {}
 
   mrmime@2.0.1: {}
@@ -14214,6 +14347,11 @@ snapshots:
 
   mute-stream@1.0.0: {}
 
+  mux.js@7.1.0:
+    dependencies:
+      '@babel/runtime': 7.28.4
+      global: 4.4.0
+
   nanoid@3.3.11: {}
 
   nanomatch@1.2.13:
@@ -14548,6 +14686,10 @@ snapshots:
 
   pirates@4.0.7: {}
 
+  pkcs7@1.0.4:
+    dependencies:
+      '@babel/runtime': 7.28.4
+
   pkg-dir@4.2.0:
     dependencies:
       find-up: 4.1.0
@@ -14692,6 +14834,8 @@ snapshots:
 
   process-nextick-args@2.0.1: {}
 
+  process@0.11.10: {}
+
   prompts@2.4.2:
     dependencies:
       kleur: 3.0.3
@@ -15939,6 +16083,34 @@ snapshots:
     dependencies:
       diff-match-patch: 1.0.5
 
+  video.js@8.23.4:
+    dependencies:
+      '@babel/runtime': 7.28.4
+      '@videojs/http-streaming': 3.17.2(video.js@8.23.4)
+      '@videojs/vhs-utils': 4.1.1
+      '@videojs/xhr': 2.7.0
+      aes-decrypter: 4.0.2
+      global: 4.4.0
+      m3u8-parser: 7.2.0
+      mpd-parser: 1.3.1
+      mux.js: 7.1.0
+      videojs-contrib-quality-levels: 4.1.0(video.js@8.23.4)
+      videojs-font: 4.2.0
+      videojs-vtt.js: 0.15.5
+
+  videojs-contrib-quality-levels@4.1.0(video.js@8.23.4):
+    dependencies:
+      global: 4.4.0
+      video.js: 8.23.4
+
+  videojs-flvjs-es6@1.0.1: {}
+
+  videojs-font@4.2.0: {}
+
+  videojs-vtt.js@0.15.5:
+    dependencies:
+      global: 4.4.0
+
   vite-plugin-compression@0.5.1(vite@4.5.14(@types/node@20.19.25)(less@4.4.2)(terser@5.44.1)):
     dependencies:
       chalk: 4.1.2

+ 6 - 6
src/design/vent/comment.less

@@ -209,18 +209,18 @@
   --image-camera_bg: url('/@/assets/images/vent/camera_bg.png');
   margin-top: 10px;
   position: relative;
-  // width: 314px;
-  // height: 208px;
-  // width: 614px;
-  // height: 508px;
+  width: 460px;
+  height: 269px;
   background: var(--image-camera_bg);
   background-size: cover;
   padding: 10px;
+  align-self: end;
+  padding: 10px;
 
   .rtspVideo {
     border: 1px solid #ffffff22;
-    height: 180px;
-    width: 320px;
+    width: 100%;
+    height: 100%;
   }
 
   .video-name {

+ 76 - 111
src/hooks/system/useCamera.ts

@@ -7,6 +7,7 @@ import HlsPlugin from 'xgplayer-hls';
 import FlvPlugin from 'xgplayer-flv';
 import 'xgplayer/dist/index.min.css';
 import ZH from 'xgplayer/es/lang/zh-cn';
+import videojs from 'video.js';
 I18N.use(ZH);
 
 export function useCamera() {
@@ -188,117 +189,78 @@ export function useCamera() {
           videoParentDom.setAttribute('class', 'liveVideo');
           livePlayerDiv?.appendChild(videoParentDom);
           useDrag(videoParentDom);
-          const videoDom: HTMLElement = document.createElement('div');
-          videoDom.setAttribute('id', videoParent[0]);
-          videoParentDom.appendChild(videoDom);
+
           if (videoParent[1] && videoParent[1].addr) {
+            let player;
             const fileExtension = videoParent[1].addr.split('.').pop();
-            const player = getPlayer(fileExtension, videoParent[0], videoParent[1].devicekind, videoParent[1].addr, videoParent[1].cameraRate);
-            // let player;
-            // if (fileExtension === 'flv' || videoParent[1].devicekind == 'flv') {
-            //   player = new Player({
-            //     lang: 'zh',
-            //     id: videoParent[0],
-            //     url: videoParent[1].addr,
-            //     width: 294,
-            //     height: 188,
-            //     poster: '/src/assets/images/vent/noSinge.png',
-            //     plugins: [FlvPlugin],
-            //     fluid: true,
-            //     autoplay: true,
-            //     isLive: true,
-            //     playsinline: true,
-            //     screenShot: true,
-            //     whitelist: [''],
-            //     ignores: ['time', 'progress', 'play', 'i18n', 'volume', 'fullscreen', 'screenShot', 'playbackRate'],
-            //     closeVideoClick: true,
-            //     customConfig: {
-            //       isClickPlayBack: false,
-            //     },
-            //     controlsList: ['nodownload', 'nofullscreen', 'noremoteplayback'],
-            //     defaultPlaybackRate: videoParent[1].cameraRate || 1,
-            //     flv: {
-            //       retryCount: 3, // 重试 3 次,默认值
-            //       retryDelay: 1000, // 每次重试间隔 1 秒,默认值
-            //       loadTimeout: 10000, // 请求超时时间为 10 秒,默认值
-            //       fetchOptions: {
-            //         // 该参数会透传给 fetch,默认值为 undefined
-            //         mode: 'cors',
-            //       },
-            //       targetLatency: 10, // 直播目标延迟,默认 10 秒
-            //       maxLatency: 20, // 直播允许的最大延迟,默认 20 秒
-            //       disconnectTime: 10, // 直播断流时间,默认 0 秒,(独立使用时等于 maxLatency)
-            //       maxJumpDistance: 10,
-            //     },
-            //   });
-
-            //   playerList.push(player);
-            // }
-            // if (fileExtension === 'm3u8' || videoParent[1].devicekind == 'm3u8') {
-            //   let player;
-            //   if (document.createElement('video').canPlayType('application/vnd.apple.mpegurl')) {
-            //     // 原生支持 hls 播放
-            //     player = new Player({
-            //       lang: 'zh',
-            //       id: videoParent[0],
-            //       url: videoParent[1].addr,
-            //       width: 294,
-            //       height: 188,
-            //       isLive: true,
-            //       autoplay: true,
-            //       autoplayMuted: true,
-            //       cors: true,
-            //       ignores: ['time', 'progress', 'play', 'i18n', 'volume', 'fullscreen', 'screenShot', 'playbackRate'],
-            //       poster: '/src/assets/images/vent/noSinge.png',
-            //       defaultPlaybackRate: videoParent[1].cameraRate || 1,
-            //       controlsList: ['nodownload', 'nofullscreen', 'noremoteplayback'],
-            //       hls: {
-            //         retryCount: 10, // 重试 3 次,默认值
-            //         retryDelay: 30000, // 每次重试间隔 1 秒,默认值
-            //         loadTimeout: 10000, // 请求超时时间为 10 秒,默认值
-            //         disconnectTime: 30, //直播断流时间,
-            //         fetchOptions: {
-            //           // 该参数会透传给 fetch,默认值为 undefined
-            //           mode: 'cors',
-            //         },
-            //         targetLatency: 10, // 直播目标延迟,默认 10 秒
-            //         maxLatency: 20, // 直播允许的最大延迟,默认 20 秒
-            //         maxJumpDistance: 10,
-            //       },
-            //     });
-            //   } else if (HlsPlugin.isSupported()) {
-            //     // 第一步
-            //     player = new Player({
-            //       lang: 'zh',
-            //       id: videoParent[0],
-            //       url: videoParent[1].addr,
-            //       width: 294,
-            //       height: 188,
-            //       isLive: true,
-            //       autoplay: true,
-            //       autoplayMuted: true,
-            //       ignores: ['time', 'progress', 'play', 'i18n', 'volume', 'fullscreen', 'screenShot', 'playbackRate'],
-            //       plugins: [HlsPlugin], // 第二步
-            //       poster: '/src/assets/images/vent/noSinge.png',
-            //       defaultPlaybackRate: videoParent[1].cameraRate || 1,
-            //       controlsList: ['nodownload', 'nofullscreen', 'noremoteplayback'],
-            //       hls: {
-            //         retryCount: 10, // 重试 3 次,默认值
-            //         retryDelay: 30000, // 每次重试间隔 1 秒,默认值
-            //         loadTimeout: 10000, // 请求超时时间为 10 秒,默认值
-            //         disconnectTime: 30,
-            //         fetchOptions: {
-            //           // 该参数会透传给 fetch,默认值为 undefined
-            //           mode: 'cors',
-            //         },
-            //         targetLatency: 10, // 直播目标延迟,默认 10 秒
-            //         maxLatency: 20, // 直播允许的最大延迟,默认 20 秒
-            //         maxJumpDistance: 10,
-            //       },
-            //     });
-            //   }
-            //   playerList.push(player);
-            // }
+            // const player = getPlayer(fileExtension, videoParent[0], videoParent[1].devicekind, videoParent[1].addr, videoParent[1].cameraRate);
+            if (fileExtension === 'flv' || videoParent[1].devicekind == 'flv') {
+              const videoDom: HTMLElement = document.createElement('div');
+              videoDom.setAttribute('id', videoParent[0]);
+              videoDom.style = 'width: 100%; height: 100%;';
+              videoParentDom.appendChild(videoDom);
+              player = new Player({
+                lang: 'zh',
+                id: videoParent[0],
+                url: videoParent[1].addr,
+                width: 294,
+                height: 188,
+                poster: '/src/assets/images/vent/noSinge.png',
+                plugins: [FlvPlugin],
+                fluid: true,
+                autoplay: true,
+                isLive: true,
+                playsinline: true,
+                screenShot: true,
+                whitelist: [''],
+                ignores: ['time', 'progress', 'play', 'i18n', 'volume', 'fullscreen', 'screenShot', 'playbackRate'],
+                closeVideoClick: true,
+                customConfig: {
+                  isClickPlayBack: false,
+                },
+                controlsList: ['nodownload', 'nofullscreen', 'noremoteplayback'],
+                defaultPlaybackRate: videoParent[1].cameraRate || 1,
+                flv: {
+                  retryCount: 3, // 重试 3 次,默认值
+                  retryDelay: 1000, // 每次重试间隔 1 秒,默认值
+                  loadTimeout: 10000, // 请求超时时间为 10 秒,默认值
+                  fetchOptions: {
+                    // 该参数会透传给 fetch,默认值为 undefined
+                    mode: 'cors',
+                  },
+                  targetLatency: 10, // 直播目标延迟,默认 10 秒
+                  maxLatency: 20, // 直播允许的最大延迟,默认 20 秒
+                  disconnectTime: 10, // 直播断流时间,默认 0 秒,(独立使用时等于 maxLatency)
+                  maxJumpDistance: 10,
+                },
+              });
+            } else {
+              const videoDom: HTMLElement = document.createElement('video');
+              videoDom.setAttribute('id', videoParent[0]);
+              videoDom.style = 'width: 100%; height: 100%;';
+              videoParentDom.appendChild(videoDom);
+              player = videojs(
+                videoParent[0],
+                {
+                  controls: false,
+                  autoplay: true,
+                  preload: 'auto',
+                  muted: true,
+                  // src: cameraUrl,
+                  sources: [
+                    {
+                      src: videoParent[1].addr,
+                      type: 'application/x-mpegURL',
+                    },
+                  ],
+                },
+                () => {
+                  videojs.log('播放器准备好了!');
+                  // this.play();
+                }
+              );
+              player.play();
+            }
             playerList.push(player);
           }
         } else {
@@ -439,7 +401,6 @@ export function useCamera() {
           },
         });
       }
-      // playerList.push(player);
     }
     return player;
   }
@@ -455,7 +416,11 @@ export function useCamera() {
       dom?.remove();
     });
     playerList.forEach((player) => {
-      if (player && player.destroy) player.destroy();
+      if (player) {
+        if (player.destroy) player.destroy();
+        if (player.dispose) player.dispose();
+        if (player.remove) player.remove();
+      }
       player = null;
     });
     videoParentDomList.length = 0;

+ 90 - 81
src/views/vent/monitorManager/airDoor/components/Modal.vue

@@ -1,7 +1,17 @@
 <template>
-  <a-modal ref="modalRef"   width="850px" :visible="props.visible" :wrap-style="{ overflow: 'hidden' }" @ok="handleOk"
-    :mask-closable="maskClosable" :centered="props.centered" :footer="props.footer" @cancel="handleCancel"
-    :confirm-loading="props.confirmLoading" :destroyOnClose="props.destroyOnClose">
+  <a-modal
+    ref="modalRef"
+    width="850px"
+    :visible="props.visible"
+    :wrap-style="{ overflow: 'hidden' }"
+    @ok="handleOk"
+    :mask-closable="maskClosable"
+    :centered="props.centered"
+    :footer="props.footer"
+    @cancel="handleCancel"
+    :confirm-loading="props.confirmLoading"
+    :destroyOnClose="props.destroyOnClose"
+  >
     <slot></slot>
 
     <template #title>
@@ -16,94 +26,93 @@
   </a-modal>
 </template>
 <script lang="ts" setup>
-import { computed, CSSProperties, ref, watch, watchEffect } from "vue";
-import { useDraggable } from "@vueuse/core";
+  import { computed, CSSProperties, ref, watch, watchEffect } from 'vue';
+  import { useDraggable } from '@vueuse/core';
 
-// 定义Props接口,描述组件的属性
-interface Props {
-  title?: string, // 对话框的标题,默认为"提示"
-  footer?: null, // 对话框的页脚,默认为null
-  visible: boolean, // 对话框是否可见
-  confirmLoading?: boolean, // 确认按钮是否处于加载状态,默认为false
-  destroyOnClose?: boolean, // 对话框关闭时是否销毁组件,默认为false
-  maskClosable?: boolean, // 点击遮罩层是否可关闭对话框,默认为false
-  centered?: boolean, // 对话框是否居中显示,默认为false
-}
-
-// 设置props的默认值
-const props = withDefaults(defineProps<Props>(), { title: '摄像头信息', visible: false, destroyOnClose: false, maskClosable: true })
+  // 定义Props接口,描述组件的属性
+  interface Props {
+    title?: string; // 对话框的标题,默认为"提示"
+    footer?: null; // 对话框的页脚,默认为null
+    visible: boolean; // 对话框是否可见
+    confirmLoading?: boolean; // 确认按钮是否处于加载状态,默认为false
+    destroyOnClose?: boolean; // 对话框关闭时是否销毁组件,默认为false
+    maskClosable?: boolean; // 点击遮罩层是否可关闭对话框,默认为false
+    centered?: boolean; // 对话框是否居中显示,默认为false
+  }
 
-// 创建ref引用modalTitleRef,用于引用组件中的标题元素
-const modalTitleRef = ref<HTMLElement | null | any>(null);
+  // 设置props的默认值
+  const props = withDefaults(defineProps<Props>(), { title: '摄像头信息', visible: false, destroyOnClose: false, maskClosable: true });
 
-// 使用useDraggable钩子,获取拖拽相关属性
-const { x, y, isDragging } = useDraggable(modalTitleRef);
+  // 创建ref引用modalTitleRef,用于引用组件中的标题元素
+  const modalTitleRef = ref<HTMLElement | null | any>(null);
 
-// 创建emit函数,用于触发自定义事件
-const emit = defineEmits(['ok', 'update:visible', 'cancel'])
+  // 使用useDraggable钩子,获取拖拽相关属性
+  const { x, y, isDragging } = useDraggable(modalTitleRef);
 
-// 处理ok事件的函数
-const handleOk = (e: MouseEvent) => {
-  emit('ok')
-};
+  // 创建emit函数,用于触发自定义事件
+  const emit = defineEmits(['ok', 'update:visible', 'cancel']);
 
-// 处理cancel事件的函数
-const handleCancel = () => {
-  emit('update:visible', false)
-  emit('cancel')
-}
+  // 处理ok事件的函数
+  const handleOk = (e: MouseEvent) => {
+    emit('ok');
+  };
 
-// 创建各种响应式数据
-const startX = ref<number>(0); // 记录起始点的 x 坐标
-const startY = ref<number>(0); // 记录起始点的 y 坐标
-const startedDrag = ref(false); // 标志位,表示是否开始拖拽,默认为 false
-const transformX = ref(0); // x 偏移量
-const transformY = ref(0); // y 偏移量
-const preTransformX = ref(0); // 拖拽前的 x 偏移量
-const preTransformY = ref(0); // 拖拽前的 y 偏移量
-const dragRect = ref({ left: 0, right: 0, top: 0, bottom: 0 }); // 可拖拽的边界
+  // 处理cancel事件的函数
+  const handleCancel = () => {
+    emit('update:visible', false);
+    emit('cancel');
+  };
 
-// 监听x和y的变化
-watch([x, y], () => { // 监听鼠标移动事件的函数
-  if (!startedDrag.value) { // 如果尚未开始拖拽
-    startX.value = x.value; // 记录起始点的 x 坐标
-    startY.value = y.value; // 记录起始点的 y 坐标
-    const bodyRect = document.body.getBoundingClientRect(); // 获取页面 body 元素的边界信息
-    const titleRect = modalTitleRef.value.getBoundingClientRect(); // 获取 modalTitle 元素的边界信息
-    dragRect.value.right = bodyRect.width - titleRect.width; // 计算可拖拽的最大右边界
-    dragRect.value.bottom = bodyRect.height - titleRect.height; // 计算可拖拽的最大下边界
-    preTransformX.value = transformX.value; // 记录拖拽前的 x 偏移量
-    preTransformY.value = transformY.value; // 记录拖拽前的 y 偏移量
-  }
-  startedDrag.value = true; // 设置已开始拖拽标志
-});
+  // 创建各种响应式数据
+  const startX = ref<number>(0); // 记录起始点的 x 坐标
+  const startY = ref<number>(0); // 记录起始点的 y 坐标
+  const startedDrag = ref(false); // 标志位,表示是否开始拖拽,默认为 false
+  const transformX = ref(0); // x 偏移量
+  const transformY = ref(0); // y 偏移量
+  const preTransformX = ref(0); // 拖拽前的 x 偏移量
+  const preTransformY = ref(0); // 拖拽前的 y 偏移量
+  const dragRect = ref({ left: 0, right: 0, top: 0, bottom: 0 }); // 可拖拽的边界
 
-// 监听isDragging的变化
-watch(isDragging, () => { // 监听 isDragging 变量的改变
-  if (!isDragging) { // 如果 isDragging 变为 false
-    startedDrag.value = false; // 将 startedDrag.value 设置为 false,表示拖拽操作结束
-  }
-});
+  // 监听x和y的变化
+  watch([x, y], () => {
+    // 监听鼠标移动事件的函数
+    if (!startedDrag.value) {
+      // 如果尚未开始拖拽
+      startX.value = x.value; // 记录起始点的 x 坐标
+      startY.value = y.value; // 记录起始点的 y 坐标
+      const bodyRect = document.body.getBoundingClientRect(); // 获取页面 body 元素的边界信息
+      const titleRect = modalTitleRef.value.getBoundingClientRect(); // 获取 modalTitle 元素的边界信息
+      dragRect.value.right = bodyRect.width - titleRect.width; // 计算可拖拽的最大右边界
+      dragRect.value.bottom = bodyRect.height - titleRect.height; // 计算可拖拽的最大下边界
+      preTransformX.value = transformX.value; // 记录拖拽前的 x 偏移量
+      preTransformY.value = transformY.value; // 记录拖拽前的 y 偏移量
+    }
+    startedDrag.value = true; // 设置已开始拖拽标志
+  });
 
-// 使用watchEffect监听响应式数据的变化
-watchEffect(() => { // 响应 startedDrag.value 的变化
-  if (startedDrag.value) { // 如果 startedDrag.value 为 true,表示正在进行拖拽操作
-    transformX.value = // 计算 x 偏移量
-      preTransformX.value +
-      Math.min(Math.max(dragRect.value.left, x.value), dragRect.value.right) -
-      startX.value;
-    transformY.value = // 计算 y 偏移量
-      preTransformY.value +
-      Math.min(Math.max(dragRect.value.top, y.value), dragRect.value.bottom) -
-      startY.value;
-  }
-});
+  // 监听isDragging的变化
+  watch(isDragging, () => {
+    // 监听 isDragging 变量的改变
+    if (!isDragging) {
+      // 如果 isDragging 变为 false
+      startedDrag.value = false; // 将 startedDrag.value 设置为 false,表示拖拽操作结束
+    }
+  });
 
-// 计算transformStyle,用于动态设置对话框的位置
-const transformStyle = computed<CSSProperties>(() => {
-  return {
-    transform: `translate(${transformX.value}px, ${transformY.value}px)`,
-  };
-});
+  // 使用watchEffect监听响应式数据的变化
+  watchEffect(() => {
+    // 响应 startedDrag.value 的变化
+    if (startedDrag.value) {
+      // 如果 startedDrag.value 为 true,表示正在进行拖拽操作
+      transformX.value = preTransformX.value + Math.min(Math.max(dragRect.value.left, x.value), dragRect.value.right) - startX.value; // 计算 x 偏移量
+      transformY.value = preTransformY.value + Math.min(Math.max(dragRect.value.top, y.value), dragRect.value.bottom) - startY.value; // 计算 y 偏移量
+    }
+  });
 
+  // 计算transformStyle,用于动态设置对话框的位置
+  const transformStyle = computed<CSSProperties>(() => {
+    return {
+      transform: `translate(${transformX.value}px, ${transformY.value}px)`,
+    };
+  });
 </script>

+ 214 - 217
src/views/vent/monitorManager/airDoor/components/cameraModal.vue

@@ -16,180 +16,113 @@
 </template>
 
 <script setup lang="ts">
-import { onMounted, onUnmounted, ref, reactive, computed } from 'vue';
-import { useRouter } from 'vue-router';
-import Player, { I18N } from 'xgplayer';
-import ZH from 'xgplayer/es/lang/zh-cn';
-import HlsPlugin from 'xgplayer-hls';
-import FlvPlugin from 'xgplayer-flv';
-import 'xgplayer/dist/index.min.css';
-import { cameraAddr } from '../airdoor.api';
-let props = defineProps({
-  cameraData: {
-    type: Object,
-    default: () => {
-      return {}
-    }
-  }
-})
-
-const playerList = ref([]);
-let addrList = ref<{ name: string; addr: string; cameraRate: number; devicekind: string }[]>([]);
-const webRtcServerList = <any[]>[];
+  import { onMounted, onUnmounted, ref, reactive, computed } from 'vue';
+  import { useRouter } from 'vue-router';
+  import Player, { I18N } from 'xgplayer';
+  import ZH from 'xgplayer/es/lang/zh-cn';
+  import HlsPlugin from 'xgplayer-hls';
+  import FlvPlugin from 'xgplayer-flv';
+  import 'xgplayer/dist/index.min.css';
+  import { cameraAddr } from '../airdoor.api';
+  let props = defineProps({
+    cameraData: {
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
+  });
 
-async function getVideoAddrs() {
-  console.log(props.cameraData, 'camera---')
-  clearCamera();
-  playerList.value = [];
+  const playerList = ref([]);
+  let addrList = ref<{ name: string; addr: string; cameraRate: number; devicekind: string }[]>([]);
+  const webRtcServerList = <any[]>[];
 
+  async function getVideoAddrs() {
+    console.log(props.cameraData, 'camera---');
+    clearCamera();
+    playerList.value = [];
 
-  const cameraList = <{ name: string; addr: string; cameraRate: number; devicekind: string }[]>[];
-  const cameras = props.cameraData.cameras;
-  for (let i = 0; i < cameras.length; i++) {
-    const item = cameras[i];
-    if (item['devicekind'] === 'toHKRtsp' || item['devicekind'] === 'toHKHLs' || item['devicekind'] === 'HLL' || item['devicekind'] === 'YZG_URL') {
-      // 从海康平台接口获取视频流
-      const videoType = item['devicekind'] === 'toHKRtsp' ? 'rtsp' : '';
-      const devicekindType = item['devicekind'] === 'YZG_URL' ? 'YZG_URL' : ''
-      try {
-        const data = await cameraAddr({ devicekind: devicekindType, cameraCode: item['addr'], videoType });
-        if (data && data['url']) {
-          cameraList.push({ name: item['name'], addr: data['url'], cameraRate: item['cameraRate'], devicekind: item['devicekind'] });
+    const cameraList = <{ name: string; addr: string; cameraRate: number; devicekind: string }[]>[];
+    const cameras = props.cameraData.cameras;
+    for (let i = 0; i < cameras.length; i++) {
+      const item = cameras[i];
+      if (item['devicekind'] === 'toHKRtsp' || item['devicekind'] === 'toHKHLs' || item['devicekind'] === 'HLL' || item['devicekind'] === 'YZG_URL') {
+        // 从海康平台接口获取视频流
+        const videoType = item['devicekind'] === 'toHKRtsp' ? 'rtsp' : '';
+        const devicekindType = item['devicekind'] === 'YZG_URL' ? 'YZG_URL' : '';
+        try {
+          const data = await cameraAddr({ devicekind: devicekindType, cameraCode: item['addr'], videoType });
+          if (data && data['url']) {
+            cameraList.push({ name: item['name'], addr: data['url'], cameraRate: item['cameraRate'], devicekind: item['devicekind'] });
+          }
+        } catch (error) {}
+      } else {
+        if (item['addr'].includes('0.0.0.0')) {
+          item['addr'] = item['addr'].replace('0.0.0.0', window.location.hostname);
         }
-
-      } catch (error) { }
-    } else {
-      if (item['addr'].includes('0.0.0.0')) {
-        item['addr'] = item['addr'].replace('0.0.0.0', window.location.hostname);
+        cameraList.push({ name: item['name'], addr: item['addr'], cameraRate: item['cameraRate'], devicekind: item['devicekind'] });
       }
-      cameraList.push({ name: item['name'], addr: item['addr'], cameraRate: item['cameraRate'], devicekind: item['devicekind'] });
     }
+    addrList.value = cameraList;
+    console.log(addrList.value, ' addrList.value-------------');
   }
-  addrList.value = cameraList;
-  console.log(addrList.value, ' addrList.value-------------');
-
-}
 
-function getVideo() {
-  const ip = VUE_APP_URL.webRtcUrl;
-  for (let i = 0; i < addrList.value.length; i++) {
-    const item = addrList.value[i];
-    if (item.addr.startsWith('rtsp://')) {
-      const dom = document.getElementById('video' + i) as HTMLVideoElement;
-      dom.muted = true;
-      dom.volume = 0;
-      const webRtcServer = new window['WebRtcStreamer'](dom, location.protocol + ip);
-      webRtcServerList.push(webRtcServer);
-      webRtcServer.connect(item.addr);
-    } else {
-      setNoRtspVideo('player' + i, item.addr, item.cameraRate, item.devicekind);
+  function getVideo() {
+    const ip = VUE_APP_URL.webRtcUrl;
+    for (let i = 0; i < addrList.value.length; i++) {
+      const item = addrList.value[i];
+      if (item.addr.startsWith('rtsp://')) {
+        const dom = document.getElementById('video' + i) as HTMLVideoElement;
+        dom.muted = true;
+        dom.volume = 0;
+        const webRtcServer = new window['WebRtcStreamer'](dom, location.protocol + ip);
+        webRtcServerList.push(webRtcServer);
+        webRtcServer.connect(item.addr);
+      } else {
+        setNoRtspVideo('player' + i, item.addr, item.cameraRate, item.devicekind);
+      }
     }
   }
-}
-function clearCamera() {
-  const num = webRtcServerList.length;
-  for (let i = 0; i < num; i++) {
-    if (webRtcServerList[i]) {
-      webRtcServerList[i].disconnect();
-      webRtcServerList[i] = null;
+  function clearCamera() {
+    const num = webRtcServerList.length;
+    for (let i = 0; i < num; i++) {
+      if (webRtcServerList[i]) {
+        webRtcServerList[i].disconnect();
+        webRtcServerList[i] = null;
+      }
     }
+    for (let i = 0; i < playerList.value.length; i++) {
+      const player = playerList.value[i];
+      if (player.destroy) player.destroy();
+    }
+    playerList.value = [];
   }
-  for (let i = 0; i < playerList.value.length; i++) {
-    const player = playerList.value[i];
-    if (player.destroy) player.destroy();
-  }
-  playerList.value = [];
-}
 
-function setNoRtspVideo(id, videoAddr, cameraRate, devicekind) {
-  const fileExtension = videoAddr.split('.').pop();
-  if (fileExtension === 'flv' || devicekind == 'flv') {
-    const player = new Player({
-      lang: 'zh',
-      id: id,
-      url: videoAddr,
-      width: 589,
-      height: 330,
-      poster: '/src/assets/images/vent/noSinge.png',
-      plugins: [FlvPlugin],
-      fluid: true,
-      autoplay: true,
-      isLive: true,
-      playsinline: true,
-      screenShot: true,
-      whitelist: [''],
-      ignores: ['time', 'progress', 'play', 'i18n', 'volume', 'fullscreen', 'screenShot', 'playbackRate'],
-      closeVideoClick: true,
-      customConfig: {
-        isClickPlayBack: false,
-      },
-      defaultPlaybackRate: cameraRate || 1,
-      controls: false,
-      flv: {
-        retryCount: 3, // 重试 3 次,默认值
-        retryDelay: 1000, // 每次重试间隔 1 秒,默认值
-        loadTimeout: 10000, // 请求超时时间为 10 秒,默认值
-        fetchOptions: {
-          // 该参数会透传给 fetch,默认值为 undefined
-          mode: 'cors',
-        },
-        targetLatency: 10, // 直播目标延迟,默认 10 秒
-        maxLatency: 20, // 直播允许的最大延迟,默认 20 秒
-        disconnectTime: 10, // 直播断流时间,默认 0 秒,(独立使用时等于 maxLatency)
-        maxJumpDistance: 10,
-      },
-    });
-    playerList.value.push(player);
-  }
-  if (fileExtension === 'm3u8' || devicekind == 'm3u8') {
-    let player;
-    if (document.createElement('video').canPlayType('application/vnd.apple.mpegurl')) {
-      // 原生支持 hls 播放
-      player = new Player({
+  function setNoRtspVideo(id, videoAddr, cameraRate, devicekind) {
+    const fileExtension = videoAddr.split('.').pop();
+    if (fileExtension === 'flv' || devicekind == 'flv') {
+      const player = new Player({
         lang: 'zh',
         id: id,
         url: videoAddr,
-        width: 376,
-        height: 210,
-        isLive: true,
-        autoplay: true,
-        autoplayMuted: true,
-        cors: true,
-        ignores: ['time', 'progress', 'play', 'i18n', 'volume', 'fullscreen', 'screenShot', 'playbackRate'],
+        width: 589,
+        height: 330,
         poster: '/src/assets/images/vent/noSinge.png',
-        defaultPlaybackRate: cameraRate || 1,
-        controls: false,
-        hls: {
-          retryCount: 3, // 重试 3 次,默认值
-          retryDelay: 1000, // 每次重试间隔 1 秒,默认值
-          loadTimeout: 10000, // 请求超时时间为 10 秒,默认值
-          fetchOptions: {
-            // 该参数会透传给 fetch,默认值为 undefined
-            mode: 'cors',
-          },
-          targetLatency: 10, // 直播目标延迟,默认 10 秒
-          maxLatency: 20, // 直播允许的最大延迟,默认 20 秒
-          disconnectTime: 10, // 直播断流时间,默认 0 秒,(独立使用时等于 maxLatency)
-          maxJumpDistance: 10,
-        },
-      });
-    } else if (HlsPlugin.isSupported()) {
-      // 第一步
-      player = new Player({
-        lang: 'zh',
-        id: id,
-        url: videoAddr,
-        width: 376,
-        height: 210,
-        isLive: true,
+        plugins: [FlvPlugin],
+        fluid: true,
         autoplay: true,
-        autoplayMuted: true,
-        plugins: [HlsPlugin], // 第二步
-        poster: '/src/assets/images/vent/noSinge.png',
+        isLive: true,
+        playsinline: true,
+        screenShot: true,
+        whitelist: [''],
         ignores: ['time', 'progress', 'play', 'i18n', 'volume', 'fullscreen', 'screenShot', 'playbackRate'],
+        closeVideoClick: true,
+        customConfig: {
+          isClickPlayBack: false,
+        },
         defaultPlaybackRate: cameraRate || 1,
         controls: false,
-        hls: {
+        flv: {
           retryCount: 3, // 重试 3 次,默认值
           retryDelay: 1000, // 每次重试间隔 1 秒,默认值
           loadTimeout: 10000, // 请求超时时间为 10 秒,默认值
@@ -203,85 +136,149 @@ function setNoRtspVideo(id, videoAddr, cameraRate, devicekind) {
           maxJumpDistance: 10,
         },
       });
+      playerList.value.push(player);
+    }
+    if (fileExtension === 'm3u8' || devicekind == 'm3u8') {
+      let player;
+      if (document.createElement('video').canPlayType('application/vnd.apple.mpegurl')) {
+        // 原生支持 hls 播放
+        player = new Player({
+          lang: 'zh',
+          id: id,
+          url: videoAddr,
+          width: 376,
+          height: 210,
+          isLive: true,
+          autoplay: true,
+          autoplayMuted: true,
+          cors: true,
+          ignores: ['time', 'progress', 'play', 'i18n', 'volume', 'fullscreen', 'screenShot', 'playbackRate'],
+          poster: '/src/assets/images/vent/noSinge.png',
+          defaultPlaybackRate: cameraRate || 1,
+          controls: false,
+          hls: {
+            retryCount: 3, // 重试 3 次,默认值
+            retryDelay: 1000, // 每次重试间隔 1 秒,默认值
+            loadTimeout: 10000, // 请求超时时间为 10 秒,默认值
+            fetchOptions: {
+              // 该参数会透传给 fetch,默认值为 undefined
+              mode: 'cors',
+            },
+            targetLatency: 10, // 直播目标延迟,默认 10 秒
+            maxLatency: 20, // 直播允许的最大延迟,默认 20 秒
+            disconnectTime: 10, // 直播断流时间,默认 0 秒,(独立使用时等于 maxLatency)
+            maxJumpDistance: 10,
+          },
+        });
+      } else if (HlsPlugin.isSupported()) {
+        // 第一步
+        player = new Player({
+          lang: 'zh',
+          id: id,
+          url: videoAddr,
+          width: 376,
+          height: 210,
+          isLive: true,
+          autoplay: true,
+          autoplayMuted: true,
+          plugins: [HlsPlugin], // 第二步
+          poster: '/src/assets/images/vent/noSinge.png',
+          ignores: ['time', 'progress', 'play', 'i18n', 'volume', 'fullscreen', 'screenShot', 'playbackRate'],
+          defaultPlaybackRate: cameraRate || 1,
+          controls: false,
+          hls: {
+            retryCount: 3, // 重试 3 次,默认值
+            retryDelay: 1000, // 每次重试间隔 1 秒,默认值
+            loadTimeout: 10000, // 请求超时时间为 10 秒,默认值
+            fetchOptions: {
+              // 该参数会透传给 fetch,默认值为 undefined
+              mode: 'cors',
+            },
+            targetLatency: 10, // 直播目标延迟,默认 10 秒
+            maxLatency: 20, // 直播允许的最大延迟,默认 20 秒
+            disconnectTime: 10, // 直播断流时间,默认 0 秒,(独立使用时等于 maxLatency)
+            maxJumpDistance: 10,
+          },
+        });
+      }
+      playerList.value.push(player);
     }
-    playerList.value.push(player);
   }
-}
 
-function goFullScreen(domId) {
-  const videoDom = document.getElementById(domId) as HTMLVideoElement;
-  if (videoDom.requestFullscreen) {
-    videoDom.requestFullscreen();
-    videoDom.play();
-  } else if (videoDom.mozRequestFullscreen) {
-    videoDom.mozRequestFullscreen();
-    videoDom.play();
-  } else if (videoDom.webkitRequestFullscreen) {
-    videoDom.webkitRequestFullscreen();
-    videoDom.play();
-  } else if (videoDom.msRequestFullscreen) {
-    videoDom.msRequestFullscreen();
-    videoDom.play();
+  function goFullScreen(domId) {
+    const videoDom = document.getElementById(domId) as HTMLVideoElement;
+    if (videoDom.requestFullscreen) {
+      videoDom.requestFullscreen();
+      videoDom.play();
+    } else if (videoDom.mozRequestFullscreen) {
+      videoDom.mozRequestFullscreen();
+      videoDom.play();
+    } else if (videoDom.webkitRequestFullscreen) {
+      videoDom.webkitRequestFullscreen();
+      videoDom.play();
+    } else if (videoDom.msRequestFullscreen) {
+      videoDom.msRequestFullscreen();
+      videoDom.play();
+    }
   }
-}
 
-onMounted(async () => {
-  await getVideoAddrs();
-  getVideo();
-});
+  onMounted(async () => {
+    await getVideoAddrs();
+    getVideo();
+  });
 
-onUnmounted(() => {
-  clearCamera();
-});
+  onUnmounted(() => {
+    clearCamera();
+  });
 </script>
 
 <style lang="less" scoped>
-@import '/@/design/theme.less';
+  @import '/@/design/theme.less';
 
-@{theme-deepblue} {
-  .camera-modal {
-    --image-camera_bg: url('/@/assets/images/themify/deepblue/vent/camera_bg.png');
+  @{theme-deepblue} {
+    .camera-modal {
+      --image-camera_bg: url('/@/assets/images/themify/deepblue/vent/camera_bg.png');
+    }
   }
-}
 
-.camera-modal {
-  --image-camera_bg: url('/@/assets/images/vent/camera_bg.png');
-  display: flex;
-  justify-content: space-between;
-  flex-wrap: wrap;
+  .camera-modal {
+    --image-camera_bg: url('/@/assets/images/vent/camera_bg.png');
+    display: flex;
+    justify-content: space-between;
+    flex-wrap: wrap;
 
-  .player-box {
-    width: 400px;
-    height: 235px;
-    padding: 10px 12px;
-    background: var(--image-camera_bg);
-    background-size: 100% 100%;
-    position: relative;
-    margin: 10px;
+    .player-box {
+      width: 400px;
+      height: 235px;
+      padding: 10px 12px;
+      background: var(--image-camera_bg);
+      background-size: 100% 100%;
+      position: relative;
+      margin: 10px;
 
-    .player-name {
-      font-size: 14px;
-      position: absolute;
-      top: 12px;
-      right: 12px;
-      color: #fff;
-      background-color: hsla(0, 0%, 50%, 0.5);
-      border-radius: 2px;
-      padding: 1px 5px;
-      max-width: 120px;
-      overflow: hidden;
-      white-space: nowrap;
-      text-overflow: ellipsis;
-      z-index: 999;
-    }
+      .player-name {
+        font-size: 14px;
+        position: absolute;
+        top: 12px;
+        right: 12px;
+        color: #fff;
+        background-color: hsla(0, 0%, 50%, 0.5);
+        border-radius: 2px;
+        padding: 1px 5px;
+        max-width: 120px;
+        overflow: hidden;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+        z-index: 999;
+      }
 
-    .click-box {
-      position: absolute;
-      width: 100%;
-      height: 100%;
-      top: 0;
-      left: 0;
+      .click-box {
+        position: absolute;
+        width: 100%;
+        height: 100%;
+        top: 0;
+        left: 0;
+      }
     }
   }
-}
 </style>

+ 73 - 75
src/views/vent/monitorManager/airDoor/index.vue

@@ -3,97 +3,95 @@
     <customHeader>风门集中同控</customHeader>
     <div class="main-container">
       <div class="container-left">
-        <doorMenuL :menuData="menuData"></doorMenuL>
+        <doorMenuL :menuData="menuData" />
       </div>
       <div class="container-right">
-        <doorContentR :infoData="menuData" :visibleTs30="visibleTs30"></doorContentR>
+        <doorContentR :infoData="menuData" :visibleTs30="visibleTs30" />
       </div>
     </div>
   </div>
 </template>
 
 <script setup lang="ts">
-import { ref, onMounted } from 'vue'
-import customHeader from '/@/components/vent/customHeader.vue';
-import doorMenuL from './components/door-menu-l.vue'
-import doorContentR from './components/door-content-r.vue'
-import { getDevice, upcoming } from './airdoor.api'
+  import { ref, onMounted } from 'vue';
+  import customHeader from '/@/components/vent/customHeader.vue';
+  import doorMenuL from './components/door-menu-l.vue';
+  import doorContentR from './components/door-content-r.vue';
+  import { getDevice, upcoming } from './airdoor.api';
 
-let menuData = ref<any[]>([])
-//控制定时设置提示弹窗显示/隐藏
-let visibleTs30 = ref(false)
+  let menuData = ref<any[]>([]);
+  //控制定时设置提示弹窗显示/隐藏
+  let visibleTs30 = ref(false);
 
+  // https获取监测数据
+  let timer: null | NodeJS.Timeout = null;
+  function getMonitor(flag?) {
+    timer = setTimeout(
+      async () => {
+        //获取左侧菜单数据
+        await getMenuList();
+        await upcomingList();
+        getMonitor(false);
+      },
+      flag ? 0 : 5000
+    );
+  }
+  //左侧数据
+  async function getMenuList() {
+    let res = await getDevice({ devicetype: 'gate', pagetype: 'normal' });
+    console.log(res, 'menuList');
+    menuData.value = res.msgTxt[0].datalist || [];
+  }
+  async function upcomingList() {
+    visibleTs30.value = true;
+    // let res = await upcoming({})
+    // console.log(res, '定时30秒')
+    // if (res.length) {
+    //   visibleTs30.value = true
+    // } else {
+    //   visibleTs30.value = false
+    // }
+  }
 
-// https获取监测数据
-let timer: null | NodeJS.Timeout = null;
-function getMonitor(flag?) {
-  timer = setTimeout(
-    async () => {
-      //获取左侧菜单数据
-      await getMenuList()
-      await upcomingList()
-      getMonitor(false);
-    },
-    flag ? 0 : 5000
-  );
-}
-//左侧数据
-async function getMenuList() {
-  let res = await getDevice({ devicetype: "gate", pagetype: "normal" })
-  console.log(res, 'menuList')
-  menuData.value = res.msgTxt[0].datalist || []
-}
-async function upcomingList() {
-   visibleTs30.value = true
-  // let res = await upcoming({})
-  // console.log(res, '定时30秒')
-  // if (res.length) {
-  //   visibleTs30.value = true
-  // } else {
-  //   visibleTs30.value = false
-  // }
-}
-
-onMounted(() => {
-  getMenuList()
-  getMonitor()
-})
-
+  onMounted(() => {
+    getMenuList();
+    getMonitor();
+  });
 </script>
 
 <style lang="less" scoped>
-.air-door {
-  position: relative;
-  width: 100%;
-  height: 100%;
-
-  .main-container {
-    display: flex;
+  .air-door {
+    position: relative;
     width: 100%;
-    margin-top: 70px;
-    height: calc(100% - 70px);
-    padding: 10px;
-    box-sizing: border-box;
-  }
-
-  .container-left {
-    width: 260px;
     height: 100%;
-    padding: 10px 15px;
-    margin-right: 10px;
-    border: 1px solid #99e8ff66;
-    background: #27546e1a;
-    overflow-y: auto;
-    box-shadow: 0px 0px 20px 7px rgba(145, 233, 254, 0.7) inset;
-    -moz-box-shadow: 0px 0px 20px 7px rgba(145, 233, 254, 0.7) inset;
-    -webkit-box-shadow: 0px 0px 50px 1px rgb(149 235 255 / 5%) inset;
-  }
 
-  .container-right {
-    width: calc(100% - 275px);
-    height: 100%;
-    // padding: 10px;
-    // box-sizing: border-box;
+    .main-container {
+      display: flex;
+      width: 100%;
+      margin-top: 70px;
+      height: calc(100% - 70px);
+      padding: 10px;
+      box-sizing: border-box;
+    }
+
+    .container-left {
+      width: 260px;
+      height: 100%;
+      padding: 10px 15px;
+      margin-right: 10px;
+      border: 1px solid #99e8ff66;
+      background: #27546e1a;
+      overflow-y: auto;
+      box-shadow: 0px 0px 20px 7px rgba(145, 233, 254, 0.7) inset;
+      -moz-box-shadow: 0px 0px 20px 7px rgba(145, 233, 254, 0.7) inset;
+      -webkit-box-shadow: 0px 0px 50px 1px rgb(149 235 255 / 5%) inset;
+    }
+
+    .container-right {
+      width: calc(100% - 275px);
+      height: 100%;
+      // padding: 10px;
+      // box-sizing: border-box;
+    }
   }
-}
 </style>

+ 2 - 10
src/views/vent/monitorManager/camera/common/cameraTree.vue

@@ -1,11 +1,5 @@
 <template>
-  <treeList
-    v-for="model in list"
-    v-bind="$attrs"
-    :model="model"
-    :key="model.id"
-    @detail-node="onDetail"
-  >
+  <treeList v-for="model in list" v-bind="$attrs" :model="model" :key="model.id" @detail-node="onDetail">
     <template #icon="slotProps">
       <slot name="icon" v-bind="slotProps"></slot>
     </template>
@@ -17,7 +11,7 @@
 <script setup lang="ts">
   import { ref } from 'vue';
   import treeList from './treeList.vue';
-  const emit = defineEmits([ 'detailNode']);
+  const emit = defineEmits(['detailNode']);
   interface IFileSystem {
     id: string;
     title: string;
@@ -57,7 +51,5 @@
       eventType: 'detail',
     });
   };
- 
-  
 </script>
 <style scoped></style>

+ 430 - 420
src/views/vent/monitorManager/camera/index.vue

@@ -40,336 +40,282 @@
   </div>
 </template>
 <script lang="ts" setup>
-import { onMounted, onUnmounted, ref, reactive, computed } from 'vue';
-import { useRouter } from 'vue-router';
-import { Pagination, Empty } from 'ant-design-vue';
-import { list, cameraAddr, getCameraDevKind, getDevice, getVentanalyCamera } from './camera.api';
-import Player, { I18N } from 'xgplayer';
-import ZH from 'xgplayer/es/lang/zh-cn';
-import HlsPlugin from 'xgplayer-hls';
-import FlvPlugin from 'xgplayer-flv';
-import 'xgplayer/dist/index.min.css';
-import cameraTree from './common/cameraTree.vue';
-import { SvgIcon } from '/@/components/Icon';
-import treeIcon from './common/Icon/treeIcon.vue';
+  import { onMounted, onUnmounted, ref, reactive, computed } from 'vue';
+  import { useRouter } from 'vue-router';
+  import { Pagination, Empty } from 'ant-design-vue';
+  import { list, cameraAddr, getCameraDevKind, getDevice, getVentanalyCamera } from './camera.api';
+  import Player, { I18N } from 'xgplayer';
+  import ZH from 'xgplayer/es/lang/zh-cn';
+  import HlsPlugin from 'xgplayer-hls';
+  import FlvPlugin from 'xgplayer-flv';
+  import 'xgplayer/dist/index.min.css';
+  import cameraTree from './common/cameraTree.vue';
+  import { SvgIcon } from '/@/components/Icon';
+  import treeIcon from './common/Icon/treeIcon.vue';
 
-//当前选中树节点
-let selected = reactive<any>({
-  id: null,
-  pid: null,
-  title: '',
-  isFolder: false,
-});
-//tree菜单列表
-let listArr = reactive<any[]>([]);
-let searchParam = reactive({
-  devKind: '',
-  strType: '',
-});
+  //当前选中树节点
+  let selected = reactive<any>({
+    id: null,
+    pid: null,
+    title: '',
+    isFolder: false,
+  });
+  //tree菜单列表
+  let listArr = reactive<any[]>([]);
+  let searchParam = reactive({
+    devKind: '',
+    strType: '',
+  });
 
-I18N.use(ZH);
-let router = useRouter(); //路由
-const pageSize = ref(4);
-const current = ref(1);
-const total = ref(0);
-const playerList = ref([]);
-const webRtcServerList = <any[]>[];
-let addrList = ref<{ name: string; addr: string; cameraRate: number; devicekind: string }[]>([]);
-async function getCameraDevKindList() {
-  let res = await getCameraDevKind();
-  if (res.length != 0) {
-    listArr.length = 0;
-    listArr.push({
-      pid: 'root',
-      isFolder: true,
-      expanded: true,
-      title: '全部',
-      id: 0,
-      children: [],
-    });
-    res.forEach((el) => {
-      el.pid = 0;
-      el.isFolder = true;
-      el.expanded = false;
-      el.title = el.itemText;
-      el.id = el.subDictId;
-      el.children = [];
-      listArr[0].children.push(el);
-    });
-    selected.id = listArr[0].id;
-    selected.pid = listArr[0].pid;
-    selected.title = listArr[0].title;
-    selected.isFolder = listArr[0].isFolder;
+  I18N.use(ZH);
+  let router = useRouter(); //路由
+  const pageSize = ref(4);
+  const current = ref(1);
+  const total = ref(0);
+  const playerList = ref([]);
+  const webRtcServerList = <any[]>[];
+  let addrList = ref<{ name: string; addr: string; cameraRate: number; devicekind: string }[]>([]);
+  async function getCameraDevKindList() {
+    let res = await getCameraDevKind();
+    if (res.length != 0) {
+      listArr.length = 0;
+      listArr.push({
+        pid: 'root',
+        isFolder: true,
+        expanded: true,
+        title: '全部',
+        id: 0,
+        children: [],
+      });
+      res.forEach((el) => {
+        el.pid = 0;
+        el.isFolder = true;
+        el.expanded = false;
+        el.title = el.itemText;
+        el.id = el.subDictId;
+        el.children = [];
+        listArr[0].children.push(el);
+      });
+      selected.id = listArr[0].id;
+      selected.pid = listArr[0].pid;
+      selected.title = listArr[0].title;
+      selected.isFolder = listArr[0].isFolder;
+    }
   }
-}
 
-//点击目录
-async function onClick(node) {
-  if (selected.title === node.title && selected.id === node.id) return;
-  current.value = 1;
-  selected.id = node.id;
-  selected.pid = node.pid;
-  selected.title = node.title;
-  selected.isFolder = node.isFolder;
-  if (node.pid != 'root') {
-    if (node.isFolder) {
-      let types, devicetype;
-      if (node.itemValue.indexOf('&') != -1) {
-        types = node.itemValue.substring(node.itemValue.indexOf('&') + 1);
-        devicetype = node.itemValue.substring(0, node.itemValue.indexOf('&'));
+  //点击目录
+  async function onClick(node) {
+    if (selected.title === node.title && selected.id === node.id) return;
+    current.value = 1;
+    selected.id = node.id;
+    selected.pid = node.pid;
+    selected.title = node.title;
+    selected.isFolder = node.isFolder;
+    if (node.pid != 'root') {
+      if (node.isFolder) {
+        let types, devicetype;
+        if (node.itemValue.indexOf('&') != -1) {
+          types = node.itemValue.substring(node.itemValue.indexOf('&') + 1);
+          devicetype = node.itemValue.substring(0, node.itemValue.indexOf('&'));
+        } else {
+          types = '';
+          devicetype = '';
+        }
+        let res = await getDevice({ ids: types, devicetype: devicetype });
+        if (res.msgTxt.length != 0) {
+          res.msgTxt[0].datalist.forEach((el) => {
+            el.pid = node.id;
+            el.isFolder = false;
+            el.title = el.strinstallpos;
+            el.id = el.deviceID;
+          });
+          listArr[0].children.forEach((v) => {
+            if (v.id == node.id) {
+              v.children = res.msgTxt[0].datalist;
+            }
+          });
+        }
+        searchParam.devKind = node.itemValue;
+        searchParam.strType = '';
+        await getVideoAddrs();
+        getVideo();
       } else {
-        types = '';
-        devicetype = '';
+        await getVideoAddrsSon(node.deviceID);
+        getVideo();
       }
-      let res = await getDevice({ ids: types, devicetype: devicetype });
-      if (res.msgTxt.length != 0) {
-        res.msgTxt[0].datalist.forEach((el) => {
-          el.pid = node.id;
-          el.isFolder = false;
-          el.title = el.strinstallpos;
-          el.id = el.deviceID;
-        });
-        listArr[0].children.forEach((v) => {
-          if (v.id == node.id) {
-            v.children = res.msgTxt[0].datalist;
-          }
-        });
-      }
-      searchParam.devKind = node.itemValue;
+    } else {
+      searchParam.devKind = '';
       searchParam.strType = '';
       await getVideoAddrs();
       getVideo();
-    } else {
-      await getVideoAddrsSon(node.deviceID);
-      getVideo();
     }
-  } else {
-    searchParam.devKind = '';
-    searchParam.strType = '';
-    await getVideoAddrs();
-    getVideo();
   }
-}
 
-//点击详情跳转
-function onDetail(node) {
-  let str = listArr[0].children.filter((v) => v.id == node.pid)[0].itemValue;
-  let type = str.indexOf('&') != -1 ? str.substring(0, str.indexOf('&')) : '';
-  console.log(type, 'type--------');
-  switch (type) {
-    case 'pulping': //注浆
-      router.push('/grout-home');
-      break;
-    case 'window': //自动风窗
-      router.push('/monitorChannel/monitor-window?id=' + node.deviceID);
-      break;
-    case 'gate': //自动风门
-      router.push('/monitorChannel/monitor-gate?id=' + node.deviceID + '&deviceType=' + node.deviceType);
-      break;
-    case 'fanlocal': //局部风机
-      router.push('/monitorChannel/monitor-fanlocal?id=' + node.deviceID + '&deviceType=fanlocal');
-      break;
-    case 'fanmain': //主风机
-      router.push('/monitorChannel/monitor-fanmain?id=' + node.deviceID);
-      break;
-    case 'forcFan': //压风机
-      router.push('/forcFan/home');
-      break;
-    case 'pump': //瓦斯抽采泵
-      router.push('/monitorChannel/gasPump-home');
-      break;
-    case 'nitrogen': //制氮
-      router.push('/nitrogen-home');
-      break;
+  //点击详情跳转
+  function onDetail(node) {
+    let str = listArr[0].children.filter((v) => v.id == node.pid)[0].itemValue;
+    let type = str.indexOf('&') != -1 ? str.substring(0, str.indexOf('&')) : '';
+    console.log(type, 'type--------');
+    switch (type) {
+      case 'pulping': //注浆
+        router.push('/grout-home');
+        break;
+      case 'window': //自动风窗
+        router.push('/monitorChannel/monitor-window?id=' + node.deviceID);
+        break;
+      case 'gate': //自动风门
+        router.push('/monitorChannel/monitor-gate?id=' + node.deviceID + '&deviceType=' + node.deviceType);
+        break;
+      case 'fanlocal': //局部风机
+        router.push('/monitorChannel/monitor-fanlocal?id=' + node.deviceID + '&deviceType=fanlocal');
+        break;
+      case 'fanmain': //主风机
+        router.push('/monitorChannel/monitor-fanmain?id=' + node.deviceID);
+        break;
+      case 'forcFan': //压风机
+        router.push('/forcFan/home');
+        break;
+      case 'pump': //瓦斯抽采泵
+        router.push('/monitorChannel/gasPump-home');
+        break;
+      case 'nitrogen': //制氮
+        router.push('/nitrogen-home');
+        break;
+    }
   }
-}
 
-async function getVideoAddrs() {
-  clearCamera();
-  playerList.value = [];
-  let paramKind = searchParam.devKind.substring(0, searchParam.devKind.indexOf('&'));
-  let res = await list({ devKind: paramKind, strType: searchParam.strType, pageSize: pageSize.value, pageNo: current.value });
-  total.value = res['total'] || 0;
-  if (res.records.length != 0) {
-    const cameraList = <{ name: string; addr: string; cameraRate: number; devicekind: string }[]>[];
-    const cameras = res.records;
-    for (let i = 0; i < cameras.length; i++) {
-      const item = cameras[i];
-      if (item['devicekind'] === 'toHKRtsp' || item['devicekind'] === 'toHKHLs' || item['devicekind'] === 'HLL' || item['devicekind'] === 'YZG_URL') {
-        // 从海康平台接口获取视频流
-        const videoType = item['devicekind'] === 'toHKRtsp' ? 'rtsp' : '';
-        const devicekindType = item['devicekind'] === 'YZG_URL' ? 'YZG_URL' : ''
-        try {
-          const data = await cameraAddr({ devicekind: devicekindType, cameraCode: item['addr'], videoType });
-          if (data && data['url']) {
-            cameraList.push({ name: item['name'], addr: data['url'], cameraRate: item['cameraRate'], devicekind: item['devicekind'] });
+  async function getVideoAddrs() {
+    clearCamera();
+    playerList.value = [];
+    let paramKind = searchParam.devKind.substring(0, searchParam.devKind.indexOf('&'));
+    let res = await list({ devKind: paramKind, strType: searchParam.strType, pageSize: pageSize.value, pageNo: current.value });
+    total.value = res['total'] || 0;
+    if (res.records.length != 0) {
+      const cameraList = <{ name: string; addr: string; cameraRate: number; devicekind: string }[]>[];
+      const cameras = res.records;
+      for (let i = 0; i < cameras.length; i++) {
+        const item = cameras[i];
+        if (
+          item['devicekind'] === 'toHKRtsp' ||
+          item['devicekind'] === 'toHKHLs' ||
+          item['devicekind'] === 'HLL' ||
+          item['devicekind'] === 'YZG_URL'
+        ) {
+          // 从海康平台接口获取视频流
+          const videoType = item['devicekind'] === 'toHKRtsp' ? 'rtsp' : '';
+          const devicekindType = item['devicekind'] === 'YZG_URL' ? 'YZG_URL' : '';
+          try {
+            const data = await cameraAddr({ devicekind: devicekindType, cameraCode: item['addr'], videoType });
+            if (data && data['url']) {
+              cameraList.push({ name: item['name'], addr: data['url'], cameraRate: item['cameraRate'], devicekind: item['devicekind'] });
+            }
+            // cameraList.push({
+            //   name: item['name'],
+            //   // addr: 'http://219.151.31.38/liveplay-kk.rtxapp.com/live/program/live/hnwshd/4000000/mnf.m3u8'
+            //   addr: 'https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.mp4/.m3u8',
+            // });
+          } catch (error) {}
+        } else {
+          if (item['addr'].includes('0.0.0.0')) {
+            item['addr'] = item['addr'].replace('0.0.0.0', window.location.hostname);
           }
-          // cameraList.push({
-          //   name: item['name'],
-          //   // addr: 'http://219.151.31.38/liveplay-kk.rtxapp.com/live/program/live/hnwshd/4000000/mnf.m3u8'
-          //   addr: 'https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.mp4/.m3u8',
-          // });
-        } catch (error) { }
-      } else {
-        if (item['addr'].includes('0.0.0.0')) {
-          item['addr'] = item['addr'].replace('0.0.0.0', window.location.hostname);
+          cameraList.push({ name: item['name'], addr: item['addr'], cameraRate: item['cameraRate'], devicekind: item['devicekind'] });
         }
-        cameraList.push({ name: item['name'], addr: item['addr'], cameraRate: item['cameraRate'], devicekind: item['devicekind'] });
       }
+      addrList.value = cameraList;
+      console.log(addrList.value, ' addrList.value-------------');
     }
-    addrList.value = cameraList;
-    console.log(addrList.value, ' addrList.value-------------');
   }
-}
 
-async function getVideoAddrsSon(Id) {
-  clearCamera();
-  playerList.value = [];
-  let res = await getVentanalyCamera({ deviceid: Id });
-  if (res.records.length != 0) {
-    const cameraList = <{ name: string; addr: string; cameraRate: number; devicekind: string }[]>[];
-    const cameras = res.records;
-    for (let i = 0; i < cameras.length; i++) {
-      const item = cameras[i];
+  async function getVideoAddrsSon(Id) {
+    clearCamera();
+    playerList.value = [];
+    let res = await getVentanalyCamera({ deviceid: Id });
+    if (res.records.length != 0) {
+      const cameraList = <{ name: string; addr: string; cameraRate: number; devicekind: string }[]>[];
+      const cameras = res.records;
+      for (let i = 0; i < cameras.length; i++) {
+        const item = cameras[i];
 
-      if (item['devicekind'] === 'toHKRtsp' || item['devicekind'] === 'toHKHLs' || item['devicekind'] === 'HLL' || item['devicekind'] === 'YZG_URL') {
-        // 从海康平台接口获取视频流
-        const videoType = item['devicekind'] === 'toHKRtsp' ? 'rtsp' : '';
-        const devicekindType = item['devicekind'] === 'YZG_URL' ? 'YZG_URL' : ''
-        try {
-          const data = await cameraAddr({ devicekind: devicekindType, cameraCode: item['addr'], videoType });
-          if (data && data['url']) {
-            cameraList.push({ name: item['name'], addr: data['url'], cameraRate: item['cameraRate'], devicekind: item['devicekind'] });
+        if (
+          item['devicekind'] === 'toHKRtsp' ||
+          item['devicekind'] === 'toHKHLs' ||
+          item['devicekind'] === 'HLL' ||
+          item['devicekind'] === 'YZG_URL'
+        ) {
+          // 从海康平台接口获取视频流
+          const videoType = item['devicekind'] === 'toHKRtsp' ? 'rtsp' : '';
+          const devicekindType = item['devicekind'] === 'YZG_URL' ? 'YZG_URL' : '';
+          try {
+            const data = await cameraAddr({ devicekind: devicekindType, cameraCode: item['addr'], videoType });
+            if (data && data['url']) {
+              cameraList.push({ name: item['name'], addr: data['url'], cameraRate: item['cameraRate'], devicekind: item['devicekind'] });
+            }
+            // cameraList.push({
+            //   name: item['name'],
+            //   // addr: 'http://219.151.31.38/liveplay-kk.rtxapp.com/live/program/live/hnwshd/4000000/mnf.m3u8'
+            //   addr: 'https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.mp4/.m3u8',
+            // });
+          } catch (error) {}
+        } else {
+          if (item['addr'].includes('0.0.0.0')) {
+            item['addr'] = item['addr'].replace('0.0.0.0', window.location.hostname);
           }
-          // cameraList.push({
-          //   name: item['name'],
-          //   // addr: 'http://219.151.31.38/liveplay-kk.rtxapp.com/live/program/live/hnwshd/4000000/mnf.m3u8'
-          //   addr: 'https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.mp4/.m3u8',
-          // });
-        } catch (error) { }
-      } else {
-        if (item['addr'].includes('0.0.0.0')) {
-          item['addr'] = item['addr'].replace('0.0.0.0', window.location.hostname);
+          cameraList.push({ name: item['name'], addr: item['addr'], cameraRate: item['cameraRate'], devicekind: item['devicekind'] });
         }
-        cameraList.push({ name: item['name'], addr: item['addr'], cameraRate: item['cameraRate'], devicekind: item['devicekind'] });
       }
+      addrList.value = cameraList;
     }
-    addrList.value = cameraList;
   }
-}
 
-async function onChange(page) {
-  current.value = page;
-  await getVideoAddrs();
-  getVideo();
-}
+  async function onChange(page) {
+    current.value = page;
+    await getVideoAddrs();
+    getVideo();
+  }
 
-function getVideo() {
-  const ip = VUE_APP_URL.webRtcUrl;
-  for (let i = 0; i < addrList.value.length; i++) {
-    const item = addrList.value[i];
-    if (item.addr.startsWith('rtsp://')) {
-      const dom = document.getElementById('video' + i) as HTMLVideoElement;
-      dom.muted = true;
-      dom.volume = 0;
-      const webRtcServer = new window['WebRtcStreamer'](dom, location.protocol + ip);
-      webRtcServerList.push(webRtcServer);
-      webRtcServer.connect(item.addr);
-    } else {
-      setNoRtspVideo('player' + i, item.addr, item.cameraRate, item.devicekind);
+  function getVideo() {
+    const ip = VUE_APP_URL.webRtcUrl;
+    for (let i = 0; i < addrList.value.length; i++) {
+      const item = addrList.value[i];
+      if (item.addr.startsWith('rtsp://')) {
+        const dom = document.getElementById('video' + i) as HTMLVideoElement;
+        dom.muted = true;
+        dom.volume = 0;
+        const webRtcServer = new window['WebRtcStreamer'](dom, location.protocol + ip);
+        webRtcServerList.push(webRtcServer);
+        webRtcServer.connect(item.addr);
+      } else {
+        setNoRtspVideo('player' + i, item.addr, item.cameraRate, item.devicekind);
+      }
     }
   }
-}
 
-function setNoRtspVideo(id, videoAddr, cameraRate, devicekind) {
-  const fileExtension = videoAddr.split('.').pop();
-  if (fileExtension === 'flv' || devicekind == 'flv') {
-    const player = new Player({
-      lang: 'zh',
-      id: id,
-      url: videoAddr,
-      width: 589,
-      height: 330,
-      poster: '/src/assets/images/vent/noSinge.png',
-      plugins: [FlvPlugin],
-      fluid: true,
-      autoplay: true,
-      isLive: true,
-      playsinline: true,
-      screenShot: true,
-      whitelist: [''],
-      ignores: ['time', 'progress', 'play', 'i18n', 'volume', 'fullscreen', 'screenShot', 'playbackRate'],
-      closeVideoClick: true,
-      customConfig: {
-        isClickPlayBack: false,
-      },
-      defaultPlaybackRate: cameraRate || 1,
-      controls: false,
-      flv: {
-        retryCount: 3, // 重试 3 次,默认值
-        retryDelay: 1000, // 每次重试间隔 1 秒,默认值
-        loadTimeout: 10000, // 请求超时时间为 10 秒,默认值
-        fetchOptions: {
-          // 该参数会透传给 fetch,默认值为 undefined
-          mode: 'cors',
-        },
-        targetLatency: 10, // 直播目标延迟,默认 10 秒
-        maxLatency: 20, // 直播允许的最大延迟,默认 20 秒
-        disconnectTime: 10, // 直播断流时间,默认 0 秒,(独立使用时等于 maxLatency)
-        maxJumpDistance: 10,
-      },
-    });
-    playerList.value.push(player);
-  }
-  if (fileExtension === 'm3u8' || devicekind == 'm3u8') {
-    let player;
-    if (document.createElement('video').canPlayType('application/vnd.apple.mpegurl')) {
-      // 原生支持 hls 播放
-      player = new Player({
+  function setNoRtspVideo(id, videoAddr, cameraRate, devicekind) {
+    const fileExtension = videoAddr.split('.').pop();
+    if (fileExtension === 'flv' || devicekind == 'flv') {
+      const player = new Player({
         lang: 'zh',
         id: id,
         url: videoAddr,
         width: 589,
         height: 330,
-        isLive: true,
-        autoplay: true,
-        autoplayMuted: true,
-        cors: true,
-        ignores: ['time', 'progress', 'play', 'i18n', 'volume', 'fullscreen', 'screenShot', 'playbackRate'],
         poster: '/src/assets/images/vent/noSinge.png',
-        defaultPlaybackRate: cameraRate || 1,
-        controls: false,
-        hls: {
-          retryCount: 3, // 重试 3 次,默认值
-          retryDelay: 1000, // 每次重试间隔 1 秒,默认值
-          loadTimeout: 10000, // 请求超时时间为 10 秒,默认值
-          fetchOptions: {
-            // 该参数会透传给 fetch,默认值为 undefined
-            mode: 'cors',
-          },
-          targetLatency: 10, // 直播目标延迟,默认 10 秒
-          maxLatency: 20, // 直播允许的最大延迟,默认 20 秒
-          disconnectTime: 10, // 直播断流时间,默认 0 秒,(独立使用时等于 maxLatency)
-          maxJumpDistance: 10,
-        },
-      });
-    } else if (HlsPlugin.isSupported()) {
-      // 第一步
-      player = new Player({
-        lang: 'zh',
-        id: id,
-        url: videoAddr,
-        width: 589,
-        height: 330,
-        isLive: true,
+        plugins: [FlvPlugin],
+        fluid: true,
         autoplay: true,
-        autoplayMuted: true,
-        plugins: [HlsPlugin], // 第二步
-        poster: '/src/assets/images/vent/noSinge.png',
+        isLive: true,
+        playsinline: true,
+        screenShot: true,
+        whitelist: [''],
         ignores: ['time', 'progress', 'play', 'i18n', 'volume', 'fullscreen', 'screenShot', 'playbackRate'],
+        closeVideoClick: true,
+        customConfig: {
+          isClickPlayBack: false,
+        },
         defaultPlaybackRate: cameraRate || 1,
         controls: false,
-        hls: {
+        flv: {
           retryCount: 3, // 重试 3 次,默认值
           retryDelay: 1000, // 每次重试间隔 1 秒,默认值
           loadTimeout: 10000, // 请求超时时间为 10 秒,默认值
@@ -383,164 +329,228 @@ function setNoRtspVideo(id, videoAddr, cameraRate, devicekind) {
           maxJumpDistance: 10,
         },
       });
+      playerList.value.push(player);
+    }
+    if (fileExtension === 'm3u8' || devicekind == 'm3u8') {
+      let player;
+      if (document.createElement('video').canPlayType('application/vnd.apple.mpegurl')) {
+        // 原生支持 hls 播放
+        player = new Player({
+          lang: 'zh',
+          id: id,
+          url: videoAddr,
+          width: 589,
+          height: 330,
+          isLive: true,
+          autoplay: true,
+          autoplayMuted: true,
+          cors: true,
+          ignores: ['time', 'progress', 'play', 'i18n', 'volume', 'fullscreen', 'screenShot', 'playbackRate'],
+          poster: '/src/assets/images/vent/noSinge.png',
+          defaultPlaybackRate: cameraRate || 1,
+          controls: false,
+          hls: {
+            retryCount: 3, // 重试 3 次,默认值
+            retryDelay: 1000, // 每次重试间隔 1 秒,默认值
+            loadTimeout: 10000, // 请求超时时间为 10 秒,默认值
+            fetchOptions: {
+              // 该参数会透传给 fetch,默认值为 undefined
+              mode: 'cors',
+            },
+            targetLatency: 10, // 直播目标延迟,默认 10 秒
+            maxLatency: 20, // 直播允许的最大延迟,默认 20 秒
+            disconnectTime: 10, // 直播断流时间,默认 0 秒,(独立使用时等于 maxLatency)
+            maxJumpDistance: 10,
+          },
+        });
+      } else if (HlsPlugin.isSupported()) {
+        // 第一步
+        player = new Player({
+          lang: 'zh',
+          id: id,
+          url: videoAddr,
+          width: 589,
+          height: 330,
+          isLive: true,
+          autoplay: true,
+          autoplayMuted: true,
+          plugins: [HlsPlugin], // 第二步
+          poster: '/src/assets/images/vent/noSinge.png',
+          ignores: ['time', 'progress', 'play', 'i18n', 'volume', 'fullscreen', 'screenShot', 'playbackRate'],
+          defaultPlaybackRate: cameraRate || 1,
+          controls: false,
+          hls: {
+            retryCount: 3, // 重试 3 次,默认值
+            retryDelay: 1000, // 每次重试间隔 1 秒,默认值
+            loadTimeout: 10000, // 请求超时时间为 10 秒,默认值
+            fetchOptions: {
+              // 该参数会透传给 fetch,默认值为 undefined
+              mode: 'cors',
+            },
+            targetLatency: 10, // 直播目标延迟,默认 10 秒
+            maxLatency: 20, // 直播允许的最大延迟,默认 20 秒
+            disconnectTime: 10, // 直播断流时间,默认 0 秒,(独立使用时等于 maxLatency)
+            maxJumpDistance: 10,
+          },
+        });
+      }
+      playerList.value.push(player);
     }
-    playerList.value.push(player);
   }
-}
 
-function goFullScreen(domId) {
-  const videoDom = document.getElementById(domId) as HTMLVideoElement;
-  if (videoDom.requestFullscreen) {
-    videoDom.requestFullscreen();
-    videoDom.play();
-  } else if (videoDom.mozRequestFullscreen) {
-    videoDom.mozRequestFullscreen();
-    videoDom.play();
-  } else if (videoDom.webkitRequestFullscreen) {
-    videoDom.webkitRequestFullscreen();
-    videoDom.play();
-  } else if (videoDom.msRequestFullscreen) {
-    videoDom.msRequestFullscreen();
-    videoDom.play();
+  function goFullScreen(domId) {
+    const videoDom = document.getElementById(domId) as HTMLVideoElement;
+    if (videoDom.requestFullscreen) {
+      videoDom.requestFullscreen();
+      videoDom.play();
+    } else if (videoDom.mozRequestFullscreen) {
+      videoDom.mozRequestFullscreen();
+      videoDom.play();
+    } else if (videoDom.webkitRequestFullscreen) {
+      videoDom.webkitRequestFullscreen();
+      videoDom.play();
+    } else if (videoDom.msRequestFullscreen) {
+      videoDom.msRequestFullscreen();
+      videoDom.play();
+    }
   }
-}
 
-function clearCamera() {
-  const num = webRtcServerList.length;
-  for (let i = 0; i < num; i++) {
-    if (webRtcServerList[i]) {
-      webRtcServerList[i].disconnect();
-      webRtcServerList[i] = null;
+  function clearCamera() {
+    const num = webRtcServerList.length;
+    for (let i = 0; i < num; i++) {
+      if (webRtcServerList[i]) {
+        webRtcServerList[i].disconnect();
+        webRtcServerList[i] = null;
+      }
     }
+    for (let i = 0; i < playerList.value.length; i++) {
+      const player = playerList.value[i];
+      if (player.destroy) player.destroy();
+    }
+    playerList.value = [];
   }
-  for (let i = 0; i < playerList.value.length; i++) {
-    const player = playerList.value[i];
-    if (player.destroy) player.destroy();
-  }
-  playerList.value = [];
-}
 
-onMounted(async () => {
-  await getCameraDevKindList();
-  await getVideoAddrs();
-  getVideo();
-});
+  onMounted(async () => {
+    await getCameraDevKindList();
+    await getVideoAddrs();
+    getVideo();
+  });
 
-onUnmounted(() => {
-  clearCamera();
-});
+  onUnmounted(() => {
+    clearCamera();
+  });
 </script>
 <style lang="less">
-@import '/@/design/theme.less';
+  @import '/@/design/theme.less';
 
-@{theme-deepblue} {
-  .camera-container {
-    --image-camera_bg: url('/@/assets/images/themify/deepblue/vent/camera_bg.png');
+  @{theme-deepblue} {
+    .camera-container {
+      --image-camera_bg: url('/@/assets/images/themify/deepblue/vent/camera_bg.png');
+    }
   }
-}
 
-.camera-container {
-  --image-camera_bg: url('/@/assets/images/vent/camera_bg.png');
-  position: relative;
-  width: calc(100% - 30px);
-  height: calc(100% - 84px);
-  display: flex;
-  margin: 15px;
-  justify-content: space-between;
-  align-items: center;
+  .camera-container {
+    --image-camera_bg: url('/@/assets/images/vent/camera_bg.png');
+    position: relative;
+    width: calc(100% - 30px);
+    height: calc(100% - 84px);
+    display: flex;
+    margin: 15px;
+    justify-content: space-between;
+    align-items: center;
 
-  .left-area {
-    width: 15%;
-    height: 100%;
-    padding: 20px;
-    border: 1px solid #99e8ff66;
-    background: #27546e1a;
-    box-shadow: 0px 0px 20px 7px rgba(145, 233, 254, 0.7) inset;
-    -moz-box-shadow: 0px 0px 20px 7px rgba(145, 233, 254, 0.7) inset;
-    -webkit-box-shadow: 0px 0px 50px 1px rgb(149 235 255 / 5%) inset;
-    box-sizing: border-box;
+    .left-area {
+      width: 15%;
+      height: 100%;
+      padding: 20px;
+      border: 1px solid #99e8ff66;
+      background: #27546e1a;
+      box-shadow: 0px 0px 20px 7px rgba(145, 233, 254, 0.7) inset;
+      -moz-box-shadow: 0px 0px 20px 7px rgba(145, 233, 254, 0.7) inset;
+      -webkit-box-shadow: 0px 0px 50px 1px rgb(149 235 255 / 5%) inset;
+      box-sizing: border-box;
 
-    // lxh
-    .iconfont {
-      color: #fff;
-      font-size: 12px;
-      margin-left: 5px;
+      // lxh
+      .iconfont {
+        color: #fff;
+        font-size: 12px;
+        margin-left: 5px;
+      }
     }
-  }
 
-  .right-area {
-    width: 85%;
-    height: 100%;
-    padding: 0px 0px 0px 15px;
-    box-sizing: border-box;
+    .right-area {
+      width: 85%;
+      height: 100%;
+      padding: 0px 0px 0px 15px;
+      box-sizing: border-box;
 
-    .camera-box {
-      width: 100%;
-      height: calc(100% - 60px);
-      display: flex;
-      justify-content: space-around;
-      align-items: flex-start;
-      flex-wrap: wrap;
-      overflow-y: auto;
-    }
+      .camera-box {
+        width: 100%;
+        height: calc(100% - 60px);
+        display: flex;
+        justify-content: space-around;
+        align-items: flex-start;
+        flex-wrap: wrap;
+        overflow-y: auto;
+      }
 
-    .camera-box1 {
-      width: 100%;
-      height: calc(100% - 60px);
-      display: flex;
-      justify-content: flex-start;
-      align-items: flex-start;
-      flex-wrap: wrap;
-      overflow-y: auto;
-    }
+      .camera-box1 {
+        width: 100%;
+        height: calc(100% - 60px);
+        display: flex;
+        justify-content: flex-start;
+        align-items: flex-start;
+        flex-wrap: wrap;
+        overflow-y: auto;
+      }
 
-    .player-box {
-      width: 626px;
-      height: 370px;
-      padding: 17px 18px;
-      background: var(--image-camera_bg);
-      background-size: 100% 100%;
-      position: relative;
-      margin: 10px;
+      .player-box {
+        width: 626px;
+        height: 370px;
+        padding: 17px 18px;
+        background: var(--image-camera_bg);
+        background-size: 100% 100%;
+        position: relative;
+        margin: 10px;
 
-      .player-name {
-        font-size: 14px;
-        position: absolute;
-        top: 35px;
-        right: 15px;
-        color: #fff;
-        background-color: hsla(0, 0%, 50%, 0.5);
-        border-radius: 2px;
-        padding: 1px 5px;
-        max-width: 120px;
-        overflow: hidden;
-        white-space: nowrap;
-        text-overflow: ellipsis;
-        z-index: 999;
+        .player-name {
+          font-size: 14px;
+          position: absolute;
+          top: 35px;
+          right: 15px;
+          color: #fff;
+          background-color: hsla(0, 0%, 50%, 0.5);
+          border-radius: 2px;
+          padding: 1px 5px;
+          max-width: 120px;
+          overflow: hidden;
+          white-space: nowrap;
+          text-overflow: ellipsis;
+          z-index: 999;
+        }
+
+        .click-box {
+          position: absolute;
+          width: 100%;
+          height: 100%;
+          top: 0;
+          left: 0;
+        }
       }
 
-      .click-box {
-        position: absolute;
+      .pagination {
         width: 100%;
-        height: 100%;
-        top: 0;
-        left: 0;
+        height: 60px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
       }
     }
-
-    .pagination {
-      width: 100%;
-      height: 60px;
-      display: flex;
-      justify-content: center;
-      align-items: center;
-    }
   }
-}
 
-:deep(video) {
-  width: 100% !important;
-  height: 100% !important;
-  object-fit: cover !important;
-}
+  :deep(video) {
+    width: 100% !important;
+    height: 100% !important;
+    object-fit: cover !important;
+  }
 </style>

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

@@ -193,8 +193,8 @@
                                 selectData[state.dataIndex.replace('Fan', 'Fan1')] === undefined
                                   ? '无状态'
                                   : selectData[state.dataIndex.replace('Fan', 'Fan1')] == '0'
-                                  ? '正常'
-                                  : '异常'
+                                    ? '正常'
+                                    : '异常'
                               }}</div>
                             </div>
                             <div class="signal-item" v-if="warningMonitorRowIndex == 1">
@@ -212,8 +212,8 @@
                                 selectData[state.dataIndex.replace('Fan', 'Fan2')] == undefined
                                   ? '无状态'
                                   : selectData[state.dataIndex.replace('Fan', 'Fan2')] == '0'
-                                  ? '正常'
-                                  : '异常'
+                                    ? '正常'
+                                    : '异常'
                               }}</div>
                             </div>
                           </div>
@@ -256,7 +256,7 @@
               ref="MonitorDataTable"
               :dataSource="dataSource"
               :columnsType="`${selectData.deviceType}_monitor`"
-              @selectRow="getSelectRow"
+              @select-row="getSelectRow"
               :scroll="scroll"
               :is-action="true"
             >
@@ -1952,9 +1952,10 @@
     justify-content: flex-end;
     padding-right: 380px;
     pointer-events: none;
-
+    .liveVideo {
+      align-self: auto !important;
+    }
     .video-parent {
-      height: 208px;
       pointer-events: auto !important;
     }
   }

+ 353 - 0
src/views/vent/monitorManager/gateMonitor/dandaoFcBd3.threejs.ts

@@ -0,0 +1,353 @@
+import * as THREE from 'three';
+
+import { getTextCanvas, renderVideo } from '/@/utils/threejs/util';
+import gsap from 'gsap';
+
+class ddFc_7 {
+  model;
+  modelName = 'ddFcGroup';
+  group: THREE.Object3D = new THREE.Object3D();
+  animationTimer;
+  isLRAnimation = true;
+  direction = 1;
+  windowsActionArr = {
+    frontWindow: [],
+    backWindow: [],
+  };
+  player1;
+  player2;
+  playerStartClickTime1 = new Date().getTime();
+  mixers: THREE.AnimationMixer | undefined;
+  frontClipAction;
+  fmClock = new THREE.Clock();
+  constructor(model) {
+    this.model = model;
+    this.group.name = 'ddFcGroup';
+  }
+  addLight = () => {
+    if (!this.group || !this.group) return;
+
+    const directionalLight = new THREE.DirectionalLight(0xffffff, 2);
+    directionalLight.position.set(-437, 61, 559);
+    this.group.add(directionalLight);
+
+    const pointLight2 = new THREE.PointLight(0xffffff, 1, 150);
+    pointLight2.position.set(-101, 34, 16);
+    pointLight2.shadow.bias = 0.05;
+    this.group.add(pointLight2);
+
+    const pointLight3 = new THREE.PointLight(0xffffff, 1, 150);
+    pointLight3.position.set(19, 25, -7);
+    pointLight3.shadow.bias = 0.05;
+    this.group.add(pointLight3);
+
+    const pointLight6 = new THREE.PointLight(0xffffff, 1, 300);
+    pointLight6.position.set(51, 51, 9);
+    pointLight6.shadow.bias = 0.05;
+    this.group.add(pointLight6);
+  };
+
+  // 设置模型位置
+  setModalPosition() {
+    this.group?.scale.set(22, 22, 22);
+    this.group?.position.set(-35, 25, 15);
+  }
+
+  addMonitorText(selectData) {
+    if (!this.group) {
+      return;
+    }
+    const screenDownText = VENT_PARAM['modalText']
+      ? VENT_PARAM['modalText']
+      : History_Type['type'] == 'remote'
+        ? `国能神东煤炭集团监制`
+        : '煤科通安(北京)智控科技有限公司研制';
+
+    const screenDownTextX = 90 - (screenDownText.length - 10) * 7;
+    const textArr = [
+      {
+        text: `远程定量调节自动风门`,
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 100,
+        y: 95,
+      },
+      {
+        text: `${selectData.OpenDegree ? '开度值(°)' : selectData.forntArea ? '过风面积(㎡)' : '过风面积(㎡)'}:`,
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 5,
+        y: 145,
+      },
+      {
+        text: selectData.OpenDegree
+          ? Number(`${selectData.OpenDegree}`).toFixed(2)
+          : selectData.forntArea
+            ? Number(`${selectData.forntArea}`).toFixed(2)
+            : '-',
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 330,
+        y: 145,
+      },
+      {
+        text: `${selectData.frontRearDP ? '风窗压差(Pa)' : selectData.windSpeed ? '风速(m/s)' : '通信状态:'}:`,
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 5,
+        y: 200,
+      },
+      {
+        text: `${
+          selectData.frontRearDP
+            ? selectData.frontRearDP
+            : selectData.windSpeed
+              ? selectData.windSpeed
+              : selectData.netStatus == '0'
+                ? '断开'
+                : '连接'
+        }`,
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 330,
+        y: 200,
+      },
+      {
+        text: `${selectData.fWindowM3 ? '过风量(m³/min)' : '风窗道数'}: `,
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 5,
+        y: 250,
+      },
+      {
+        text: `${selectData.fWindowM3 ? selectData.fWindowM3 : selectData.nwindownum}`,
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 330,
+        y: 250,
+      },
+      {
+        text: screenDownText,
+        font: 'normal 28px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: screenDownTextX,
+        y: 300,
+      },
+    ];
+    getTextCanvas(750, 546, textArr, '').then((canvas: HTMLCanvasElement) => {
+      const textMap = new THREE.CanvasTexture(canvas); // 关键一步
+      const textMaterial = new THREE.MeshBasicMaterial({
+        // 关于材质并未讲解 实操即可熟悉                 这里是漫反射类似纸张的材质,对应的就有高光类似金属的材质.
+        map: textMap, // 设置纹理贴图
+        transparent: true,
+        side: THREE.DoubleSide, // 这里是双面渲染的意思
+      });
+      textMap.dispose();
+      textMaterial.blending = THREE.CustomBlending;
+      const monitorPlane = this.group?.getObjectByName('monitorText');
+      if (monitorPlane) {
+        monitorPlane.material = textMaterial;
+      } else {
+        const planeGeometry = new THREE.PlaneGeometry(526, 346); // 平面3维几何体PlaneGeometry
+        const planeMesh = new THREE.Mesh(planeGeometry, textMaterial);
+        planeMesh.name = 'monitorText';
+        planeMesh.scale.set(0.003, 0.0034, 0.004);
+        planeMesh.position.set(4.25, 0.41, -0.27);
+        this.group?.add(planeMesh);
+      }
+    });
+  }
+
+  /* 提取风门序列帧,初始化前后门动画 */
+  initAnimation() {
+    const modalGroup = this.group?.getObjectByName('ddFc-bd3');
+    // 初始化窗得动画
+    const meshArr01: THREE.Object3D[] = [];
+    const meshArr02: THREE.Object3D[] = [];
+    const fmGroup = modalGroup?.getObjectByName('FengMen_ShouDong_1')?.getObjectByName('FengMen_1');
+    const fcGroup1 = fmGroup?.getObjectByName('Men_1');
+    const fcGroup2 = fmGroup?.getObjectByName('Men_2');
+    if (fcGroup1 && fcGroup2) {
+      fcGroup1.getObjectByName('shanye_1')?.children.filter((obj) => {
+        if (obj.name.includes('shanye_1')) {
+          obj.rotateOnAxis(new THREE.Vector3(0, 1, 0), 0);
+          meshArr01.push(obj);
+        }
+      });
+      fcGroup1.getObjectByName('shanye_2')?.children.filter((obj) => {
+        if (obj.name.includes('shanye_2')) {
+          obj.rotateOnAxis(new THREE.Vector3(0, 1, 0), 0);
+          meshArr01.push(obj);
+        }
+      });
+      fcGroup2.children.filter((obj) => {
+        if (obj.name.includes('shanye_3')) {
+          obj.rotateOnAxis(new THREE.Vector3(0, 1, 0), 0);
+          meshArr02.push(obj);
+        }
+      });
+      fcGroup2.getObjectByName('shanye_4')?.children.filter((obj) => {
+        if (obj.name.includes('shanye_4')) {
+          obj.rotateOnAxis(new THREE.Vector3(0, 1, 0), 0);
+          meshArr02.push(obj);
+        }
+      });
+      this.windowsActionArr.frontWindow = [...meshArr01];
+      this.windowsActionArr.backWindow = [...meshArr02];
+    }
+    // 初始化门的动画
+    if (modalGroup && fmGroup) {
+      const tracks = modalGroup.animations[0].tracks;
+      const fontTracks: any[] = [];
+      for (let i = 0; i < tracks.length; i++) {
+        const track = tracks[i];
+        if (track.name.startsWith('Men')) {
+          fontTracks.push(track);
+        }
+      }
+      this.mixers = new THREE.AnimationMixer(fmGroup);
+      const frontDoor = new THREE.AnimationClip('frontDoor', 15, fontTracks);
+      this.frontClipAction = this.mixers.clipAction(frontDoor, fmGroup);
+      this.frontClipAction.clampWhenFinished = true;
+      // this.frontClipAction.reset();
+      // this.frontClipAction.time = 0;
+      // this.frontClipAction.timeScale = 1;
+      // this.frontClipAction.clampWhenFinished = true;
+      // this.frontClipAction.loop = THREE.LoopOnce;
+      // this.frontClipAction.play();
+    }
+  }
+
+  // 播放动画
+  play(handlerState, timeScale = 0.01) {
+    let handler = () => {};
+    if (this.frontClipAction) {
+      switch (handlerState) {
+        case 1: // 打开前门
+          handler = () => {
+            this.frontClipAction.paused = true;
+            this.frontClipAction.reset();
+            this.frontClipAction.time = 0;
+            this.frontClipAction.timeScale = timeScale;
+            this.frontClipAction.play();
+            this.fmClock.start();
+          };
+          break;
+        case 2: // 关闭前门
+          handler = () => {
+            this.frontClipAction.paused = true;
+            this.frontClipAction.reset(); //
+            this.frontClipAction.time = 2.5;
+            this.frontClipAction.timeScale = -timeScale;
+            this.frontClipAction.play();
+            this.fmClock.start();
+          };
+          break;
+        default:
+      }
+      handler();
+    }
+  }
+
+  playWindow(rotationParam, flag) {
+    if (!this.windowsActionArr.frontWindow) {
+      return;
+    }
+    if (flag === 1) {
+      // 前风窗动画
+      this.windowsActionArr.frontWindow.forEach((mesh: THREE.Mesh) => {
+        gsap.to(mesh.rotation, {
+          z: THREE.MathUtils.degToRad(rotationParam.frontDeg1),
+          duration: (1 / 9) * Math.abs(rotationParam.frontDeg1 - mesh.rotation.z),
+          overwrite: true,
+        });
+      });
+    } else if (flag === 2) {
+      // 后风窗动画
+      this.windowsActionArr.backWindow.forEach((mesh: THREE.Mesh) => {
+        gsap.to(mesh.rotation, {
+          z: THREE.MathUtils.degToRad(rotationParam.backDeg1),
+          duration: (1 / 9) * Math.abs(rotationParam.backDeg1 - mesh.rotation.z),
+          overwrite: true,
+        });
+      });
+    } else if (flag === 0) {
+      ([...this.windowsActionArr.frontWindow] as THREE.Mesh[]).forEach((mesh) => {
+        gsap.to(mesh.rotation, {
+          z: THREE.MathUtils.degToRad(90),
+          overwrite: true,
+        });
+      });
+    }
+  }
+
+  /* 点击风窗,风窗全屏 */
+  mousedownModel(intersects: THREE.Intersection<THREE.Object3D<THREE.Event>>[]) {
+    if (this.animationTimer) {
+      clearTimeout(this.animationTimer);
+      this.animationTimer = null;
+    }
+    // 判断是否点击到视频
+    intersects.find((intersect) => {
+      const mesh = intersect.object;
+      if (mesh.name === 'player1') {
+        if (new Date().getTime() - this.playerStartClickTime1 < 400) {
+          // 双击,视频放大
+          if (this.player1) {
+            this.player1.requestFullscreen();
+          }
+        }
+        this.playerStartClickTime1 = new Date().getTime();
+        return true;
+      }
+      return false;
+    });
+  }
+
+  mouseUpModel() {}
+
+  /* 风门动画 */
+  render() {
+    if (!this.model) {
+      return;
+    }
+    if (this.mixers && this.fmClock.running) {
+      this.mixers.update(2);
+    }
+  }
+
+  mountedThree() {
+    return new Promise((resolve) => {
+      this.model.setGLTFModel(['ddFc-bd3'], this.group).then(() => {
+        console.log(this.group);
+        this.setModalPosition();
+        this.initAnimation();
+        resolve(null);
+      });
+    });
+  }
+
+  destroy() {
+    if (this.mixers) {
+      const modalGroup = this.group?.getObjectByName('ddFc-bd3');
+      const fmGroup = modalGroup?.getObjectByName('FengMen_ShouDong_1')?.getObjectByName('FengMen_1');
+      this.mixers.uncacheClip(this.frontClipAction.getClip());
+      this.mixers.uncacheAction(this.frontClipAction.getClip(), fmGroup);
+      if (fmGroup) this.mixers.uncacheRoot(fmGroup);
+      if (this.model.animations[0]) this.model.animations[0].tracks = [];
+    }
+    this.model.clearGroup(this.group);
+    this.frontClipAction = undefined;
+    this.model = null;
+    this.group = null;
+  }
+}
+export default ddFc_7;

+ 343 - 0
src/views/vent/monitorManager/gateMonitor/gate.threejs.tj.ssl.ts

@@ -0,0 +1,343 @@
+import * as THREE from 'three';
+
+import { getTextCanvas, renderVideo } from '/@/utils/threejs/util';
+import gsap from 'gsap';
+
+class ddFmSsl {
+  model;
+  modelName = 'fm-fc-ssl';
+  group: THREE.Object3D = new THREE.Object3D();
+  animationTimer;
+  isLRAnimation = true;
+  direction = 1;
+  windowsActionArr = {
+    frontWindow: [],
+    backWindow: [],
+  };
+  player1;
+  player2;
+  playerStartClickTime1 = new Date().getTime();
+  mixers: THREE.AnimationMixer | undefined;
+  frontClipAction;
+  fmClock = new THREE.Clock();
+  constructor(model) {
+    this.model = model;
+    this.group.name = 'fm-fc-ssl';
+  }
+  addLight = () => {
+    if (!this.group || !this.group) return;
+
+    const directionalLight = new THREE.DirectionalLight(0xffffff, 2);
+    directionalLight.position.set(-437, 61, 559);
+    this.group.add(directionalLight);
+
+    const pointLight2 = new THREE.PointLight(0xffffff, 1, 150);
+    pointLight2.position.set(-101, 34, 16);
+    pointLight2.shadow.bias = 0.05;
+    this.group.add(pointLight2);
+
+    const pointLight3 = new THREE.PointLight(0xffffff, 1, 150);
+    pointLight3.position.set(19, 25, -7);
+    pointLight3.shadow.bias = 0.05;
+    this.group.add(pointLight3);
+
+    const pointLight6 = new THREE.PointLight(0xffffff, 1, 300);
+    pointLight6.position.set(51, 51, 9);
+    pointLight6.shadow.bias = 0.05;
+    this.group.add(pointLight6);
+  };
+
+  // 设置模型位置
+  setModalPosition() {
+    this.group?.scale.set(22, 22, 22);
+    this.group?.position.set(-35, 25, 15);
+  }
+
+  addMonitorText(selectData) {
+    if (!this.group) {
+      return;
+    }
+    const screenDownText = VENT_PARAM['modalText']
+      ? VENT_PARAM['modalText']
+      : History_Type['type'] == 'remote'
+        ? `国能神东煤炭集团监制`
+        : '煤科通安(北京)智控科技有限公司研制';
+
+    const screenDownTextX = 90 - (screenDownText.length - 10) * 7;
+    const textArr = [
+      {
+        text: `远程定量调节自动风门`,
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 100,
+        y: 95,
+      },
+      {
+        text: `${selectData.OpenDegree ? '开度值(°)' : selectData.forntArea ? '过风面积(㎡)' : '过风面积(㎡)'}:`,
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 5,
+        y: 145,
+      },
+      {
+        text: selectData.OpenDegree
+          ? Number(`${selectData.OpenDegree}`).toFixed(2)
+          : selectData.forntArea
+            ? Number(`${selectData.forntArea}`).toFixed(2)
+            : '-',
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 330,
+        y: 145,
+      },
+      {
+        text: `${selectData.frontRearDP ? '风窗压差(Pa)' : selectData.windSpeed ? '风速(m/s)' : '通信状态:'}:`,
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 5,
+        y: 200,
+      },
+      {
+        text: `${
+          selectData.frontRearDP
+            ? selectData.frontRearDP
+            : selectData.windSpeed
+              ? selectData.windSpeed
+              : selectData.netStatus == '0'
+                ? '断开'
+                : '连接'
+        }`,
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 330,
+        y: 200,
+      },
+      {
+        text: `${selectData.fWindowM3 ? '过风量(m³/min)' : '风窗道数'}: `,
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 5,
+        y: 250,
+      },
+      {
+        text: `${selectData.fWindowM3 ? selectData.fWindowM3 : selectData.nwindownum}`,
+        font: 'normal 30px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: 330,
+        y: 250,
+      },
+      {
+        text: screenDownText,
+        font: 'normal 28px Arial',
+        color: '#009900',
+        strokeStyle: '#002200',
+        x: screenDownTextX,
+        y: 300,
+      },
+    ];
+    getTextCanvas(750, 546, textArr, '').then((canvas: HTMLCanvasElement) => {
+      const textMap = new THREE.CanvasTexture(canvas); // 关键一步
+      const textMaterial = new THREE.MeshBasicMaterial({
+        // 关于材质并未讲解 实操即可熟悉                 这里是漫反射类似纸张的材质,对应的就有高光类似金属的材质.
+        map: textMap, // 设置纹理贴图
+        transparent: true,
+        side: THREE.DoubleSide, // 这里是双面渲染的意思
+      });
+      textMap.dispose();
+      textMaterial.blending = THREE.CustomBlending;
+      const monitorPlane = this.group?.getObjectByName('monitorText');
+      if (monitorPlane) {
+        monitorPlane.material = textMaterial;
+      } else {
+        const planeGeometry = new THREE.PlaneGeometry(526, 346); // 平面3维几何体PlaneGeometry
+        const planeMesh = new THREE.Mesh(planeGeometry, textMaterial);
+        planeMesh.name = 'monitorText';
+        planeMesh.scale.set(0.003, 0.0034, 0.004);
+        planeMesh.position.set(4.25, 0.41, -0.27);
+        this.group?.add(planeMesh);
+      }
+    });
+  }
+
+  /* 提取风门序列帧,初始化前后门动画 */
+  initAnimation() {
+    const modalGroup = this.group?.getObjectByName('fm-fc-ssl');
+    // 初始化窗得动画
+    const meshArr01: THREE.Object3D[] = [];
+    const meshArr02: THREE.Object3D[] = [];
+    const fmGroup = modalGroup?.getObjectByName('FengMen_DaiChuang');
+    const fcGroup1 = fmGroup?.getObjectByName('Men_1');
+    const fcGroup2 = fmGroup?.getObjectByName('Men_2');
+    if (fcGroup1 && fcGroup2) {
+      fcGroup1.getObjectByName('shanye_1')?.children.filter((obj) => {
+        if (obj.name.includes('shanye_1')) {
+          obj.rotateOnAxis(new THREE.Vector3(0, 1, 0), 0);
+          meshArr01.push(obj);
+        }
+      });
+      fcGroup2.getObjectByName('shanye_3')?.children.filter((obj) => {
+        if (obj.name.includes('shanye_1')) {
+          obj.rotateOnAxis(new THREE.Vector3(0, 1, 0), 0);
+          meshArr02.push(obj);
+        }
+      });
+
+      this.windowsActionArr.frontWindow = [...meshArr01];
+      this.windowsActionArr.backWindow = [...meshArr02];
+    }
+    // 初始化门的动画
+    if (modalGroup && fmGroup) {
+      const tracks = modalGroup.animations[0].tracks;
+      const fontTracks: any[] = [];
+      for (let i = 0; i < tracks.length; i++) {
+        const track = tracks[i];
+        if (track.name.startsWith('Men')) {
+          fontTracks.push(track);
+        }
+      }
+      this.mixers = new THREE.AnimationMixer(fmGroup);
+      const frontDoor = new THREE.AnimationClip('frontDoor', 15, fontTracks);
+      this.frontClipAction = this.mixers.clipAction(frontDoor, fmGroup);
+      this.frontClipAction.clampWhenFinished = true;
+      // this.frontClipAction.reset();
+      // this.frontClipAction.time = 0;
+      // this.frontClipAction.timeScale = 1;
+      // this.frontClipAction.clampWhenFinished = true;
+      // this.frontClipAction.loop = THREE.LoopOnce;
+      // this.frontClipAction.play();
+    }
+  }
+
+  // 播放动画
+  play(handlerState, timeScale = 0.01) {
+    let handler = () => {};
+    if (this.frontClipAction) {
+      switch (handlerState) {
+        case 1: // 打开前门
+          handler = () => {
+            this.frontClipAction.paused = true;
+            this.frontClipAction.reset();
+            this.frontClipAction.time = 0;
+            this.frontClipAction.timeScale = timeScale;
+            this.frontClipAction.play();
+            this.fmClock.start();
+          };
+          break;
+        case 2: // 关闭前门
+          handler = () => {
+            this.frontClipAction.paused = true;
+            this.frontClipAction.reset(); //
+            this.frontClipAction.time = 2.5;
+            this.frontClipAction.timeScale = -timeScale;
+            this.frontClipAction.play();
+            this.fmClock.start();
+          };
+          break;
+        default:
+      }
+      handler();
+    }
+  }
+
+  playWindow(rotationParam, flag) {
+    if (!this.windowsActionArr.frontWindow) {
+      return;
+    }
+    if (flag === 1) {
+      // 前风窗动画
+      this.windowsActionArr.frontWindow.forEach((mesh: THREE.Mesh) => {
+        gsap.to(mesh.rotation, {
+          z: THREE.MathUtils.degToRad(rotationParam.frontDeg1),
+          duration: (1 / 9) * Math.abs(rotationParam.frontDeg1 - mesh.rotation.z),
+          overwrite: true,
+        });
+      });
+    } else if (flag === 2) {
+      // 后风窗动画
+      this.windowsActionArr.backWindow.forEach((mesh: THREE.Mesh) => {
+        gsap.to(mesh.rotation, {
+          z: THREE.MathUtils.degToRad(rotationParam.backDeg1),
+          duration: (1 / 9) * Math.abs(rotationParam.backDeg1 - mesh.rotation.z),
+          overwrite: true,
+        });
+      });
+    } else if (flag === 0) {
+      ([...this.windowsActionArr.frontWindow] as THREE.Mesh[]).forEach((mesh) => {
+        gsap.to(mesh.rotation, {
+          z: THREE.MathUtils.degToRad(90),
+          overwrite: true,
+        });
+      });
+    }
+  }
+
+  /* 点击风窗,风窗全屏 */
+  mousedownModel(intersects: THREE.Intersection<THREE.Object3D<THREE.Event>>[]) {
+    if (this.animationTimer) {
+      clearTimeout(this.animationTimer);
+      this.animationTimer = null;
+    }
+    // 判断是否点击到视频
+    intersects.find((intersect) => {
+      const mesh = intersect.object;
+      if (mesh.name === 'player1') {
+        if (new Date().getTime() - this.playerStartClickTime1 < 400) {
+          // 双击,视频放大
+          if (this.player1) {
+            this.player1.requestFullscreen();
+          }
+        }
+        this.playerStartClickTime1 = new Date().getTime();
+        return true;
+      }
+      return false;
+    });
+  }
+
+  mouseUpModel() {}
+
+  /* 风门动画 */
+  render() {
+    if (!this.model) {
+      return;
+    }
+    if (this.mixers && this.fmClock.running) {
+      this.mixers.update(2);
+    }
+  }
+
+  mountedThree() {
+    return new Promise((resolve) => {
+      this.model.setGLTFModel('fm-fc-ssl').then((gltf) => {
+        this.group = gltf[0];
+        this.group.name = 'fm-fc-ssl';
+        this.setModalPosition();
+        this.initAnimation();
+        resolve(null);
+      });
+    });
+  }
+
+  destroy() {
+    if (this.mixers) {
+      const modalGroup = this.group?.getObjectByName('fm-fc-ssl');
+      const fmGroup = modalGroup?.getObjectByName('FengMen_ShouDong_1')?.getObjectByName('FengMen_1');
+      this.mixers.uncacheClip(this.frontClipAction.getClip());
+      this.mixers.uncacheAction(this.frontClipAction.getClip(), fmGroup);
+      if (fmGroup) this.mixers.uncacheRoot(fmGroup);
+      if (this.model.animations[0]) this.model.animations[0].tracks = [];
+    }
+    this.model.clearGroup(this.group);
+    this.frontClipAction = undefined;
+    this.model = null;
+    this.group = null;
+  }
+}
+export default ddFmSsl;

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

@@ -33,6 +33,9 @@ let model,
   fmYjXr, // 窑街拱形行人风门
   fmYj, // 窑街拱形行车风门
   fmSp1, // 沙坪一道风门
+  fmDcBd, // 带风窗
+  fmSsl, // 思山岭双道蓝色风门
+  fm_fc_ssl, // 带风窗
   group: THREE.Object3D,
   fmType = '',
   windowType = 'singleWindow';
@@ -46,6 +49,10 @@ const rotationParam = {
   frontRightDeg1: 0, // 前门目标
   backRightDeg0: 0, // 后门初始
   backRightDeg1: 0, // 后门目标
+  frontDeg0: 0,
+  frontDeg1: 0,
+  backDeg0: 0,
+  backDeg1: 0,
 };
 
 const { mouseDownFn } = useEvent();
@@ -84,6 +91,12 @@ const startAnimation = () => {
       fmYj.mouseUpModel();
     } else if (fmType === 'fmSp1') {
       fmSp1.mouseUpModel();
+    } else if (fmType === 'fm_fc_bd') {
+      fmDcBd.mouseUpModel();
+    } else if (fmType === 'fmSsl') {
+      fmSsl.mouseUpModel();
+    } else if (fmType === 'fm_fc_ssl') {
+      fm_fc_ssl.mouseUpModel();
     }
   });
 };
@@ -119,6 +132,12 @@ const mouseEvent = (event) => {
         fmYj.mousedownModel(intersects);
       } else if (fmType === 'fmSp1') {
         fmSp1.mousedownModel(intersects);
+      } else if (fmType === 'fm_fc_bd' && fmDcBd) {
+        fmDcBd.mousedownModel(intersects);
+      } else if (fmType === 'fmSsl' && fmSsl) {
+        fmSsl.mousedownModel(intersects);
+      } else if (fmType === 'fm_fc_ssl' && fm_fc_ssl) {
+        fm_fc_ssl.mousedownModel(intersects);
       }
     });
     console.log('摄像头控制信息', model.orbitControls, model.camera);
@@ -153,6 +172,12 @@ export const addMonitorText = (selectData) => {
     fmYj.addMonitorText(selectData);
   } else if (fmType === 'fmSp1' && fmSp1) {
     fmSp1.addMonitorText(selectData);
+  } else if (fmType === 'fm_fc_bd' && fmDcBd) {
+    return fmDcBd.addMonitorText(selectData);
+  } else if (fmType === 'fmSsl' && fmSsl) {
+    return fmSsl.addMonitorText.call(fmSsl, selectData);
+  } else if (fmType === 'fm_fc_ssl' && fm_fc_ssl) {
+    return fm_fc_ssl.addMonitorText.call(fm_fc_ssl, selectData);
   }
 };
 
@@ -197,6 +222,12 @@ export const play = (handlerState, flag?) => {
     return fmYj?.play.call(fmYj, handlerState, flag);
   } else if (fmType === 'fmSp1') {
     return fmSp1?.play(handlerState, flag);
+  } else if (fmType === 'fm_fc_bd' && fmDcBd) {
+    return fmDcBd.play.call(fmDcBd, handlerState, flag);
+  } else if (fmType === 'fmSsl' && fmSsl) {
+    return fmSsl.play.call(fmSsl, handlerState, flag);
+  } else if (fmType === 'fm_fc_ssl' && fm_fc_ssl) {
+    return fm_fc_ssl.play.call(fm_fc_ssl, handlerState, flag);
   }
 };
 
@@ -257,6 +288,23 @@ export function computePlay(data, maxarea, isFirst = false) {
     fmWindow.playWindow(rotationParam, 2);
     fmWindow.playWindow(rotationParam, 3);
     fmWindow.playWindow(rotationParam, 4);
+  } else if (fmType === 'fm_fc_bd' || fmType === 'fm_fc_ssl') {
+    maxarea = 90;
+    rotationParam.frontDeg0 = (90 / maxarea) * Number(isFirst ? 0 : data.forntArea);
+    rotationParam.backDeg0 = (90 / maxarea) * Number(isFirst ? 0 : data.rearArea);
+    rotationParam.frontDeg1 = (90 / maxarea) * Number(data.forntArea) || 0;
+    rotationParam.backDeg1 = (90 / maxarea) * Number(data.rearArea) || 0;
+    // rotationParam.frontDeg1 = 50;
+    // rotationParam.backDeg1 = 80;
+    let fmDc;
+    if (fmType === 'fm_fc_bd') {
+      fmDc = fmDcBd;
+    } else if (fmType === 'fm_fc_ssl') {
+      fmDc = fm_fc_ssl;
+    }
+
+    fmDc.playWindow(rotationParam, 1);
+    fmDc.playWindow(rotationParam, 2);
   }
 }
 
@@ -409,6 +457,56 @@ export const setModelType = (type) => {
         model.scene.add(fmWindowZhq.group);
         const position = { x: -2.28, y: -0.91, z: -5.68 };
 
+        await animateCamera(
+          oldCameraPosition,
+          { x: -2.27, y: -0.91, z: -5.67 },
+          { x: 66.257, y: 57.539, z: 94.313 },
+          { x: position.x, y: position.y, z: position.z },
+          model,
+          0.6
+        );
+      }, 300);
+    } else if (fmType === 'fm_fc_bd' && fmDcBd && fmDcBd.group) {
+      if (fmDcBd.frontClipAction) {
+        fmDcBd.frontClipAction.reset();
+        fmDcBd.frontClipAction.time = 0.5;
+        fmDcBd.frontClipAction.stop();
+      }
+
+      model.startAnimation = fmDcBd.render.bind(fmDcBd);
+      model.scene.remove(group);
+      group = fmDcBd.group;
+      const oldCameraPosition = { x: -761, y: 569, z: 871 };
+      setTimeout(async () => {
+        resolve(null);
+        model.scene.add(fmDcBd.group);
+        const position = { x: -2.28, y: -0.91, z: -5.68 };
+
+        await animateCamera(
+          oldCameraPosition,
+          { x: -2.27, y: -0.91, z: -5.67 },
+          { x: 66.257, y: 57.539, z: 94.313 },
+          { x: position.x, y: position.y, z: position.z },
+          model,
+          0.6
+        );
+      }, 300);
+    } else if (fmType === 'fm_fc_ssl' && fm_fc_ssl && fm_fc_ssl.group) {
+      if (fm_fc_ssl.frontClipAction) {
+        fm_fc_ssl.frontClipAction.reset();
+        fm_fc_ssl.frontClipAction.time = 0.5;
+        fm_fc_ssl.frontClipAction.stop();
+      }
+
+      model.startAnimation = fm_fc_ssl.render.bind(fm_fc_ssl);
+      model.scene.remove(group);
+      group = fm_fc_ssl.group;
+      const oldCameraPosition = { x: -761, y: 569, z: 871 };
+      setTimeout(async () => {
+        resolve(null);
+        model.scene.add(fm_fc_ssl.group);
+        const position = { x: -2.28, y: -0.91, z: -5.68 };
+
         await animateCamera(
           oldCameraPosition,
           { x: -2.27, y: -0.91, z: -5.67 },
@@ -682,6 +780,35 @@ export const setModelType = (type) => {
           0.8
         );
       }, 300);
+    } else if (fmType === 'fmSsl' && fmSsl && fmSsl.group) {
+      if (fmSsl.clipActionArr.frontDoor) {
+        fmSsl.clipActionArr.frontDoor.reset();
+        fmSsl.clipActionArr.frontDoor.time = 0.5;
+        fmSsl.clipActionArr.frontDoor.stop();
+      }
+      if (fmSsl.clipActionArr.backDoor) {
+        fmSsl.clipActionArr.backDoor.reset();
+        fmSsl.clipActionArr.backDoor.time = 0.5;
+        fmSsl.clipActionArr.backDoor.stop();
+      }
+      model.startAnimation = fmSsl.render.bind(fmSsl);
+      model.scene.remove(group);
+      group = fmSsl.group;
+      group.rotation.y = 0;
+
+      const oldCameraPosition = { x: -1000, y: 100, z: 500 };
+      setTimeout(async () => {
+        resolve(null);
+        model.scene.add(fmSsl.group);
+        await animateCamera(
+          oldCameraPosition,
+          { x: 0, y: 0, z: 0 },
+          { x: 50.99, y: 69.32, z: 93.61 },
+          { x: -10.04, y: -14.38, z: -31.4 },
+          model,
+          0.8
+        );
+      }, 300);
     }
   });
 };
@@ -713,6 +840,9 @@ const loadModel = (code): Promise<any> => {
   if (code === 'FmYjXr') return import('./gate.threejs.two.yj').then((r) => r.default); // 姚街行人
   if (code === 'FmYj') return import('./gate.threejs.yj').then((r) => r.default); // 姚街
   if (code === 'FmSp1') return import('./gate.threejs.one.sp').then((r) => r.default);
+  if (code === 'fmDcBd') return import('./dandaoFcBd3.threejs').then((r) => r.default);
+  if (code === 'fmSsl') return import('./gate.threejs.two.ssl').then((r) => r.default);
+  if (code === 'fm_fc_ssl') return import('./gate.threejs.tj.ssl').then((r) => r.default);
   return import('./gate.threejs.yy').then((r) => r.default);
 };
 
@@ -794,6 +924,21 @@ export const mountedThree = (playerDom) => {
             fmSp1 = new FmSp1(model);
             await fmSp1.mountedThree();
             break;
+          case 'fm_fc_bd':
+            const FmDcBd = await loadModel('fmDcBd');
+            fmDcBd = new FmDcBd(model);
+            await fmDcBd.mountedThree();
+            break;
+          case 'fmSsl':
+            const FmSsl = await loadModel('fmSsl');
+            fmSsl = new FmSsl(model);
+            await fmSsl.mountedThree();
+            break;
+          case 'fm_fc_ssl':
+            const Fm_fc_ssl = await loadModel('fm_fc_ssl');
+            fm_fc_ssl = new Fm_fc_ssl(model);
+            await fm_fc_ssl.mountedThree();
+            break;
         }
       }
       resolve(null);
@@ -842,6 +987,8 @@ export const destroy = () => {
     if (fmYjXr) fmYjXr.destroy();
     if (fmYj) fmYj.destroy();
     if (fmSp1) fmSp1.destroy();
+    if (fmDcBd) fmDcBd.destroy();
+    if (fm_fc_ssl) fm_fc_ssl.destroy();
     fm1 = null;
     fm2 = null;
     fm3 = null;
@@ -855,6 +1002,8 @@ export const destroy = () => {
     fmYjXr = null;
     fmYj = null;
     fmSp1 = null;
+    fmDcBd = null;
+    fm_fc_ssl = null;
     group = null;
     model.mixers = [];
     model.destroy();

+ 353 - 0
src/views/vent/monitorManager/gateMonitor/gate.threejs.two.ssl.ts

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

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

@@ -379,10 +379,7 @@
   import { render } from '/@/utils/common/renderUtils';
   import { useGlobSetting } from '/@/hooks/setting';
   import { getDictItemsByCode } from '/@/utils/dict';
-  import { defHttp } from '/@/utils/http/axios';
-  import BarAndLine from '/@/components/chart/BarAndLine.vue';
   import HistoryTableChart from '../comment/HistoryTableChart.vue';
-  import { useSvgAnimation } from '/@/hooks/vent/useSvgAnimation';
 
   const { hasPermission } = usePermission();
   const { sysOrgCode } = useGlobSetting();

+ 22 - 21
src/views/vent/monitorManager/mainFanMonitor/index.vue

@@ -76,22 +76,22 @@
                     selectData['Fan1StartStatus'] == '0' && globalConfig?.simulatedPassword
                       ? '-'
                       : selectData[data.dataIndex.replace('Fan', 'Fan1')]
-                      ? selectData[data.dataIndex.replace('Fan', 'Fan1')]
-                      : '-'
+                        ? selectData[data.dataIndex.replace('Fan', 'Fan1')]
+                        : '-'
                   }}</div>
                   <div class="item-value" v-if="dataMonitorRowIndex == 1">{{
                     selectData['Fan2StartStatus'] == '0' && globalConfig?.simulatedPassword
                       ? '-'
                       : selectData[data.dataIndex.replace('Fan', 'Fan2')]
-                      ? selectData[data.dataIndex.replace('Fan', 'Fan2')]
-                      : '-'
+                        ? selectData[data.dataIndex.replace('Fan', 'Fan2')]
+                        : '-'
                   }}</div>
                   <div class="item-value" v-if="dataMonitorRowIndex == 2">{{
                     selectData['Fan3StartStatus'] == '0' && globalConfig?.simulatedPassword
                       ? '-'
                       : selectData[data.dataIndex.replace('Fan', 'Fan3')]
-                      ? selectData[data.dataIndex.replace('Fan', 'Fan3')]
-                      : '-'
+                        ? selectData[data.dataIndex.replace('Fan', 'Fan3')]
+                        : '-'
                   }}</div>
                 </div>
                 <div v-else>
@@ -150,8 +150,8 @@
                           selectData[state.dataIndex.replace('Fan', 'Fan1')] === undefined
                             ? '无状态'
                             : selectData[state.dataIndex.replace('Fan', 'Fan1')] == '0'
-                            ? '正常'
-                            : '异常'
+                              ? '正常'
+                              : '异常'
                         }}</div>
                       </template>
                     </div>
@@ -175,8 +175,8 @@
                           selectData[state.dataIndex.replace('Fan', 'Fan2')] == undefined
                             ? '无状态'
                             : selectData[state.dataIndex.replace('Fan', 'Fan2')] == '0'
-                            ? '正常'
-                            : '异常'
+                              ? '正常'
+                              : '异常'
                         }}</div>
                       </template>
                     </div>
@@ -200,8 +200,8 @@
                           selectData[state.dataIndex.replace('Fan', 'Fan3')] == undefined
                             ? '无状态'
                             : selectData[state.dataIndex.replace('Fan', 'Fan3')] == '0'
-                            ? '正常'
-                            : '异常'
+                              ? '正常'
+                              : '异常'
                         }}</div>
                       </template>
                     </div>
@@ -311,7 +311,7 @@
               ref="MonitorDataTable"
               :dataSource="dataSource"
               columnsType="fanmain_monitor"
-              @selectRow="getSelectRow"
+              @select-row="getSelectRow"
               :scroll="{ y: scroll.y - (headElHeight - 56) }"
               :is-action="true"
             >
@@ -1060,12 +1060,12 @@
         selectData['modalTyoe'] === 'xiejing'
           ? 'mainXjWindRect'
           : selectData['modalTyoe'] === 'lijing1'
-          ? 'mainLjWindRect'
-          : selectData['modalTyoe'] === 'lijing_3'
-          ? 'mainWindRect3'
-          : selectData['modalTyoe'] === 'lijing_1'
-          ? 'mainLjDtWindRect'
-          : 'mainWindRect';
+            ? 'mainLjWindRect'
+            : selectData['modalTyoe'] === 'lijing_3'
+              ? 'mainWindRect3'
+              : selectData['modalTyoe'] === 'lijing_1'
+                ? 'mainLjDtWindRect'
+                : 'mainWindRect';
 
       frontMonitorIsShow.value = false;
       centerMonitorIsShow.value = false;
@@ -2377,9 +2377,10 @@
     // padding-left: 380px;
     pointer-events: none;
     overflow-x: auto;
-
+    .liveVideo {
+      align-self: auto !important;
+    }
     .video-parent {
-      // height: 100%;
       pointer-events: auto !important;
     }
   }