Browse Source

风机工况、瓦斯抽采泵、视频

hongrunxia 1 year ago
parent
commit
d262ba9e01
71 changed files with 1971 additions and 815 deletions
  1. 2 0
      .env
  2. 15 4
      .env.production
  3. 1 1
      index.html
  4. 1 1
      public/js/config.js
  5. 21 8
      public/js/webrtcstreamer.js
  6. BIN
      public/model/glft/fc/ddFc_2023-10-11.glb
  7. BIN
      public/model/glft/fc/wall_2023-10-11.glb
  8. BIN
      public/model/glft/fm/Fm-door_2023-09-26.glb
  9. BIN
      public/model/glft/fm/Fm-wall_2023-09-26.glb
  10. BIN
      public/model/glft/fm/Fm-wire_2023-09-26.glb
  11. BIN
      public/model/glft/fm/Fm-wire_2023-10-05.glb
  12. BIN
      public/model/glft/gas/gasPumpUnder_2023-10-05.glb
  13. BIN
      src/assets/images/vent/camera_bg.png
  14. BIN
      src/assets/images/vent/camera_bg_icon.png
  15. BIN
      src/assets/images/vent/model_image/noSinge.png
  16. BIN
      src/assets/images/vent/noSinge.png
  17. 3 3
      src/components/Application/src/AppLogo.vue
  18. 40 0
      src/design/vent/comment.less
  19. 11 2
      src/hooks/setting/index.ts
  20. 1 3
      src/layouts/default/header/index.less
  21. 6 6
      src/utils/threejs/main.worker.ts
  22. 11 5
      src/utils/threejs/util.ts
  23. 141 32
      src/utils/ventutil.ts
  24. 3 0
      src/views/vent/deviceManager/comment/NormalTable.vue
  25. 1 1
      src/views/vent/deviceManager/deviceTable/index.vue
  26. 81 0
      src/views/vent/deviceManager/equipManager/component/DeviceModal.vue
  27. 72 0
      src/views/vent/deviceManager/equipManager/component/FormModal.vue
  28. 5 30
      src/views/vent/deviceManager/equipManager/component/normalBtnTable.vue
  29. 7 0
      src/views/vent/deviceManager/equipManager/equip.api.ts
  30. 45 2
      src/views/vent/deviceManager/equipManager/equip.data.ts
  31. 3 2
      src/views/vent/deviceManager/equipManager/index.vue
  32. 86 0
      src/views/vent/home/clique/clique.data.ts
  33. 111 0
      src/views/vent/home/clique/index.vue
  34. 116 0
      src/views/vent/home/colliery/index.vue
  35. 0 1
      src/views/vent/monitorManager/alarmMonitor/index.vue
  36. 2 1
      src/views/vent/monitorManager/camera/index.vue
  37. 1 1
      src/views/vent/monitorManager/compressor/components/nitrogenHome.vue
  38. 112 3
      src/views/vent/monitorManager/deviceMonitor/components/device/device.data.ts
  39. 33 13
      src/views/vent/monitorManager/deviceMonitor/components/device/index.vue
  40. 6 6
      src/views/vent/monitorManager/deviceMonitor/components/device/modal/bundle.modal.vue
  41. 7 7
      src/views/vent/monitorManager/deviceMonitor/components/network/index.vue
  42. 2 0
      src/views/vent/monitorManager/deviceMonitor/components/network/network.data.ts
  43. 5 4
      src/views/vent/monitorManager/fanLocalMonitor/index.vue
  44. 12 3
      src/views/vent/monitorManager/gasPumpMonitor/components/gasPumpHome.vue
  45. 0 0
      src/views/vent/monitorManager/gasPumpMonitor/gasPump.threejs.over.ts
  46. 32 5
      src/views/vent/monitorManager/gasPumpMonitor/gasPump.threejs.ts
  47. 57 0
      src/views/vent/monitorManager/gasPumpMonitor/gasPump.threejs.under.ts
  48. 4 2
      src/views/vent/monitorManager/gasPumpMonitor/index.vue
  49. 47 50
      src/views/vent/monitorManager/gateMonitor/gate.threejs.three.ts
  50. 16 8
      src/views/vent/monitorManager/gateMonitor/gate.threejs.ts
  51. 110 73
      src/views/vent/monitorManager/gateMonitor/gate.threejs.two.ts
  52. 20 60
      src/views/vent/monitorManager/gateMonitor/index.vue
  53. 6 5
      src/views/vent/monitorManager/groutMonitor/components/groutHome.vue
  54. 0 1
      src/views/vent/monitorManager/groutMonitor/grout.api.ts
  55. 73 9
      src/views/vent/monitorManager/groutMonitor/index.vue
  56. 1 3
      src/views/vent/monitorManager/mainFanMonitor/components/conditionAssistance.vue
  57. 7 5
      src/views/vent/monitorManager/mainFanMonitor/index.vue
  58. 51 50
      src/views/vent/monitorManager/windowMonitor/dandaoFc.threejs.ts
  59. 46 44
      src/views/vent/monitorManager/windowMonitor/index.vue
  60. 103 72
      src/views/vent/monitorManager/windowMonitor/shuangdaoFc.threejs.ts
  61. 5 0
      src/views/vent/monitorManager/windowMonitor/window.api.ts
  62. 11 4
      src/views/vent/monitorManager/windowMonitor/window.threejs.ts
  63. 66 0
      src/views/vent/monitorManager/windrectMonitor/components/modal.vue
  64. 58 53
      src/views/vent/monitorManager/windrectMonitor/duishe.threejs.ts
  65. 89 55
      src/views/vent/monitorManager/windrectMonitor/index.vue
  66. 67 64
      src/views/vent/monitorManager/windrectMonitor/longmen.threejs.ts
  67. 57 55
      src/views/vent/monitorManager/windrectMonitor/longmenSide.threejs.ts
  68. 6 0
      src/views/vent/monitorManager/windrectMonitor/windrect.api.ts
  69. 17 5
      src/views/vent/monitorManager/windrectMonitor/windrect.threejs.ts
  70. 58 53
      src/views/vent/monitorManager/windrectMonitor/zhedie.threejs.ts
  71. 1 0
      types/config.d.ts

+ 2 - 0
.env

@@ -4,6 +4,8 @@ VITE_PORT = 3100
 #  网站标题
 VITE_GLOB_APP_TITLE = 智能通风管控系统
 
+VITE_GLOB_AP_LOGO = 
+
 # 简称,用于配置文件名字 不要出现空格、数字开头等特殊字符
 VITE_GLOB_APP_SHORT_NAME = JeecgBootAdmin
 

+ 15 - 4
.env.production

@@ -15,7 +15,11 @@ VITE_BUILD_COMPRESS = 'gzip'
 # 使用压缩时是否删除原始文件,默认为false
 VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
 #VITE_PROXY = [["/jeecgsystem","http://10.248.223.116:9999"],["/upload","http://localhost:3300/upload"]]
-VITE_PROXY = [["/jeecgsystem","http://47.94.222.6:9999"],["/upload","http://localhost:3300/upload"]]
+#VITE_PROXY = [["/jeecgsystem","http://10.248.210.152:9999"],["/upload","http://10.248.210.152:9999/upload"]]
+#VITE_PROXY = [["/jeecgsystem","http://182.92.126.35:9999"],["/upload","http://182.92.126.35:9999/upload"]]
+VITE_PROXY = [["/jeecgsystem","http://172.16.41.171:9999"],["/upload","http://172.16.41.171:9999/upload"]]
+#VITE_PROXY = [["/jeecgsystem","http://172.16.41.171:9999"],["/upload","http://172.16.41.171:9999/upload"]]
+#VITE_PROXY = [["/jeecgsystem","http://10.120.120.163:9999"],["/upload","http://10.120.120.163:9999/upload"]]
 #VITE_PROXY = [["/jeecgsystem","http://192.168.1.4:9999"],["/upload","http://localhost:3300/upload"]]
 #VITE_PROXY = [["/jeecgsystem","http://192.168.0.79:9999"],["/upload","http://localhost:3300/upload"]]
 #VITE_PROXY = [["/jeecgsystem","http://42.194.132.36:8099"],["/upload","http://localhost:3300/upload"]]
@@ -27,7 +31,10 @@ VITE_GLOB_API_URL=/jeecgsystem
 
 #后台接口全路径地址(必填)
 #VITE_GLOB_DOMAIN_URL=http://jeecg-boot-system:8080/jeecg-boot
-VITE_GLOB_DOMAIN_URL=http://47.94.222.6:9999
+#VITE_GLOB_DOMAIN_URL=http://182.92.126.35:9999
+#VITE_GLOB_DOMAIN_URL=http://10.248.210.152:9999 #宝德
+VITE_GLOB_DOMAIN_URL = http://172.16.41.171:9999
+#VITE_GLOB_DOMAIN_URL = http://10.120.120.163:9999
 #VITE_GLOB_DOMAIN_URL=http://10.248.223.50:9999
 #VITE_GLOB_DOMAIN_URL=http://192.168.1.4:9999
 #VITE_GLOB_DOMAIN_URL=http://192.168.0.79:9999
@@ -51,7 +58,11 @@ VITE_LEGACY = false
 
 #微前端qiankun应用,命名必须以VITE_APP_SUB_开头,jeecg-app-1为子应用的项目名称,也是子应用的路由父路径
 #VITE_APP_SUB_APP = [["micro-need-air", "//10.248.223.116:7777/"], ["micro-vent-3dModal", "//10.248.223.116:7121/"]]
-VITE_APP_SUB_APP = [["micro-need-air", "//47.94.222.6:7123/"], ["micro-vent-3dModal", "//47.94.222.6:7121/"]]
+#VITE_APP_SUB_APP = [["micro-need-air", "//10.248.210.152:8093/"], ["micro-vent-3dModal", "//10.248.210.152:8091/"]] #宝德
+#VITE_APP_SUB_APP = [["micro-need-air", "//10.120.120.163:8093/"], ["micro-vent-3dModal", "//10.120.120.163:8091/"]] #查哈素
+#VITE_APP_SUB_APP = [["micro-need-air", "//182.92.126.35:8093/"], ["micro-vent-3dModal", "//182.92.126.35:8091/"]]
+VITE_APP_SUB_APP = [["micro-need-air", ":8093/"], ["micro-vent-3dModal", ":8091/"]]
+#VITE_APP_SUB_APP = [["micro-need-air", "//172.16.41.171:7123/"], ["micro-vent-3dModal", "//172.16.41.171:7121/"]]
 #VITE_APP_SUB_APP = [["micro-vent-3dModal", "//192.168.0.79:7121/"]]
 #VITE_APP_SUB_APP = [["micro-need-air", "//127.0.0.1:20000/"], ["micro-vent-3dModal", "//127.0.0.1:30000/"], ["micro-fire-front", "//127.0.0.1:40000/"]]
-#VITE_APP_SUB_APP = [["micro-need-air", "//127.0.0.1:7123/"], ["micro-vent-3dModal", "//127.0.0.1:7121/"]]  
+#VITE_APP_SUB_APP = [["micro-need-air", "//127.0.0.1:7123/"], ["micro-vent-3dModal", "//127.0.0.1:7121/"]]

+ 1 - 1
index.html

@@ -8,7 +8,7 @@
     <title><%= title %></title>
     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" />
     <!-- <link rel="preload" as="script" href="/js/config.js"> -->
-    <!-- <link rel="icon" href="/logo.png" /> -->
+    <link rel="icon" id="faviconIcon" href="/logo.png" />
     <!-- 全局配置 -->
     <script src="/js/config.js"></script>
     <script src="/js/liveplayer-lib.min.js"></script>

+ 1 - 1
public/js/config.js

@@ -1,4 +1,4 @@
 const VUE_APP_URL = {
   baseUrl: "http://182.92.126.35:9999", // 后台地址
-  webRtcUrl: '//192.168.183.216:8051' // rtsp服务器IP地址
+  webRtcUrl: '//192.168.183.216:8000' // rtsp服务器IP地址
 }

+ 21 - 8
public/js/webrtcstreamer.js

@@ -35,22 +35,35 @@ WebRtcStreamer.prototype._handleHttpErrors = function (response) {
  * @param {string} options -  options of WebRTC call
  * @param {string} stream  -  local stream to send
 */
-WebRtcStreamer.prototype.connect = function(videourl, audiourl, options, localstream) {
+WebRtcStreamer.prototype.connect =async function(videourl, audiourl, options, localstream) {
 	this.disconnect();
 	
 	// getIceServers is not already received
 	if (!this.iceServers) {
 		console.log("Get IceServers");
+		try {
+			// fetch(this.srvurl + "/api/getIceServers")
+			// 	.then(this._handleHttpErrors)
+			// 	.then((response) => { return response.json() })
+			// 	.then((response) => this.onReceiveGetIceServers(response, videourl, audiourl, options, localstream))
+			// 	.catch((error) => {
+			// 		debugger
+			// 		// new Error('WebRtcStreamer connect error')
+			// 		return this.onError("getIceServers " + error)
+			// 	})
+			const response = await fetch(this.srvurl + "/api/getIceServers")
+			const res = this._handleHttpErrors(response).json()
+			this.onReceiveGetIceServers(res, videourl, audiourl, options, localstream)
+		} catch (error) {
+			// this.onError("getIceServers " + error)
+			throw new Error('WebRtcStreamer connect error')
+		}
 		
-		fetch(this.srvurl + "/api/getIceServers")
-			.then(this._handleHttpErrors)
-			.then((response) => {debugger; return response.json() } )
-			.then( (response) =>  this.onReceiveGetIceServers(response, videourl, audiourl, options, localstream))
-			.catch( (error) => this.onError("getIceServers " + error ))
-				
 	} else {
 		this.onReceiveGetIceServers(this.iceServers, videourl, audiourl, options, localstream);
 	}
+	
+	
 }
 
 /** 
@@ -84,7 +97,6 @@ WebRtcStreamer.prototype.disconnect = function() {
 */
 WebRtcStreamer.prototype.onReceiveGetIceServers = function(iceServers, videourl, audiourl, options, stream) {
 	this.iceServers       = iceServers;
-	debugger
 	this.pcConfig         = iceServers || {"iceServers": [] };
 	try {            
 		this.createPeerConnection();
@@ -293,6 +305,7 @@ WebRtcStreamer.prototype.onReceiveCandidate = function(dataJson) {
 */
 WebRtcStreamer.prototype.onError = function(status) {
 	console.log("onError:" + status);
+	throw new Error('视频播放错误')
 }
 
 return WebRtcStreamer;

BIN
public/model/glft/fc/ddFc_2023-10-11.glb


BIN
public/model/glft/fc/wall_2023-10-11.glb


BIN
public/model/glft/fm/Fm-door_2023-09-26.glb


BIN
public/model/glft/fm/Fm-wall_2023-09-26.glb


BIN
public/model/glft/fm/Fm-wire_2023-09-26.glb


BIN
public/model/glft/fm/Fm-wire_2023-10-05.glb


BIN
public/model/glft/gas/gasPumpUnder_2023-10-05.glb


BIN
src/assets/images/vent/camera_bg.png


BIN
src/assets/images/vent/camera_bg_icon.png


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


BIN
src/assets/images/vent/noSinge.png


+ 3 - 3
src/components/Application/src/AppLogo.vue

@@ -4,7 +4,7 @@
 -->
 <template>
   <div class="anticon" :class="getAppLogoClass" @click="goHome">
-    <img src="../../../assets/images/logo.png" />
+    <img :src="`${baseUrl}/sys/common/static/${logoUrl}`" />
     <div class="ml-2 truncate md:opacity-100" :class="getTitleClass" v-show="showTitle">
       {{ title }}
     </div>
@@ -37,9 +37,9 @@
   const { prefixCls } = useDesign('app-logo');
   const { getCollapsedShowTitle } = useMenuSetting();
   const userStore = useUserStore();
-  const { title } = useGlobSetting();
+  const { title, logoUrl } = useGlobSetting();
   const go = useGo();
-
+  const baseUrl = VUE_APP_URL.baseUrl;
   const getAppLogoClass = computed(() => [prefixCls, props.theme, { 'collapsed-show-title': unref(getCollapsedShowTitle) }]);
 
   const getTitleClass = computed(() => [

+ 40 - 0
src/design/vent/comment.less

@@ -170,6 +170,46 @@
   animation: ease-in-out breathe 100ms infinite alternate;
 }
 
+// 视频样式
+.video-parent{
+  margin-top: 10px;
+  position: relative;
+  width: 314px;
+  height: 208px;
+  background: url('/@/assets/images/vent/camera_bg.png');
+  background-size: cover;
+  padding: 10px;
+  .rtspVideo{
+    border: 1px solid #ffffff22;
+    height: 180px;
+    width: 320px;
+ 
+  }
+  .video-name{
+    font-size: 14px;
+    position: absolute;
+    top: 25px;
+    right: 35px;
+    color: #fff;
+    background-color: hsla(0, 0%, 50%, .5);
+    border-radius: 2px;
+    padding: 1px 5px;
+    max-width: 120px;
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+  }
+}
+#LivePlayerBox{
+  .player{
+    width: 314px;
+    height: 208px;
+    padding: 10px;
+    background: url('/@/assets/images/vent/camera_bg.png');
+    background-size: cover;
+  }
+}
+
 @keyframes breathe {
   0% {
     opacity: .2;

+ 11 - 2
src/hooks/setting/index.ts

@@ -3,6 +3,7 @@ import type { GlobConfig } from '/#/config';
 import { getAppEnvConfig } from '/@/utils/env';
 // 读取ip地址
 let domainUrl = '',
+  logoUrl = '',
   title = '';
 
 const getUrl = () => {
@@ -14,7 +15,15 @@ const getUrl = () => {
     },
   })
     .then((response) => response.json())
-    .then((data) => (title = data.result && data.result['systemTitle'] ? data.result['systemTitle'] : ''));
+    .then((data) => {
+      title = data.result && data.result['systemTitle'] ? data.result['systemTitle'] : '';
+      logoUrl = data.result && data.result['logoIcon'] ? data.result['logoIcon'] : '';
+
+      const faviconIcon = document.getElementById('faviconIcon');
+      if (faviconIcon) {
+        faviconIcon.setAttribute('href', `${VUE_APP_URL.baseUrl}/sys/common/static/${logoUrl}`);
+      }
+    });
 };
 if (!title) {
   try {
@@ -22,7 +31,6 @@ if (!title) {
   } catch (error) {}
 }
 
-
 export const useGlobSetting = (): Readonly<GlobConfig> => {
   const {
     VITE_GLOB_APP_TITLE,
@@ -49,6 +57,7 @@ export const useGlobSetting = (): Readonly<GlobConfig> => {
   }
   // Take global configuration
   const glob: Readonly<GlobConfig> = {
+    logoUrl: logoUrl,
     title: title,
     domainUrl: domainUrl,
     apiUrl: VITE_GLOB_API_URL,

+ 1 - 3
src/layouts/default/header/index.less

@@ -59,9 +59,7 @@
     font-size: 14px;
 
     img {
-      // width: @logo-width;
-      // height: @logo-width;
-      width: 40px;
+      width: @logo-width;
       height: @logo-width;
       margin-right: 5px;
     }

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

@@ -12,13 +12,14 @@ export function initModalWorker() {
   };
   const modalUrlArr = [
     'fm/fm_2023-06-02.glb',
-    'fm/Fm-door_2023-06-02.glb',
-    'fm/Fm-wire_2023-06-02.glb',
-    'fm/Fm-wall_2023-06-02.glb',
+    'fm/Fm-door_2023-09-26.glb',
+    'fm/Fm-wire_2023-10-05.glb',
+    'fm/Fm-wall_2023-09-26.glb',
     'fm/fmThree_2023-07-25.glb',
     'fm/fmThreeBase_2023-07-25.glb',
+    'fc/wall_2023-10-11.glb',
+    'fc/ddFc_2023-10-11.glb',
     'fc/sdFc_2023-06-02.glb',
-    'fc/ddFc_2023-06-02.glb',
     'cf/lmcf_2023-06-02.glb',
     'cf/lmcfSide_2023-06-02.glb',
     'cf/zdcf_2023-06-02.glb',
@@ -26,9 +27,7 @@ export function initModalWorker() {
     'cf/dsgd_2023-06-02.glb',
     'cf/ddcf_2023-07-13.glb',
     'cf/dsmove_2023-06-02.glb',
-
     'jbfj/jbfj-hd_2023-07-25.glb',
-
     'jbfj/jbfj-fm_2023-06-02.glb',
     'jbfj/jbfj-fc_2023-06-02.glb',
     'ztfj/dj1_2023-06-02.glb',
@@ -49,6 +48,7 @@ export function initModalWorker() {
     'fire/balancePress_2023-07-20.glb',
     'yafeng/compressor_2023-07-10.glb',
     'gas/gasPump_2023-08-18.glb',
+    'gas/gasPumpUnder_2023-10-05.glb',
     'mb/obfurage_2023-09-09.glb',
   ];
 

+ 11 - 5
src/utils/threejs/util.ts

@@ -70,11 +70,13 @@ export const getTextCanvas = (w, h, textArr, imgUrl) => {
         ctx.textBaseline = 'middle';
         // 由于文字需要自己排版 所以循环一下
         // item 是自定义的文字对象 包含文字内容 字体大小颜色 位置信息等
-        textArr.forEach((item) => {
-          ctx.font = item.font;
-          ctx.fillStyle = item.color;
-          ctx.fillText(item.text, item.x, item.y, 1024);
-        });
+        if (textArr) {
+          textArr.forEach((item) => {
+            ctx.font = item.font;
+            ctx.fillStyle = item.color;
+            ctx.fillText(item.text, item.x, item.y, 1024);
+          });
+        }
         resolve(canvas);
       };
       //图片加载失败的方法
@@ -272,6 +274,10 @@ export const setOutline = (model, group) => {
 export const renderVideo = (group, player, playerMeshName) => {
   //加载视频贴图;
   const texture = new THREE.VideoTexture(player);
+  console.log('视频贴图------------>', texture);
+  if(texture && texture['data'] && !texture['data'].currentSrc){
+    console.log('摄像头纹理为空。。。。')
+  }
   if (texture && group?.getObjectByName(playerMeshName)) {
     const player = group.getObjectByName(playerMeshName);
     player.material.map = texture;

+ 141 - 32
src/utils/ventutil.ts

@@ -42,6 +42,7 @@ export function formatNum(data) {
 export function cameraInit(dom, rtspUrl) {
   let webRtcServer = undefined;
   const ip = VUE_APP_URL.webRtcUrl;
+  debugger;
   // const ip = '//192.168.183.216:8000';
   webRtcServer = new window['WebRtcStreamer'](dom, location.protocol + ip);
 
@@ -50,61 +51,169 @@ export function cameraInit(dom, rtspUrl) {
 }
 
 export function deviceCameraInit(cameraAddrs, player: HTMLElement, webRtcServerList: any[] = []) {
-  const webRtcServerLen = webRtcServerList.length;
-  const playerDoms: HTMLElement[] = [];
-  const cameraUrls: string[] = [];
+  debugger;
+  console.log('webRtcServerList0--------->', webRtcServerList);
+
+  const playerDoms: (HTMLVideoElement | undefined | null)[] = [];
   const webRtcServer: any[] = [];
   let livePlayerDiv: HTMLElement | null = document.getElementById('LivePlayerBox');
-  if (livePlayerDiv) livePlayerDiv.remove();
+  if (livePlayerDiv) {
+    livePlayerDiv.remove();
+    livePlayerDiv = null;
+  }
   if (!livePlayerDiv) {
     const dom = document.createElement('div');
     dom.setAttribute('id', 'LivePlayerBox');
     livePlayerDiv = dom;
     player.appendChild(livePlayerDiv);
   }
+  const videoParentDomList: (HTMLElement | [string, { name: string; addr: string }])[] = [];
   return new Promise((resolve) => {
     const playCamrea = () => {
-      cameraAddrs.forEach((cameraUrl: string, index) => {
-        if (cameraUrl.startsWith('rtsp://')) {
-          const server = webRtcServerList.shift();
-          if (server) {
-            server.connect(cameraUrls[index]);
-            webRtcServer.push(server);
-          } else {
-            const videoDom = document.createElement('video');
-            videoDom.setAttribute('class', 'rtspVideo');
-            videoDom.autoplay = true;
-            player.appendChild(videoDom);
-            playerDoms.push(videoDom);
-            const server = new window['WebRtcStreamer'](videoDom, location.protocol + VUE_APP_URL.webRtcUrl);
-            webRtcServer.push(server);
-            if (server) server.connect(cameraUrl);
-          }
-        } else {
-          render(h(LivePlayer, { class: 'player', muted: true, autoplay: true, live: true, videoUrl: cameraUrl }), livePlayerDiv);
-        }
-      });
-      resolve(null);
+      if (cameraAddrs.length > 0) {
+        const promiseList: Promise<any>[] = [];
+        cameraAddrs.forEach(async (cameraUrl: { name: string; addr: string }, index) => {
+          const promise = new Promise(async (childResolve) => {
+            let cameraNameDom: null | HTMLElement = null;
+            console.log('摄像头地址--------->', cameraUrl, cameraUrl.addr.startsWith('rtsp://'), livePlayerDiv);
+            if (cameraUrl.addr.startsWith('rtsp://')) {
+              const server = webRtcServerList.shift();
+              if (server) {
+                try {
+                  const videoElement = server.videoElement as HTMLVideoElement;
+                  const cameraNameDom = videoElement.parentElement?.getElementsByClassName('video-name')[0];
+                  if (cameraNameDom) cameraNameDom.innerText = cameraUrl.name;
+                  playerDoms.unshift(videoElement);
+                  webRtcServer.unshift(server);
+                  await server.connect(cameraUrl['addr']);
+                  videoElement.play();
+                  childResolve(null);
+                } catch (error) {
+                  playerDoms.unshift(undefined);
+                  childResolve(null);
+                }
+              } else {
+                const videoParentDom: HTMLElement = document.createElement('div');
+                videoParentDom.setAttribute('class', 'video-parent');
+                const videoDom: HTMLVideoElement = document.createElement('video');
+                videoDom.setAttribute('class', 'rtspVideo');
+                videoDom.setAttribute('muted', 'muted');
+                videoDom.setAttribute('poster', '/src/assets/images/vent/noSinge.png');
+                videoDom.autoplay = true;
+                videoParentDom.appendChild(videoDom);
+                cameraNameDom = document.createElement('div');
+                cameraNameDom.setAttribute('class', 'video-name');
+                cameraNameDom.innerText = cameraUrl.name;
+                videoParentDom.appendChild(cameraNameDom);
+                videoParentDomList.push(videoParentDom);
+                try {
+                  const server = new window['WebRtcStreamer'](videoDom, location.protocol + VUE_APP_URL.webRtcUrl);
+                  webRtcServer.unshift(server);
+                  await server.connect(cameraUrl.addr);
+                  videoDom.play();
+                  playerDoms.unshift(videoDom);
+                  childResolve(null);
+                } catch (error) {
+                  console.log('WebRtcStreamer 抛出异常!!!!!!');
+                  playerDoms.unshift(null);
+                  childResolve(null);
+                }
+              }
+            } else {
+              try {
+                fetch(cameraUrl.addr)
+                  .then(() => {
+                    videoParentDomList.push(['player', cameraUrl]);
+                    childResolve(null);
+                  })
+                  .catch(() => {
+                    videoParentDomList.push(['onPlayer' + index, cameraUrl]);
+                    childResolve(null);
+                  });
+              } catch (error) {
+                // console.log('可以捕获到异常吗?????');
+                childResolve(null);
+              }
+            }
+          });
+          promiseList.push(promise);
+        });
+        Promise.all(promiseList).then(() => {
+          resolve(null);
+        });
+      } else {
+        resolve(null);
+      }
     };
     playCamrea();
   }).then(() => {
+    debugger;
+    videoParentDomList.forEach((videoParentDom) => {
+      if (typeof videoParentDom[0] === 'string') {
+        if (videoParentDom[0].startsWith('onPlayer')) {
+          render(
+            h(LivePlayer, {
+              class: 'player',
+              id: videoParentDom[0],
+              muted: 'muted',
+              autoplay: true,
+              live: true,
+              videoUrl: videoParentDom[1].addr,
+              videoTitle: videoParentDom[1].name,
+              alt: '无信号',
+              poster: '/src/assets/images/vent/noSinge.png',
+            }),
+            livePlayerDiv
+          );
+        } else {
+          render(
+            h(LivePlayer, {
+              class: 'player',
+              muted: 'muted',
+              autoplay: true,
+              live: true,
+              videoUrl: videoParentDom[1].addr,
+              videoTitle: videoParentDom[1].name,
+              alt: '无信号',
+              poster: '/src/assets/images/vent/noSinge.png',
+            }),
+            livePlayerDiv
+          );
+        }
+      } else {
+        player.appendChild(videoParentDom as Node);
+      }
+    });
+
     const players = livePlayerDiv?.getElementsByClassName('player');
     if (players && players.length) {
       for (let i = 0; i < players.length; i++) {
-        debugger;
-        const dom = players[i].getElementsByTagName('video')[0];
-        if (dom) playerDoms.push(dom);
+        try {
+          const isCanPlayer = !players[i].getAttribute('id')?.startsWith('onPlayer');
+          const dom = players[i].getElementsByTagName('video')[0];
+          if (dom && isCanPlayer) {
+            playerDoms.unshift(dom);
+          } else {
+            playerDoms.unshift(null);
+          }
+        } catch (error) {
+          console.log('可以捕获到异常吗?????');
+          playerDoms.unshift(null);
+        }
       }
     }
-    debugger
     if (webRtcServerList.length > 0) {
-      const rtspVideoList = player.getElementsByClassName('rtspVideo');
       for (let i = 0; i < webRtcServerList.length; i++) {
+        webRtcServerList[i].videoElement.parentElement.remove();
         webRtcServerList[i].disconnect();
-        rtspVideoList[webRtcServerLen - webRtcServerList.length + i].remove()
+        webRtcServerList[i] = undefined;
       }
     }
-    return { webRtcServer, playerDoms };
+
+    console.log('webRtcServerList--------->', webRtcServerList);
+
+    console.log('playerDoms--------->', playerDoms);
+    return { webRtcServerList: webRtcServer, playerDoms };
   });
 }
 

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

@@ -109,6 +109,8 @@
     },
   });
 
+  const emit = defineEmits(['submitSuccess']);
+
   const isUpdate = ref(false);
   const record = reactive({});
 
@@ -173,6 +175,7 @@
       await props.saveOrUpdate(params, isUpdate.value);
       !props.showTab ? closeModal() : '';
       await doRequest(props.list, { confirm: false });
+      emit('submitSuccess', params)
     } catch (error) {
       message.error('保存失败,请联系管理员');
     }

+ 1 - 1
src/views/vent/deviceManager/deviceTable/index.vue

@@ -124,7 +124,7 @@
           labelField: 'strname',
           valueField: 'id',
         },
-      }
+      },
     )
   };
 

+ 81 - 0
src/views/vent/deviceManager/equipManager/component/DeviceModal.vue

@@ -0,0 +1,81 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="registerModal"
+    :title="title"
+    width="1000px"
+    :showCancelBtn="false"
+    :showOkBtn="false"
+    :footer="null"
+    destroyOnClose
+  > 
+    <a-tabs v-if="isEditParent" v-model:activeKey="activeKey" @change="changeTab">
+      <a-tab-pane key="1" tab="基本信息" force-render>
+        <FormModal  v-if="activeKey == '1'" :record="record" :formSchema="formSchema" @saveOrUpdate="saveOrUpdate" />
+      </a-tab-pane>
+      <a-tab-pane key="2" tab="密码设置" force-render>
+        <FormModal v-if="activeKey == '2'" :record="passwordRecord" :formSchema="passwordFormSchema" @saveOrUpdate="savePassword" />
+      </a-tab-pane>
+    </a-tabs>
+    <FormModal v-else :record="record"  :formSchema="formSchema" @saveOrUpdate="saveOrUpdate" />
+  </BasicModal>
+</template>
+
+
+<script lang="ts" setup>
+  import { ref, onMounted, reactive } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import FormModal from './FormModal.vue';
+  import { formSchema, passwordFormSchema } from '../equip.data.ts';
+  import { passwordList, editPassword } from '../equip.api.ts'
+
+  // 声明Emits
+  const emit = defineEmits(['saveOrUpdate', 'register']);  
+  const title = ref('')
+  const record = ref({})
+  const passwordRecord = ref({})
+  const isEditParent = ref(false)
+  const activeKey = ref('1')
+  //表单赋值
+  const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
+    //重置表单
+    setModalProps({ confirmLoading: true });
+    if(data.record){
+      title.value = '编辑'
+      record.value = data.record
+      if(data.record['itemValue'].split('_')[1]){
+        isEditParent.value = false
+      }else{
+        isEditParent.value = true
+        // 查询密码record
+        const result = await passwordList({ devicekind: data.record['itemValue']})
+        passwordRecord.value = Object.assign(result, { itemText: data.record['itemText'], devicekind: data.record['itemValue'] })
+      }
+    }else{
+      title.value = '新增'
+      record.value = {}
+      isEditParent.value = false
+    }
+    setModalProps({ confirmLoading: false });
+  });
+
+  function changeTab(key) {
+    if(key == '2' && !record.value['itemValue']){
+      activeKey.value = '1'
+    }
+  }
+  function saveOrUpdate(record) {
+    emit('saveOrUpdate', record)
+  }
+  function savePassword(data) {
+    editPassword(data)
+  }
+</script>
+<style scoped lang="less">
+  ::v-deep .suffix {
+    height: 32px;
+    line-height: 32px;
+    margin-left: 5px;
+    color: #fff;
+  }
+</style>

+ 72 - 0
src/views/vent/deviceManager/equipManager/component/FormModal.vue

@@ -0,0 +1,72 @@
+<template>
+  <div class="vent-form">
+    <BasicForm @register="registerForm" />
+    <div class="j-box-bottom-button offset-20" style="margin-top: 30px">
+      <div class="j-box-bottom-button-float">
+        <a-button preIcon="ant-design:sync-outlined" @click="onReset">重置</a-button>
+        <a-button type="primary" preIcon="ant-design:save-filled" @click="handleSubmit">保存</a-button>
+      </div>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+  import { inject, nextTick, watch } from 'vue';
+  import { BasicForm, useForm } from '/@/components/Form/index';
+  // 声明Emits
+  const props = defineProps({
+    formSchema: { type: Array },
+    record: {type: Object}
+  });
+
+  const emit = defineEmits(['saveOrUpdate']);
+  // const testData = inject('formData') as any;
+  //表单配置
+  const [registerForm, { resetFields, setFieldsValue, validate, reload }] = useForm({
+    schemas: props.formSchema,
+    showActionButtonGroup: false,
+  });
+
+  watch(
+    () => props.record,
+    (newV) => {
+      nextTick(() => {
+        setFieldsValue({ ...newV });
+      });
+    },
+    { immediate: true }
+  );
+
+  // 重置表单
+  async function onReset() {
+    await resetFields();
+    await setFieldsValue({ ...props.record });
+  }
+  //表单提交事件
+  async function handleSubmit(v) {
+    try {
+      let values = await validate();
+      emit('saveOrUpdate', values);
+    } finally {
+      // setModalProps({ confirmLoading: false });
+    }
+  }
+
+</script>
+<style lang="less" scoped>
+  @ventSpace: zxm;
+  .j-box-bottom-button-float {
+    border: none !important;
+    padding-bottom: 30px;
+    left: 0px !important;
+    right: 0px !important;
+    bottom: 0px !important;
+  }
+  .vent-form {
+    max-height: 700px; 
+    overflow-y: auto;
+    
+    .@{ventSpace}-select-selection-item {
+      color: rgba(255, 255, 255, 1) !important;
+    }
+  }
+</style>

+ 5 - 30
src/views/vent/deviceManager/comment/normalBtnTable.vue → src/views/vent/deviceManager/equipManager/component/normalBtnTable.vue

@@ -27,7 +27,7 @@
         <slot name="filterCell" v-bind="{ column, record }"></slot>
       </template>
     </BasicTable>
-    <DeviceModal @register="registerModal" @saveOrUpdate="saveOrUpdateHandler" :showTab="showTab" :deviceType="deviceType" />
+    <DeviceModal @register="registerModal" @saveOrUpdate="saveOrUpdateHandler" />
   </div>
 </template>
 
@@ -50,11 +50,6 @@
       // required: true,
       default: () => [],
     },
-    searchFormSchema: {
-      type: Array,
-      required: true,
-      default: () => [],
-    },
     formSchema: {
       type: Array,
       required: true,
@@ -63,30 +58,14 @@
       type: Function,
       required: true,
     },
-    getImportUrl: {
-      type: String,
-      required: true,
-    },
-    getExportUrl: {
-      type: String,
-      required: true,
-    },
     deleteById: {
       type: Function,
       required: true,
     },
-    batchDelete: {
-      type: Function,
-      // required: true,
-    },
     saveOrUpdate: {
       type: Function,
       required: true,
     },
-    pointList: {
-      type: Function,
-      // required: true,
-    },
     showTab: {
       type: Boolean,
       default: false,
@@ -101,16 +80,12 @@
       type: String,
     },
   });
-
+  const emit = defineEmits(['submitSuccess']);
   const isUpdate = ref(false);
   //lxh
   let dictId = ref(null);
   const record = reactive({});
 
-  provide('formSchema', props.formSchema);
-  provide('isUpdate', isUpdate);
-  provide('formData', record);
-  provide('deviceType', props.deviceType);
   // const glob = useGlobSetting();
   const [registerModal, { openModal, closeModal }] = useModal();
 
@@ -182,7 +157,7 @@
       delete record[key];
     }
     isUpdate.value = false;
-    openModal(true);
+    openModal(true, {addParent: true});
   }
   /**
    * 新增下级
@@ -194,7 +169,7 @@
       delete record[key];
     }
     isUpdate.value = false;
-    openModal(true);
+    openModal(true, { addParent: false });
   }
   /**
    * 编辑事件
@@ -245,7 +220,7 @@
         label: '删除',
         popConfirm: {
           title: '是否确认删除',
-          confirm: handleDelete.bind(null, record),
+          confirm: handleDelete.bind(null, record.id),
         },
       },
       // {

+ 7 - 0
src/views/vent/deviceManager/equipManager/equip.api.ts

@@ -7,6 +7,9 @@ enum Api {
   //   selectDevice = '/jeecg-system/sys/dict/DeviceKind/query',
   deleteById = '/sys/dict/DeviceKind/delete',
   //   queryDevice = '/sys/dict/DeviceKind/query',
+
+  password = '/ventanaly-device/safety/devicePwd/edit',
+  passwordList = '/ventanaly-device/safety/devicePwd/queryByDeviceKind',
 }
 // /**
 //  * 列表接口
@@ -43,3 +46,7 @@ export const saveOrUpdate = (params, isUpdate) => {
   const url = isUpdate ? Api.edit : Api.save;
   return isUpdate ? defHttp.put({ url: url, params }) : defHttp.post({ url: url, params });
 };
+
+export const editPassword = (params) => defHttp.put({ url: Api.password, params });
+
+export const passwordList = (params) => defHttp.get({ url: Api.passwordList, params });

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

@@ -19,7 +19,7 @@ export const columns: BasicColumn[] = [
     dataIndex: 'description_dictText',
     width: 100,
   },
- 
+
   {
     title: '排序',
     dataIndex: 'sortOrder',
@@ -27,6 +27,48 @@ export const columns: BasicColumn[] = [
   },
 ];
 
+export const passwordFormSchema: FormSchema[] = [
+  {
+    label: '值',
+    field: 'devicekind',
+    component: 'Input',
+    show: false,
+  },
+  {
+    label: '名称',
+    field: 'itemText',
+    component: 'Input',
+  },
+  {
+    label: '是否校验密码',
+    field: 'bpass',
+    component: 'RadioGroup',
+    defaultValue: 0,
+    componentProps: {
+      options: [
+        {
+          label: '是',
+          value: 1,
+        },
+        {
+          label: '否',
+          value: 0,
+        },
+      ],
+    },
+  },
+  {
+    label: '旧密码',
+    field: 'oldPassword',
+    component: 'InputPassword',
+  },
+  {
+    label: '新密码',
+    field: 'password',
+    component: 'InputPassword',
+  },
+];
+
 export const formSchema: FormSchema[] = [
   {
     label: '',
@@ -60,7 +102,7 @@ export const formSchema: FormSchema[] = [
     field: 'description',
     component: 'JDictSelectTag',
     componentProps: {
-      dictCode: 'kindtype ',  
+      dictCode: 'kindtype ',
       placeholder: '请选择所属系统',
     },
     // colProps: { span: 6 },
@@ -72,3 +114,4 @@ export const formSchema: FormSchema[] = [
     component: 'InputNumber',
   },
 ];
+

+ 3 - 2
src/views/vent/deviceManager/equipManager/index.vue

@@ -15,9 +15,10 @@
 
 <script lang="ts" name="system-user" setup>
   //ts语法
-  import NormalTable from '../comment/normalBtnTable.vue';
+  import NormalTable from './component/normalBtnTable.vue';
   import { columns, formSchema } from './equip.data';
-  import { list, saveOrUpdate, deleteById } from './equip.api';
+  import { list, saveOrUpdate, deleteById, editPassword } from './equip.api';
+
 </script>
 
 <style scoped lang="less"></style>

+ 86 - 0
src/views/vent/home/clique/clique.data.ts

@@ -0,0 +1,86 @@
+export const airVolumeMonitorKey = [
+  {
+    code: 'name',
+    value: '矿井名称',
+  },
+  {
+    code: 'jin',
+    value: '总进风量',
+  },
+  {
+    code: 'hui',
+    value: '总回风量',
+  },
+  {
+    code: 'xufeng',
+    value: '总需风量',
+  },
+];
+export const airVolumeMonitor = [
+  {
+    name: '大柳塔',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+  {
+    name: '大柳塔',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+  {
+    name: '大柳塔',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+  {
+    name: '大柳塔',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+  {
+    name: '大柳塔',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+  {
+    name: '大柳塔',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+  {
+    name: '大柳塔',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+  {
+    name: '大柳塔',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+  {
+    name: '大柳塔',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+  {
+    name: '大柳塔',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+  {
+    name: '大柳塔1111',
+    jin: 10215,
+    hui: 10215,
+    xufeng: 10215,
+  },
+];

+ 111 - 0
src/views/vent/home/clique/index.vue

@@ -0,0 +1,111 @@
+<template>
+  <div class="header">1111</div>
+  <div class="container-box">
+    <div class="left-box lr-box">
+      <div class="lr-top air-monitor">
+        <div class="column-header">
+          <div class="header-item" v-for="(item, index) in airVolumeMonitorKey" :key="index">{{ item.value }}</div>
+        </div>
+        <div class="column-container">
+          <div class="column-item" v-for="(airVolume, index) in airVolumeMonitor" :key="index">
+            <div class="item-column" v-for="(item, key) in airVolumeMonitorKey" :key="key">{{ airVolume[item.code] }}</div>
+          </div>
+        </div>
+      </div>
+      <div class="lr-bottom warning-monitor"></div>
+    </div>
+    <div class="center-box ">
+      <div class="center-container file-list"></div>
+    </div>
+    <div class="right-box lr-box">
+      <div class="lr-top scene-monitor"></div>
+      <div class="lr-bottom tunnel-statistic">
+        
+      </div>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+  import { airVolumeMonitorKey, airVolumeMonitor } from './clique.data'
+</script>
+<style lang="less" scoped>
+  .header{
+    width: 100%;
+    height: 100px;
+    background-color: #ffffff11;
+  }
+  .container-box{
+    height: calc(100% - 32px);
+    display: flex;
+    margin: 16px 10px;
+    .lr-box{
+      width: 400px;
+      height: calc(100% - 50px);
+      position: relative;
+      top: -50px;
+      background-color: #ffffff11;
+    }
+    .center-box{
+      flex: 1;
+      margin: 0 16px;
+      .center-container{
+        height: 500px;
+        position: fixed;
+        bottom: 0;
+        background-color: #ffffff11;
+      }
+    }
+    .air-monitor{
+      .column-header{
+        width: 100%;
+        display: flex;
+        justify-content: center;
+        color: aqua;
+        height: 80px;
+        line-height: 80px;
+        .header-item{
+          width: 25%;
+          text-align: center;
+        }
+      }
+      .column-container{
+        height: 400px;
+        overflow-y: auto;
+        &:hover {
+          overflow-y: auto;
+          & > .column-item{
+            animation-play-state: paused;
+            // animation: move1 2s linear;
+          }
+        }
+        .column-item{
+          width: 100%;
+          display: flex;
+          justify-content: center;
+          color: #fff;
+          height: 60px;
+          animation: move 5s linear infinite;
+          .item-column{
+            width: 25%;
+            text-align: center;
+          }
+        }
+      }
+      @keyframes move {
+        0% {
+          transform: translateY(0px);
+        }
+        100% {
+          transform: translateY(-260px);
+        }
+      }
+
+      @keyframes move1 {
+        0% {
+          transform: translateY(0px);
+        }
+      }
+      
+    }
+  }
+</style>

+ 116 - 0
src/views/vent/home/colliery/index.vue

@@ -0,0 +1,116 @@
+<template>
+  <div class="header">1111</div>
+  <div class="container-box">
+    <div class="left-box lr-box">
+      <div class="lr-top air-monitor">
+        
+      </div>
+      <div class="lr-bottom warning-monitor"></div>
+    </div>
+    <div class="center-box ">
+      <div class="center-container file-list"></div>
+    </div>
+    <div class="right-box lr-box">
+      <div class="lr-top scene-monitor"></div>
+      <div class="lr-bottom tunnel-statistic">
+
+      </div>
+    </div>
+  </div>
+</template>
+<script lang="ts" setup>
+
+</script>
+<style lang="less" scoped>
+.header {
+  width: 100%;
+  height: 100px;
+  background-color: #ffffff11;
+}
+
+.container-box {
+  height: calc(100% - 32px);
+  display: flex;
+  margin: 16px 10px;
+
+  .lr-box {
+    width: 400px;
+    height: calc(100% - 50px);
+    position: relative;
+    top: -50px;
+    background-color: #ffffff11;
+  }
+
+  .center-box {
+    flex: 1;
+    margin: 0 16px;
+
+    .center-container {
+      height: 500px;
+      position: fixed;
+      bottom: 0;
+      background-color: #ffffff11;
+    }
+  }
+
+  .air-monitor {
+    .column-header {
+      width: 100%;
+      display: flex;
+      justify-content: center;
+      color: aqua;
+      height: 80px;
+      line-height: 80px;
+
+      .header-item {
+        width: 25%;
+        text-align: center;
+      }
+    }
+
+    .column-container {
+      height: 400px;
+      overflow-y: auto;
+
+      &:hover {
+        overflow-y: auto;
+
+        &>.column-item {
+          animation-play-state: paused;
+          // animation: move1 2s linear;
+        }
+      }
+
+      .column-item {
+        width: 100%;
+        display: flex;
+        justify-content: center;
+        color: #fff;
+        height: 60px;
+        animation: move 10s linear infinite;
+
+        .item-column {
+          width: 25%;
+          text-align: center;
+        }
+      }
+    }
+
+    @keyframes move {
+      0% {
+        transform: translateY(0px);
+      }
+
+      100% {
+        transform: translateY(-269px);
+      }
+    }
+
+    @keyframes move1 {
+      0% {
+        transform: translateY(0px);
+      }
+    }
+
+  }
+}</style>

+ 0 - 1
src/views/vent/monitorManager/alarmMonitor/index.vue

@@ -482,7 +482,6 @@
           align-items: center;
           justify-content: center;
           padding: 3px;
-
           animation: move 10s linear infinite;
           
           .level-text{

+ 2 - 1
src/views/vent/monitorManager/camera/index.vue

@@ -24,8 +24,9 @@
   ]
 
   function getVideo() {
+    const ip = VUE_APP_URL.webRtcUrl;
     for(let i =1; i<= num; i++){
-      const webRtcServer = new window['WebRtcStreamer']('video'+i , location.protocol + '//192.168.183.216:8000')
+      const webRtcServer = new window['WebRtcStreamer']('video'+i , location.protocol + ip)
       webRtcServerList.push(webRtcServer)
       webRtcServer.connect('rtsp://admin:admin12345@192.168.183.64:554/Streaming/Channels/1')
       // webRtcServer.connect(urls[i])

+ 1 - 1
src/views/vent/monitorManager/compressor/components/nitrogenHome.vue

@@ -123,7 +123,7 @@
             </template>
           </ventBox1>
           <div class="vent-margin-t-10">
-            <LivePlayer id="fm-player1" style="height: 250px;" ref="player1" :videoUrl="flvURL1()" muted live loading controls />
+            <!-- <LivePlayer id="fm-player1" style="height: 250px;" ref="player1" :videoUrl="flvURL1()" muted live loading controls /> -->
           </div>
         </div>
       </div>

+ 112 - 3
src/views/vent/monitorManager/deviceMonitor/components/device/device.data.ts

@@ -1,6 +1,4 @@
-
-import { FormSchema } from '/@/components/Table';
-import dayjs from 'dayjs';
+import { BasicColumn } from '/@/components/Table';
 
 export const chartsColumns = (deviceType) => {
   if (deviceType === '') {
@@ -110,3 +108,114 @@ export const locationList = [
 //     },
 //   },
 // ];
+export const majorColumns: BasicColumn[] = [
+  {
+    title: '序号',
+    dataIndex: '',
+    key: 'rowIndex',
+    width: 60,
+    align: 'center',
+    customRender: ({ index }) => {
+      return `${index}`;
+    },
+  },
+  {
+    title: '测段名称',
+    align: 'center',
+    dataIndex: 'name',
+    width: 110,
+  },
+  {
+    title: '始点',
+    children: [
+      {
+        title: '测点位置',
+        align: 'center',
+        dataIndex: 'name1',
+        width: 140,
+      },
+      {
+        title: '风压(Pa)',
+        align: 'center',
+        dataIndex: 'pressure1',
+        width: 100,
+      },
+      // {
+      //   title:'风压(KPa)',
+      //   align:"center",
+      //   dataIndex: 'name1'
+      // },
+      {
+        title: '密度(kg/m3)',
+        align: 'center',
+        dataIndex: 'density1',
+        width: 100,
+      },
+      {
+        title: '标高(m)',
+        align: 'center',
+        dataIndex: 'elevation1',
+        width: 100,
+      },
+    ],
+  },
+  {
+    title: '末点',
+    children: [
+      {
+        title: '测点位置',
+        align: 'center',
+        dataIndex: 'name2',
+        width: 140,
+      },
+      {
+        title: '风压(Pa)',
+        align: 'center',
+        dataIndex: 'pressure2',
+        width: 100,
+      },
+      // {
+      //   title:'风压(KPa)',
+      //   align:"center",
+      //   dataIndex: 'name1'
+      // },
+      {
+        title: '密度(kg/m3)',
+        align: 'center',
+        dataIndex: 'density2',
+        width: 100,
+      },
+      {
+        title: '标高(m)',
+        align: 'center',
+        dataIndex: 'elevation2',
+        width: 100,
+      },
+    ],
+  },
+  {
+    title: '风量(m³/min)',
+    align: 'center',
+    dataIndex: 'm3',
+    width: 110,
+  },
+
+  {
+    title: '阻力(Pa)',
+    align: 'center',
+    dataIndex: 'drag',
+    width: 100,
+  },
+  {
+    title: '风阻(Ns²/m^8)',
+    align: 'center',
+    dataIndex: 'wdrag',
+    width: 110,
+  },
+  {
+    title: '更新时间',
+    dataIndex: 'datatime',
+    align: 'center',
+    width: 127,
+  },
+];

+ 33 - 13
src/views/vent/monitorManager/deviceMonitor/components/device/index.vue

@@ -46,7 +46,7 @@
       </div>
     </div>
 
-    <div class="bottom-tabs-box" @mousedown="setDivHeight($event, 230, scroll, 125)" id="monitorBox">
+    <div class="bottom-tabs-box" @mousedown="setDivHeight($event, 170, scroll, 125)" id="monitorBox">
       <!-- <dv-border-box8 :dur="5"  :style="`padding: 5px; height: ${scroll.y + 100}px`" > -->
       <div :style="`padding: 5px; height: ${scroll.y + 100}px`">
         <div class="to-small" @click="toHome"></div>
@@ -64,7 +64,20 @@
             <template v-if="deviceType == 'fan' && activeKey == '1'">
               <GroupMonitorTable :dataSource="dataSource" :columnsType="`${deviceType}_monitor`" />
             </template>
-            <template v-else-if="activeKey == '1'">
+            <template v-else-if="deviceType == 'majorpath' && activeKey == '1'">
+              <a-table :columns="majorColumns" :data-source="dataSource" bordered :scroll="scroll" :pagination="false">
+                <template #bodyCell="{ column, record }">
+                  <!-- <template v-if="column.dataIndex === 'operation'">
+                    <a class="action-link" @click="handleOpen(record)">编辑</a>
+                    <a class="action-link vent-margin-l-10" @click="handleDelete(record)">删除</a>
+                  </template>
+                  <template v-if="column.dataIndex === 'operation1'">
+                    <a class="action-link" @click="handleOpen()">新增</a>
+                  </template> -->
+                </template>
+              </a-table>
+            </template>
+            <template v-else="activeKey == '1'">
               <MonitorTable ref="monitorTable" :columnsType="`${deviceType}_monitor`" :dataSource="dataSource"
                 design-scope="device_monitor" :isShowPagination="false" :isShowActionColumn="true" title="设备监测"
                 :scroll="scroll">
@@ -194,6 +207,7 @@ import { SvgIcon } from '/@/components/Icon';
 import { getActions } from '/@/qiankun/state';
 import { useRouter } from 'vue-router';
 import { setDivHeight } from '/@/utils/event';
+import { majorColumns } from  './device.data'
 // import { BorderBox8 as DvBorderBox8 } from '@kjgl77/datav-vue3';
 
 
@@ -239,7 +253,7 @@ const systemID = ref('') // 系统监测时,系统id
 const selectedKeys = ref<string[]>([]);
 const expandedKeys = ref<string[]>(['0-0-0-1']);
 const scroll = reactive({
-  y: 220
+  y: 180
 })
 const treeData = ref<TreeProps['treeData']>([]);
 
@@ -335,19 +349,25 @@ async function getDataSource() {
         return Object.assign(data, readData);
       })
       if (item.type != 'sys') {
-        deviceArr.unshift({ deviceType: item.type, deviceName: item['typeName'] ? item['typeName'] : item['datalist'][0]['typeName'], datalist: data })
+        if(item.type === 'majorpath'){
+          deviceArr.unshift({ deviceType: item.type, deviceName: item['typeName'], datalist: item['datalist'][0]['paths'] })
+        }else {
+          deviceArr.unshift({ deviceType: item.type, deviceName: item['typeName'] ? item['typeName'] : item['datalist'][0]['typeName'], datalist: data })
+        }
       }
     })
 
     deviceList.value = deviceArr
     if (deviceArr.length > 0) {
-      if (deviceArr[1]) {
-        deviceActive.value = deviceArr[1].deviceType
-        monitorChange(1)
-      } else {
-        deviceActive.value = deviceArr[0].deviceType
-        monitorChange(0)
-      }
+      // if (deviceArr[1]) {
+      //   deviceActive.value = deviceArr[1].deviceType
+      //   monitorChange(1)
+      // } else {
+      //   deviceActive.value = deviceArr[0].deviceType
+      //   monitorChange(0)
+      // }
+      deviceActive.value = deviceArr[0].deviceType
+      monitorChange(0)
     }
   } else {
     const res = await list({ devicetype: deviceType.value, pagetype: 'normal' })
@@ -869,7 +889,7 @@ onUnmounted(() => {
 .bottom-tabs-box {
 
   // position: relative;
-  // height: 320px !important;
+  // height: 330px !important;
   .tabs-box {
     width: calc(100% - 12px) !important;
     bottom: 3px !important;
@@ -1001,7 +1021,7 @@ onUnmounted(() => {
     color: #fff;
     cursor: pointer;
     position: absolute;
-    right: 120px;
+    right: 100px;
     top: -6px;
     padding: 5px;
     border-radius: 5px;

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

@@ -15,7 +15,7 @@
             </div>
             <div class="item-container">
               <div class="title">一氧化碳</div>
-              <div class="value">{{ posMonitor.coval ? posMonitor.coval : '-' }} <span>ppm</span> </div>
+              <div class="value">{{ (posMonitor.coval !== undefined && posMonitor.coval !== null) ? posMonitor.coval : '-' }} <span>ppm</span> </div>
             </div>
           </div>
           <div class="top-item">
@@ -24,7 +24,7 @@
             </div>
             <div class="item-container">
               <div class="title">二氧化碳</div>
-              <div class="value">{{ posMonitor.co2val ? posMonitor.co2val: '-' }} <span>%</span></div>
+              <div class="value">{{ (posMonitor.co2val !== undefined && posMonitor.co2val !== null) ? posMonitor.co2val: '-' }} <span>%</span></div>
             </div>
           </div>
           <div class="top-item">
@@ -33,7 +33,7 @@
             </div>
             <div class="item-container">
               <div class="title">甲烷</div>
-              <div class="value">{{ posMonitor.gasval ? posMonitor.gasval : '-' }} <span>%</span></div>
+              <div class="value">{{ (posMonitor.gasval !== undefined && posMonitor.gasval !== null) ? posMonitor.gasval : '-' }} <span>%</span></div>
             </div>
           </div>
           <div class="top-item">
@@ -42,7 +42,7 @@
             </div>
             <div class="item-container">
               <div class="title">乙烯</div>
-              <div class="value">{{ posMonitor.ch2val ? posMonitor.ch2val : '-' }} <span>ppm</span></div>
+              <div class="value">{{ (posMonitor.ch2val !== undefined && posMonitor.ch2val !== null) ? posMonitor.ch2val : '-' }} <span>ppm</span></div>
             </div>
           </div>
           <div class="top-item">
@@ -51,7 +51,7 @@
             </div>
             <div class="item-container">
               <div class="title">乙炔</div>
-              <div class="value">{{ posMonitor.chval ? posMonitor.chval : '-' }} <span>ppm</span></div>
+              <div class="value">{{ (posMonitor.chval !== undefined && posMonitor.chval !== null) ? posMonitor.chval : '-' }} <span>ppm</span></div>
             </div>
           </div>
           <div class="top-item">
@@ -60,7 +60,7 @@
             </div>
             <div class="item-container">
               <div class="title">氧气</div>
-              <div class="value">{{ posMonitor.o2val ? posMonitor.o2val : '-' }} <span>%</span></div>
+              <div class="value">{{ (posMonitor.o2val !== undefined && posMonitor.o2val !== null) ? posMonitor.o2val : '-' }} <span>%</span></div>
             </div>
           </div>
           <div class="top-item warning-box">

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

@@ -45,7 +45,7 @@
                     <div v-if="data.code !== 'level' && data.code !== 'resistance'" class="item-value">{{ pageData[data.code] }}
                     </div>
                     <div v-if="data.code == 'level'" class="item-value">
-                      <span class="signal-round signal-round-run"></span>
+                      <span class="signal-round signal-round-run" :class="{'signal-round-run': Number(pageData.dTotalArea) <= 2, 'signal-round-red': Number(pageData.dTotalArea) > 2 }"></span>
                     </div>
                     <div v-if="data.code == 'resistance'" class="item-value">{{ totalPa }}</div>
                   </div>
@@ -216,7 +216,6 @@
 <script setup lang="ts">
 import { ref, onMounted, onUnmounted, defineEmits, defineProps, watch, reactive } from 'vue';
 import { Icon as SvgIcon } from '/@/components/Icon';
-import { Progress } from 'ant-design-vue';
 import { BorderBox11, BorderBox1, ScrollBoard as DvScrollBoard } from '@kjgl77/datav-vue3';
 import { sensorColumns, networkColumns, warningColumns, deviceTab, SensorType, NetworkType, windowColumns, gateColumns, WindowType, GateType, solveTimesData } from './network.data'
 import dayjs from 'dayjs'
@@ -239,7 +238,7 @@ const pageData = reactive({
   totalToNum: '-',
   totallength: '-', // 总长
   level: '-',
-  hole: '-',
+  dTotalArea: '-',
   sensorDataList: <SensorType[]>[],
   networkDataList: <NetworkType[]>[],
   gateDataList: <GateType[]>[],
@@ -259,7 +258,7 @@ const rate2 = ref(95 + '')
 const rate3 = ref(95 + '')
 
 
-const analysisDetailDataList = ref([
+const analysisDetailDataList = [
   {
     code: 'totallength',
     name: '通风巷道规模(m)',
@@ -277,11 +276,11 @@ const analysisDetailDataList = ref([
   //   icon: 'path-icon3'
   // },
   {
-    code: 'hole',
+    code: 'dTotalArea',
     name: '等积孔(㎡)',
     icon: 'path-icon4'
   },
-])
+]
 const maxPaths = ref([])
 const activePath = ref(1)
 let solveTimes: [string, string][] = []
@@ -314,7 +313,8 @@ function analyzePageResult(resultData){
     pageData.totalEnterNum = solutionresult['TotalInQ'] != null ? formatNum(Number(solutionresult['TotalInQ'])) : '-';
     pageData.totalToNum = solutionresult['TotalOutQ'] != null ? formatNum(Number(solutionresult['TotalOutQ'])): '-';
     pageData.totallength = solutionresult['TotalLength'] != null ? formatNum(Number(solutionresult['TotalLength'])) : '-';
-
+    pageData.dTotalArea = solutionresult['dTotalArea'] != null ? formatNum(Number(solutionresult['dTotalArea'])) : '-';
+    
     if (solutionresult['tuns'])
 
       for (const key in solutionresult['tuns']) {

+ 2 - 0
src/views/vent/monitorManager/deviceMonitor/components/network/network.data.ts

@@ -48,11 +48,13 @@ export const sensorColumns: BasicColumn[] = [
   {
     title: '风速(m/s)',
     dataIndex: 'va',
+    width: 100,
     align: 'center',
   },
   {
     title: '风量',
     dataIndex: 'm3',
+    width: 100,
     align: 'center',
   },
 ];

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

@@ -584,6 +584,7 @@
       deviceid: selectData.deviceID,
       devicetype: 'fanlocal_systeml_zj',
       paramcode: '',
+      password: passWord.value,
       value: null,
     };
     if (handType === 'startSmoke') {
@@ -591,13 +592,13 @@
       // 启动风机
       if (mainWindIsShow1.value === 'open' && mainWindIsShow2.value === 'stop') {
         playSmoke(handType, 'top', frequency, 'open');
-        data.paramcode = 'fanRun1';
+        data.paramcode = 'CtrlFan1Start';
         deviceControlApi(data).then((res) => {
           console.log('设备操作结果', res);
         });
       } else if (mainWindIsShow2.value === 'open' && mainWindIsShow1.value === 'stop') {
         playSmoke(handType, 'down', frequency, 'open');
-        data.paramcode = 'fanRun2';
+        data.paramcode = 'CtrlFan2Start';
         deviceControlApi(data).then((res) => {
           console.log('设备操作结果', res);
         });
@@ -608,9 +609,9 @@
       // 调频
       playSmoke(handType, 'top', frequency, '');
       if (mainWindIsShow1.value === 'open') {
-        data.paramcode = 'power1';
+        data.paramcode = 'Fan1FreqHz';
       } else if (mainWindIsShow2.value === 'open') {
-        data.paramcode = 'power2';
+        data.paramcode = 'Fan2FreqHz';
       }
       data.value = frequency;
       deviceControlApi(data).then((res) => {

+ 12 - 3
src/views/vent/monitorManager/gasPumpMonitor/components/gasPumpHome.vue

@@ -155,6 +155,10 @@ const props = defineProps({
   deviceId: {
     type: String,
     require: true
+  },
+  deviceType: {
+    type: String,
+    require: true
   }
 })
 
@@ -207,7 +211,7 @@ function getMonitor(flag?) {
 };
 
 async function getDataSource(systemID) {
-  const res = await list({ devicetype: 'sys', systemID });
+  const res = await list({ devicetype: props.deviceType, ids: systemID });
   const result = res.msgTxt;
   result.forEach(item => {
 
@@ -222,7 +226,12 @@ function handlerDevice(code, data) {
 }
 
 watch(() => props.deviceId, () => {
-  setModelType('gasPumpBase')
+  if(props.deviceType == 'pump_over'){
+    setModelType('gasPump')
+  }else if(props.deviceType == 'pump_under') {
+    setModelType('gasPumpUnder')
+  }
+  
   loading.value = true
 })
 
@@ -233,7 +242,7 @@ onBeforeMount(() => {
 onMounted(() => {
   loading.value = true;
   mountedThree().then(async () => {
-    await setModelType('gasPumpBase');
+    await setModelType('gasPump');
     loading.value = false;
     timer = null
     await getMonitor(true)

+ 0 - 0
src/views/vent/monitorManager/gasPumpMonitor/gasPump.threejs.base.ts → src/views/vent/monitorManager/gasPumpMonitor/gasPump.threejs.over.ts


+ 32 - 5
src/views/vent/monitorManager/gasPumpMonitor/gasPump.threejs.ts

@@ -1,14 +1,16 @@
 import * as THREE from 'three';
 import UseThree from '../../../../utils/threejs/useThree';
-import gasPumpBase from './gasPump.threejs.base';
+import gasPumpBase from './gasPump.threejs.over';
+import gasPumpUnder from './gasPump.threejs.under';
 import { animateCamera, setModalCenter } from '/@/utils/threejs/util';
 import useEvent from '../../../../utils/threejs/useEvent';
 
 // 模型对象、 文字对象
 let model: UseThree | undefined,
   gasPumpBaseObj: gasPumpBase | undefined,
+  gasPumpUnderObj: gasPumpUnder | undefined,
   group: THREE.Object3D | undefined,
-  gasPumpType = 'gasPumpBase';
+  gasPumpType = 'gasPump';
 
 const { mouseDownFn } = useEvent();
 
@@ -16,7 +18,7 @@ const { mouseDownFn } = useEvent();
 const mouseEvent = (event) => {
   if (event.button == 0) {
     mouseDownFn(<UseThree>model, <THREE.Object3D>group, event, (intersects) => {
-      if (gasPumpType === 'gasPumpBase') {
+      if (gasPumpType === 'gasPump') {
         // gasPumpBaseObj.mousedownModel.call(gasPumpBaseObj, intersects);
       }
     });
@@ -38,7 +40,7 @@ const render = () => {
 };
 
 export const addgasPumpText = (selectData) => {
-  if (gasPumpType === 'gasPumpBase') {
+  if (gasPumpType === 'gasPump') {
     // return gasPumpBaseObj.addgasPumpText.call(gasPumpBaseObj, selectData);
   }
 };
@@ -47,7 +49,10 @@ export const addgasPumpText = (selectData) => {
 export const setModelType = (type) => {
   gasPumpType = type;
   return new Promise((resolve) => {
-    if (gasPumpType === 'gasPumpBase' && gasPumpBaseObj && gasPumpBaseObj.group) {
+    if (gasPumpType === 'gasPump' && gasPumpBaseObj && gasPumpBaseObj.group) {
+      if (model?.scene?.getObjectByName('gasPumpUnder') && gasPumpUnderObj && gasPumpUnderObj.group) {
+        model.scene.remove(gasPumpUnderObj.group);
+      }
       group = gasPumpBaseObj.group;
       const oldCameraPosition = { x: 15.9074, y: 5.40264, z: 27.12551 };
       setTimeout(async () => {
@@ -64,6 +69,26 @@ export const setModelType = (type) => {
 
       resolve(null);
     }
+    if (gasPumpType === 'gasPumpUnder' && gasPumpUnderObj && gasPumpUnderObj.group) {
+      if (model?.scene?.getObjectByName('gasPump') && gasPumpBaseObj && gasPumpBaseObj.group) {
+        model.scene.remove(gasPumpBaseObj.group);
+      }
+      group = gasPumpUnderObj.group;
+      const oldCameraPosition = { x: 15.9074, y: 5.40264, z: 27.12551 };
+      setTimeout(async () => {
+        model?.scene?.add(group);
+        await animateCamera(
+          oldCameraPosition,
+          { x: 0.544, y: 0.3335, z: 0.29222 },
+          { x: 3.3224253129798633, y: 2.3189559678790963, z: 5.1822770949018695 },
+          { x: 0.7866051731597254, y: -0.21180783848684975, z: 0.20318654152228077 },
+          model,
+          0.6
+        );
+      }, 300);
+
+      resolve(null);
+    }
   });
 };
 
@@ -76,6 +101,8 @@ export const mountedThree = () => {
     gasPumpBaseObj = new gasPumpBase(model);
     await gasPumpBaseObj.mountedThree();
 
+    gasPumpUnderObj = new gasPumpUnder(model);
+    await gasPumpUnderObj.mountedThree();
     addMouseEvent();
     // render();
     model.animate();

+ 57 - 0
src/views/vent/monitorManager/gasPumpMonitor/gasPump.threejs.under.ts

@@ -0,0 +1,57 @@
+import * as THREE from 'three';
+
+// import * as dat from 'dat.gui';
+// const gui = new dat.GUI();
+// gui.domElement.style = 'position:absolute;top:100px;left:10px;z-index:99999999999999';
+
+class gasPumpUnder {
+  model;
+  modelName = 'gasPumpUnder';
+  group: THREE.Object3D | null = null;
+
+  constructor(model) {
+    this.model = model;
+  }
+
+  addLight() {
+    const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
+    directionalLight.position.set(-48, 107, 36);
+    this.group?.add(directionalLight);
+    directionalLight.target = this.group as THREE.Object3D;
+
+    // gui.add(directionalLight.position, 'x', -500, 800);
+    // gui.add(directionalLight.position, 'y', -500, 800);
+    // gui.add(directionalLight.position, 'z', -500, 800);
+
+    // const pointLight2 = new THREE.PointLight(0xffffff, 2, 500);
+    // pointLight2.position.set(-113, 29, 10);
+    // // light2.castShadow = true
+    // pointLight2.shadow.bias = -0.05;
+    // this.group?.add(pointLight2);
+
+    // gui.add(pointLight2.position, 'x', -500, 500);
+    // gui.add(pointLight2.position, 'y', -500, 500);
+    // gui.add(pointLight2.position, 'z', -500, 500);
+  }
+
+  mountedThree() {
+    return new Promise((resolve) => {
+      this.model.setGLTFModel([this.modelName]).then((gltf) => {
+        this.group = gltf[0];
+        if (this.group) {
+          // this.group?.scale.set(0.1, 0.1, 0.1);
+          // this.group.position.y += 40;
+          resolve(null);
+          this.addLight();
+        }
+      });
+    });
+  }
+
+  destroy() {
+    this.model.clearGroup(this.group);
+    this.model = null;
+    this.group = null;
+  }
+}
+export default gasPumpUnder;

+ 4 - 2
src/views/vent/monitorManager/gasPumpMonitor/index.vue

@@ -19,7 +19,7 @@
   <div class="scene-box">
     <customHeader :fieldNames="{ label: 'strinstallpos', value: 'deviceID', options: 'children' }" :options = 'options' @change="getSelectRow" :optionValue="optionValue">瓦斯抽采泵站监测与管控</customHeader>
     <div class="center-container">
-      <gasPumpHome v-if="activeKey == 'monitor'" :deviceId = 'optionValue' />
+      <gasPumpHome v-if="activeKey == 'monitor'" :deviceId = 'optionValue' :device-type="currentDeviceType" />
       <div v-else class="history-group">
         <div class="device-button-group" v-if="deviceList.length > 0">
           <div class="device-button" :class="{ 'device-active': deviceActive == device.deviceType }" v-for="(device, index) in deviceList" :key="index" @click="deviceChange(index)">{{ device.deviceName }}</div>
@@ -69,6 +69,7 @@ const selectRowIndex = ref(0);
 const dataSource = ref([])
 
 const optionValue = ref('')
+const currentDeviceType = ref('')
 
 // 监测数据
 const selectData = reactive({});
@@ -101,7 +102,7 @@ async function getDeviceList() {
 };
 
 async function getSysDataSource () {
-  const res = await list({ devicetype: 'sys_dongshi', pagetype: 'normal' });
+  const res = await list({ devicetype: 'pump', pagetype: 'normal' });
   dataSource.value = res.msgTxt[0].datalist || [];
   dataSource.value.forEach((data: any) => {
     const readData = data.readData;
@@ -130,6 +131,7 @@ function getSelectRow(deviceID){
   })
   if(currentData){
     optionValue.value = currentData['deviceID']
+    currentDeviceType.value = currentData['deviceType']
     Object.assign(selectData, currentData)
   }
 }

+ 47 - 50
src/views/vent/monitorManager/gateMonitor/gate.threejs.three.ts

@@ -415,6 +415,52 @@ class Fm2 {
     // }, 1000);
   }
 
+  async initCamera(dom1?) {
+    const videoPlayer1 = dom1;
+    let monitorPlane: THREE.Mesh | null = null;
+    const canvas = await getTextCanvas(320, 180, '', 'noSinge.png');
+    const textMap = new THREE.CanvasTexture(canvas); // 关键一步
+    const textMaterial = new THREE.MeshBasicMaterial({
+      map: textMap, // 设置纹理贴图
+      transparent: true,
+      side: THREE.DoubleSide, // 这里是双面渲染的意思
+    });
+    textMaterial.blending = THREE.CustomBlending;
+    monitorPlane = this.group?.getObjectByName('noPlayer');
+    if (monitorPlane) {
+      monitorPlane.material = textMaterial;
+    } else {
+      const planeGeometry = new THREE.PlaneGeometry(100, 100); // 平面3维几何体PlaneGeometry
+      monitorPlane = new THREE.Mesh(planeGeometry, textMaterial);
+      textMaterial.dispose();
+      planeGeometry.dispose();
+    }
+    const videoPlayer = this.group.getObjectByName('player1');
+    if (videoPlayer) {
+      this.model.clearMesh(videoPlayer);
+      this.group.remove(videoPlayer);
+    }
+    const noPlayer1 = this.group.getObjectByName('noPlayer1');
+    if (noPlayer1) {
+      this.model.clearMesh(noPlayer1);
+      this.group.remove(noPlayer1);
+    }
+    if (!videoPlayer1 && videoPlayer1 === null) {
+      monitorPlane.name = 'noPlayer1';
+      monitorPlane.scale.set(0.0085, 0.0056, 0.012);
+      monitorPlane.position.set(-4.23, 0.02, -0.39);
+      this.group?.add(monitorPlane);
+    } else if (videoPlayer1) {
+      const mesh = renderVideo(this.group, videoPlayer1, 'player1');
+      if (mesh) {
+        mesh?.scale.set(-0.028, 0.0285, 1);
+        mesh?.position.set(-4.238, 0.02, -0.4);
+        mesh.rotation.y = -Math.PI;
+        this.group.add(mesh);
+      }
+    }
+  }
+
   mountedThree() {
     this.group = new THREE.Object3D();
     this.group.name = this.modelName;
@@ -429,56 +475,7 @@ class Fm2 {
         // this.deviceDetailCard();
         this.model.animate();
         if (this.model.camera && this.model.camera.layers.mask == -1) this.model.camera.layers.toggle(1);
-        setTimeout(async () => {
-          const videoPlayer1 = document.getElementById('fm-player1')?.getElementsByClassName('vjs-tech')[0];
-          if (!videoPlayer1) {
-            const textArr = [
-              {
-                text: `无信号输入`,
-                font: 'normal 40px Arial',
-                color: '#009900',
-                strokeStyle: '#002200',
-                x: 170,
-                y: 40,
-              },
-            ];
-            getTextCanvas(560, 346, textArr, '').then((canvas: HTMLCanvasElement) => {
-              const textMap = new THREE.CanvasTexture(canvas); // 关键一步
-              const textMaterial = new THREE.MeshBasicMaterial({
-                map: textMap, // 设置纹理贴图
-                transparent: true,
-                side: THREE.DoubleSide, // 这里是双面渲染的意思
-              });
-              textMaterial.blending = THREE.CustomBlending;
-              const monitorPlane = this.group?.getObjectByName('noPlayer');
-              if (monitorPlane) {
-                monitorPlane.material = textMaterial;
-              } else {
-                const planeGeometry = new THREE.PlaneGeometry(100, 100); // 平面3维几何体PlaneGeometry
-                const planeMesh = new THREE.Mesh(planeGeometry, textMaterial);
-                if (!videoPlayer1) {
-                  planeMesh.name = 'noPlayer1';
-                  planeMesh.scale.set(0.011, 0.008, 0.011);
-                  planeMesh.position.set(-4.23, -0.28, -0.39);
-                  this.group?.add(planeMesh.clone());
-                }
-                textMaterial.dispose();
-                planeGeometry.dispose();
-              }
-            });
-          } else {
-            if (videoPlayer1) {
-              const mesh = renderVideo(this.group, videoPlayer1, 'player1');
-              mesh?.scale.set(-0.028, 0.0285, 1);
-              mesh?.position.set(4.298, 0.02, -0.4);
-              mesh.rotation.y = -Math.PI;
-              this.group.add(mesh);
-            }
-          }
-
-          resolve(this.model);
-        }, 0);
-
+        this.initCamera();
         resolve(null);
       });
     });

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

@@ -72,14 +72,20 @@ export const setModelType = (type) => {
   fmType = type;
   return new Promise((resolve) => {
     // 暂停风门1动画
-    fm1.clipActionArr.frontDoor.reset();
-    fm1.clipActionArr.frontDoor.time = 0.5;
-    fm1.clipActionArr.backDoor.reset();
-    fm1.clipActionArr.backDoor.time = 0.5;
-    fm1.clipActionArr.frontDoor.stop();
-    fm1.clipActionArr.backDoor.stop();
 
     if (fmType === 'fm1' && fm1 && fm1.group) {
+      fm1.clipActionArr.frontDoor.reset();
+      fm1.clipActionArr.frontDoor.time = 0.5;
+      fm1.clipActionArr.backDoor.reset();
+      fm1.clipActionArr.backDoor.time = 0.5;
+      fm1.clipActionArr.frontDoor.stop();
+      fm1.clipActionArr.backDoor.stop();
+
+      if (fm1.frontDamperOpenMesh) fm1.frontDamperOpenMesh.visible = false;
+      if (fm1.frontDamperClosedMesh) fm1.frontDamperClosedMesh.visible = true;
+      if (fm1.backDamperOpenMesh) fm1.backDamperOpenMesh.visible = false;
+      if (fm1.backDamperClosedMesh) fm1.backDamperClosedMesh.visible = true;
+
       model.startAnimation = fm1.render.bind(fm1);
       group = fm1.group;
       group.rotation.y = 0;
@@ -100,6 +106,7 @@ export const setModelType = (type) => {
         );
       }, 300);
     } else if (fmType === 'fm2' && fm2 && fm2.group) {
+      
       fm2.clipActionArr.frontDoor.reset();
       fm2.clipActionArr.frontDoor.time = 0.5;
       fm2.clipActionArr.backDoor.reset();
@@ -134,11 +141,12 @@ export const setModelType = (type) => {
   });
 };
 
-export const initCameraCanvas = async(playerVal1?, playerVal2?) => {
+export const initCameraCanvas = async (playerVal1?, playerVal2?) => {
   if (fmType === 'fm1' && fm1) {
     return await fm1.initCamera.call(fm1, playerVal1, playerVal2);
   } else if (fmType === 'fm2' && fm2) {
-    // return fm2.initCamera.call(fm2, playerVal1, playerVal2);
+    console.log('fm2-------',playerVal1);
+    return fm2.initCamera.call(fm2, playerVal1);
   }
 };
 

+ 110 - 73
src/views/vent/monitorManager/gateMonitor/gate.threejs.two.ts

@@ -26,6 +26,11 @@ class Fm1 {
   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,
@@ -36,7 +41,7 @@ class Fm1 {
   }
 
   addLight() {
-    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.2);
+    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;
@@ -235,35 +240,35 @@ class Fm1 {
     // 判断是否点击到视频
     intersects.find((intersect) => {
       const mesh = intersect.object;
-      if (mesh.name === 'player1') {
-        if (new Date().getTime() - this.playerStartClickTime1 < 400) {
-          // 双击,视频放大
-          if (this.player1) {
-            this.player1.requestPictureInPicture();
-          }
-        }
-        this.playerStartClickTime1 = new Date().getTime();
-        return true;
-      } else if (mesh.name === 'player2') {
-        if (new Date().getTime() - this.playerStartClickTime2 < 400) {
-          // 双击,视频放大
-          if (this.player2) {
-            this.player2.requestPictureInPicture();
-          }
-        }
-        this.playerStartClickTime2 = new Date().getTime();
-        return true;
-      } else if (mesh.name.startsWith('hotPoint')) {
-        if (this.deviceDetailCSS3D) {
-          this.deviceDetailCSS3D.position.set(mesh.position.x + 0.035, mesh.position.y + 0.68, mesh.position.z + 0.02);
-          console.log('[ deviceDetailCSS3D.position ] >', this.deviceDetailCSS3D.position);
-          this.deviceDetailCSS3D.visible = true;
-          return true;
-        }
-      } else {
-        if (this.deviceDetailCSS3D) this.deviceDetailCSS3D.visible = false;
-        console.log('[ 点击事件 ] >');
-      }
+      // if (mesh.name === 'player1') {
+      //   if (new Date().getTime() - this.playerStartClickTime1 < 400) {
+      //     // 双击,视频放大
+      //     if (this.player1) {
+      //       this.player1.requestPictureInPicture();
+      //     }
+      //   }
+      //   this.playerStartClickTime1 = new Date().getTime();
+      //   return true;
+      // } else if (mesh.name === 'player2') {
+      //   if (new Date().getTime() - this.playerStartClickTime2 < 400) {
+      //     // 双击,视频放大
+      //     if (this.player2) {
+      //       this.player2.requestPictureInPicture();
+      //     }
+      //   }
+      //   this.playerStartClickTime2 = new Date().getTime();
+      //   return true;
+      // } else if (mesh.name.startsWith('hotPoint')) {
+      //   if (this.deviceDetailCSS3D) {
+      //     this.deviceDetailCSS3D.position.set(mesh.position.x + 0.035, mesh.position.y + 0.68, mesh.position.z + 0.02);
+      //     console.log('[ deviceDetailCSS3D.position ] >', this.deviceDetailCSS3D.position);
+      //     this.deviceDetailCSS3D.visible = true;
+      //     return true;
+      //   }
+      // } else {
+      //   if (this.deviceDetailCSS3D) this.deviceDetailCSS3D.visible = false;
+      //   console.log('[ 点击事件 ] >');
+      // }
       return false;
     });
   }
@@ -323,6 +328,7 @@ class Fm1 {
 
   // 播放动画
   play(handlerState, timeScale = 0.01) {
+
     let handler = () => {};
     switch (handlerState) {
       case 1: // 打开前门
@@ -334,6 +340,10 @@ class Fm1 {
           // this.clipActionArr.frontDoor.clampWhenFinished = true;
           this.clipActionArr.frontDoor.play();
           this.fmClock.start();
+
+          // 显示打开前门文字
+          if (this.frontDamperOpenMesh) this.frontDamperOpenMesh.visible = true;
+          if (this.frontDamperClosedMesh) this.frontDamperClosedMesh.visible = false;
         };
         break;
       case 2: // 关闭前门
@@ -345,6 +355,9 @@ class Fm1 {
           // this.clipActionArr.frontDoor.clampWhenFinished = true;
           this.clipActionArr.frontDoor.play();
           this.fmClock.start();
+
+          if (this.frontDamperOpenMesh) this.frontDamperOpenMesh.visible = false;
+          if (this.frontDamperClosedMesh) this.frontDamperClosedMesh.visible = true;
         };
         break;
       case 3: // 打开后门
@@ -356,6 +369,9 @@ class Fm1 {
           // this.clipActionArr.backDoor.clampWhenFinished = true;
           this.clipActionArr.backDoor.play();
           this.fmClock.start();
+
+          if (this.backDamperOpenMesh) this.backDamperOpenMesh.visible = true;
+          if (this.backDamperClosedMesh) this.backDamperClosedMesh.visible = false;
         };
         break;
       case 4: // 关闭后门
@@ -367,6 +383,9 @@ class Fm1 {
           // this.clipActionArr.backDoor.clampWhenFinished = true;
           this.clipActionArr.backDoor.play();
           this.fmClock.start();
+
+          if (this.backDamperOpenMesh) this.backDamperOpenMesh.visible = false;
+          if (this.backDamperClosedMesh) this.backDamperClosedMesh.visible = true;
         };
         break;
       // case 5: // 打开前后门
@@ -425,7 +444,7 @@ class Fm1 {
     // }, 1000);
   }
 
-  async initCamera(dom1, dom2) {
+  async initCamera(dom1?, dom2?) {
     const videoPlayer1 = dom1;
     const videoPlayer2 = dom2;
     this.player1 = dom1;
@@ -442,7 +461,7 @@ class Fm1 {
           y: 40,
         },
       ];
-      const canvas = await getTextCanvas(560, 346, textArr, '');
+      const canvas = await getTextCanvas(320, 180, '', 'noSinge.png');
 
       let textMaterial: THREE.MeshBasicMaterial | null = null;
       if (canvas) {
@@ -462,58 +481,66 @@ class Fm1 {
         textMap.dispose();
       }
     }
-    if (!videoPlayer1) {
-      const videoPlayer = this.group.getObjectByName('player1');
-      if (videoPlayer) {
-        this.model.clearMesh(videoPlayer);
-        this.group.remove(videoPlayer);
-      }
+    const player1 = this.group.getObjectByName('player1');
+    if (player1) {
+      this.model.clearMesh(player1);
+      this.group.remove(player1);
+    }
+    const noPlayer1 = this.group.getObjectByName('noPlayer1');
+    if (noPlayer1) {
+      this.model.clearMesh(noPlayer1);
+      this.group.remove(noPlayer1);
+    }
+    if (!videoPlayer1 && videoPlayer1 === null) {
       if (monitorPlane && !this.group.getObjectByName('noPlayer1')) {
         const planeMesh = monitorPlane.clone();
         planeMesh.name = 'noPlayer1';
-        planeMesh.scale.set(0.011, 0.008, 0.011);
-        planeMesh.position.set(-4.23, -0.28, -0.39);
+        planeMesh.scale.set(0.0085, 0.0056, 0.012);
+        planeMesh.position.set(-4.23, 0.02, -0.39);
         this.group?.add(planeMesh.clone());
       }
-    } else {
-      const noPlayer1 = this.group.getObjectByName('noPlayer1');
-      if (noPlayer1) {
-        this.model.clearMesh(noPlayer1);
-        this.group.remove(noPlayer1);
-      }
-      const mesh = renderVideo(this.group, videoPlayer1, 'player1');
-      if (mesh) {
-        mesh?.scale.set(-0.028, 0.0285, 1);
-        mesh?.position.set(-4.262, 0.02, -0.4);
-        mesh.rotation.y = -Math.PI;
-        this.group.add(mesh);
+    } else if (videoPlayer1) {
+      try {
+        const mesh = renderVideo(this.group, videoPlayer1, 'player1');
+        if (mesh) {
+          mesh?.scale.set(-0.028, 0.0285, 1);
+          mesh?.position.set(-4.262, 0.02, -0.4);
+          mesh.rotation.y = -Math.PI;
+          this.group.add(mesh);
+        }
+      } catch (error) {
+        console.log('视频信号异常');
       }
     }
-    if (!videoPlayer2) {
-      const videoPlayer = this.group.getObjectByName('player2');
-      if (videoPlayer) {
-        this.model.clearMesh(videoPlayer);
-        this.group.remove(videoPlayer);
-      }
+    const player2 = this.group.getObjectByName('player2');
+    if (player2) {
+      this.model.clearMesh(player2);
+      this.group.remove(player2);
+    }
+    const noPlayer2 = this.group.getObjectByName('noPlayer2');
+    if (noPlayer2) {
+      this.model.clearMesh(noPlayer2);
+      this.group.remove(noPlayer2);
+    }
+    if (!videoPlayer2 && videoPlayer2 === null) {
       if (monitorPlane && !this.group.getObjectByName('noPlayer2')) {
         const planeMesh = monitorPlane.clone();
         planeMesh.name = 'noPlayer2';
-        planeMesh.scale.set(0.012, 0.009, 0.012);
-        planeMesh.position.set(4.33, -0.33, -0.39);
+        planeMesh.scale.set(0.0085, 0.0056, 0.012);
+        planeMesh.position.set(4.29, 0.02, -0.41);
         this.group?.add(planeMesh.clone());
       }
-    } else {
-      const noPlayer2 = this.group.getObjectByName('noPlayer2');
-      if (noPlayer2) {
-        this.model.clearMesh(noPlayer2);
-        this.group.remove(noPlayer2);
-      }
-      const mesh = renderVideo(this.group, videoPlayer2, 'player2');
-      if (mesh) {
-        mesh?.scale.set(-0.028, 0.0285, 1);
-        mesh?.position.set(4.298, 0.02, -0.4);
-        mesh.rotation.y = -Math.PI;
-        this.group.add(mesh);
+    } else if (videoPlayer2) {
+      try {
+        const mesh = renderVideo(this.group, videoPlayer2, 'player2');
+        if (mesh) {
+          mesh?.scale.set(-0.028, 0.0285, 1);
+          mesh?.position.set(4.298, 0.02, -0.4);
+          mesh.rotation.y = -Math.PI;
+          this.group.add(mesh);
+        }
+      } catch (error) {
+        console.log('视频信号异常');
       }
     }
   }
@@ -530,7 +557,17 @@ class Fm1 {
         this.addLight();
         // this.deviceDetailCard();
         this.model.animate();
-        if (this.model.camera && this.model.camera.layers.mask == -1) this.model.camera.layers.toggle(1);
+
+        this.backDamperOpenMesh = this.group.getObjectByName('Dampler_open_1');
+        if (this.backDamperOpenMesh) this.backDamperOpenMesh.visible = false;
+        this.backDamperClosedMesh = this.group.getObjectByName('Damper_Closed_1');
+        if (this.backDamperClosedMesh) this.backDamperClosedMesh.visible = true;
+
+        this.frontDamperOpenMesh = this.group.getObjectByName('Damper_Open_2');
+        if (this.frontDamperOpenMesh) this.frontDamperOpenMesh.visible = false;
+        this.frontDamperClosedMesh = this.group.getObjectByName('Damper_Closed_2');
+        if (this.frontDamperClosedMesh) this.frontDamperClosedMesh.visible = true;
+
         resolve(this.model);
       });
     });

+ 20 - 60
src/views/vent/monitorManager/gateMonitor/index.vue

@@ -21,25 +21,12 @@
   <div class="scene-box">
     <div class="top-box">
       <div class="top-center row">
-        <!-- <div class="button-box" :class="{ 'button-disable': backDoorIsOpen }" @click="playAnimation(1)">打开前门</div>
-        <div class="button-box" :class="{ 'button-disable': backDoorIsOpen }" @click="playAnimation(2)">关闭前门</div>
-        <div class="button-box" :class="{ 'button-disable': frontDoorIsOpen }" @click="playAnimation(3)">打开后门</div>
-        <div class="button-box" :class="{ 'button-disable': frontDoorIsOpen }" @click="playAnimation(4)">关闭后门</div>
-        <div class="button-box" :class="{ 'button-disable': frontDoorIsOpen || backDoorIsOpen }" @click="playAnimation(5)">打开前后门</div> -->
-        <!-- <div
-            class="button-box"
-            :class="{ 'button-disable': (frontDoorIsOpen && !backDoorIsOpen) || (backDoorIsOpen && !frontDoorIsOpen) }"
-            @click="playAnimation(6)"
-            >关闭前后门</div> -->
-
         <div class="button-box" @click="playAnimation(1)">打开前门</div>
         <div class="button-box" @click="playAnimation(2)">关闭前门</div>
         <div class="button-box" @click="playAnimation(3)">打开后门</div>
         <div class="button-box" @click="playAnimation(4)">关闭后门</div>
         <div class="button-box" @click="playAnimation(5)">打开前后门</div>
-
         <div class="button-box" @click="playAnimation(6)">关闭前后门</div>
-        <!-- <div class="button-box" @click="enterMY">漫游</div> -->
       </div>
       <div class="top-right row">
         <div class="control-type row">
@@ -49,13 +36,13 @@
             <a-radio :value="`1`">远程</a-radio>
           </a-radio-group>
         </div>
-        <div class="run-type row">
+        <!-- <div class="run-type row">
           <div class="control-title">运行状态:</div>
           <a-radio-group v-model:value="selectData.runRoRecondition">
             <a-radio :value="`0`">检修</a-radio>
             <a-radio :value="`1`">运行</a-radio>
           </a-radio-group>
-        </div>
+        </div> -->
       </div>
     </div>
     <div class="title-text">
@@ -141,40 +128,13 @@
       </dv-border-box8>
     </div>
   </div>
-  <div ref="playerRef" style="z-index: -1; position: absolute; top: 50px; right: 10px; width: 300px; height: 280px; margin: auto">
-    <!-- <div id="fmPlayer1">
-      <video controls></video>
-    </div>
-    <div id="fmPlayer2">
-      <video controls muted autoplay></video>
-    </div> -->
-    <!-- <template v-if="flvURL1.startsWith('rtsp://')">
-      <video id="fmPlayer1" muted autoplay width="400" height="400" style="border: 1px solid #fff;"></video>
-    </template>
-    <template v-else>
-      <LivePlayer v-if="flvURL1" id="fmPlayer1" ref="player1" :videoUrl="flvURL1" muted live loading controls />
-    </template>
-    <template v-if="flvURL2.startsWith('rtsp://')">
-      <video id="fmPlayer2" muted autoplay width="400" height="400" style="border: 1px solid #fff;"></video>
-    </template>
-    <template v-else>
-      <LivePlayer v-if="flvURL2" id="fmPlayer2" ref="player2" :videoUrl="flvURL2" muted live loading controls style="margin-top: 10px" />
-    </template> -->
+  <div ref="playerRef" style="z-index: 999; position: absolute; top: 100px; right: 15px; width: 300px; height: 280px; margin: auto">
   </div>
-  <!-- <a-modal v-model:visible="modalIsShow" :title="modalTitle" @ok="handleOk">
-    <div class="modal-container">
-      <div class="vent-flex-row">
-        <ExclamationCircleFilled style="color: #ffb700; font-size: 30px" />
-        <div class="warning-text">您是否要进行{{ modalTitle }}操作?</div>
-      </div>
-    </div>
-  </a-modal> -->
   <HandleModal :modal-is-show="modalIsShow" :modal-title="modalTitle" :modal-type="modalType" @handle-ok="handleOK"
     @handle-cancel="handleCancel" />
 </template>
 
 <script setup lang="ts">
-import LivePlayer from '@liveqing/liveplayer-v3';
 import { onBeforeUnmount, onUnmounted, onMounted, ref, reactive, nextTick, h, render } from 'vue';
 import DeviceEcharts from '../comment/DeviceEcharts.vue';
 import MonitorTable from '../comment/MonitorTable.vue';
@@ -251,9 +211,6 @@ const initData = {
 // 监测数据
 const selectData = reactive(lodash.cloneDeep(initData));
 
-const flvURL1 = ref('')
-const flvURL2 = ref('')
-
 // 获取设备基本信息列表
 function getDeviceBaseList() {
   getTableList({ pageSize: 1000 }).then((res) => {
@@ -296,27 +253,27 @@ async function getMonitor(flag?) {
 async function getCamera() {
   const res = await cameraList({ deviceid: selectData['deviceID'] })
   const cameras: [] = res.records || []
-  let playerDom1, playerDom2, cameraAddrs:string[] = [], cameraNames:string[] = [];
-
+  let cameraAddrs:any[] = [], cameraNames:string[] = [];
   if (cameras.length > 0){
     cameras.forEach(item => {
       if (item['devicekind'] == 'toRtsp' || item['devicekind'] == 'toHLS') {
         cameraNames.push(item['name'])
       } else {
-        cameraAddrs.push(item['addr'])
+        cameraAddrs.push({name: item['name'], addr: item['addr'] })
       }
     })
   }
-  
   if (cameraNames.length > 0) {
     // 请求接口从装备院拿数据
     const addrs: string[] = await cameraAddrList({ cameraNameList: cameraNames })
-    cameraAddrs.push(...addrs)
+    for(let i=0; i < addrs.length; i++){
+      cameraAddrs.push({name: '摄像头'+i, addr: addrs[i]})
+    }
   }
-
   const obj = await deviceCameraInit(cameraAddrs, playerRef.value, webRtcServer)
-  webRtcServer = obj.webRtcServer
+  webRtcServer = obj.webRtcServerList
   const playerDoms = obj.playerDoms
+  // 注意前后门适应需要对应 //[0] 后门 [1]前门
   await initCameraCanvas(...playerDoms)
 }
 
@@ -411,10 +368,10 @@ function playAnimation(handlerState) {
 
 
 function handleOK(passWord, handlerState) {
-  if (passWord !== '123456') {
-    message.warning('密码不正确,请重新输入');
-    return;
-  }
+  // if (passWord !== '123456') {
+  //   message.warning('密码不正确,请重新输入');
+  //   return;
+  // }
 
   if ((isFrontOpenRunning || isFrontCloseRunning) && (handlerState == 2 || handlerState == 1 || handlerState == 5 || handlerState == 6)) {
     return
@@ -429,6 +386,7 @@ function handleOK(passWord, handlerState) {
     devicetype: selectData.deviceType,
     paramcode: '',
     value: null,
+    password: passWord,
     masterComputer: selectData.masterComputer,
   };
   let handler = () => { };
@@ -597,7 +555,7 @@ function monitorAnimation(selectData) {
     }
   }
 
-  console.log('frontGateOpen:', selectData.frontGateOpen, '  frontGateClose:', selectData.frontGateClose, ' rearGateOpen:', selectData.rearGateOpen, '  rearGateClose:', selectData.rearGateClose, '  frontGateOpenCtrl:', selectData.frontGateOpenCtrl, '  rearGateOpenCtrl:', selectData.rearGateOpenCtrl)
+  // console.log('frontGateOpen:', selectData.frontGateOpen, '  frontGateClose:', selectData.frontGateClose, ' rearGateOpen:', selectData.rearGateOpen, '  rearGateClose:', selectData.rearGateClose, '  frontGateOpenCtrl:', selectData.frontGateOpenCtrl, '  rearGateOpenCtrl:', selectData.rearGateOpenCtrl)
 
 }
 
@@ -637,12 +595,12 @@ onUnmounted(() => {
     clearTimeout(timer);
     timer = undefined;
   }
+  destroy()
   if(webRtcServer.length > 0){
     webRtcServer.forEach(item => {
       item.disconnect()
     })
   }
-  destroy()
 });
 </script>
 
@@ -674,4 +632,6 @@ onUnmounted(() => {
 ::-webkit-scrollbar-thumb {
   -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
   background: #4288A444;
-}</style>
+}
+
+</style>

+ 6 - 5
src/views/vent/monitorManager/groutMonitor/components/groutHome.vue

@@ -27,7 +27,7 @@
         </ventBox1>
       </div>
       <div class="item-box vent-margin-t-10">
-        <LivePlayer id="fm-player1" style="height: 220px;" ref="player1" :videoUrl="flvURL1()" muted live loading controls />
+        <!-- <LivePlayer id="fm-player1" style="height: 220px;" ref="player1" :videoUrl="flvURL1()" muted live loading controls /> -->
       </div>
     </div>
     <div class="lr right-box">
@@ -76,8 +76,7 @@
               <a-button type="primary"  @click="openModal('WarningParameterModal')">报警设置</a-button>
             </div>
           </template>
-        </ventBox1>
-        
+        </ventBox1>    
       </div>
       <div class="control-container item-box echarts-box">
         <ventBox1>
@@ -121,13 +120,11 @@
 import { onBeforeMount, ref, onMounted, onUnmounted, shallowRef, defineProps, ComponentOptions, reactive } from 'vue';
 import { mountedThree, destroy, setModelType } from '../grout.threejs';
 import { ScrollBoard as DvScrollBoard } from '@kjgl77/datav-vue3';
-import { SvgIcon } from '/@/components/Icon';
 import ventBox1 from '/@/components/vent/ventBox1.vue';
 import RunParameterModal from './runParameter.modal.vue'
 import WarningParameterModal from './warningParameter.modal.vue'
 import { warningConfig, zhujiangOption, yaliOption } from '../grout.data'
 import { list } from '../grout.api';
-import LivePlayer from '@liveqing/liveplayer-v3';
 import BarAndLineCustom from '/@/components/chart/BarAndLineCustom.vue';
 
 
@@ -135,6 +132,10 @@ const props = defineProps({
   deviceId: {
     type: String,
     require: true
+  },
+  deviceType: {
+    type: String,
+    require: true
   }
 })
 const left: string = "0px";

+ 0 - 1
src/views/vent/monitorManager/groutMonitor/grout.api.ts

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

+ 73 - 9
src/views/vent/monitorManager/groutMonitor/index.vue

@@ -17,9 +17,9 @@
     </div> -->
   </div>
   <div class="scene-box">
-    <customHeader >智能注浆系统</customHeader>
+    <customHeader :fieldNames="{ label: 'strinstallpos', value: 'deviceID', options: 'children' }" :options = 'options' @change="getSelectRow" :optionValue="optionValue">智能注浆系统</customHeader>
     <div class="center-container">
-      <groutHome v-if="activeKey == 'monitor'" :deviceId = 'optionValue' />
+      <groutHome v-if="activeKey == 'monitor'" :deviceId = 'optionValue' :device-type="currentDeviceType" />
       <div v-else class="history-group">
         <div class="history-container">
           <groutHistory v-if="activeKey == 'monitor_history'" ref="historyTable" class="vent-margin-t-20"/>
@@ -35,29 +35,36 @@
 
 <script setup lang="ts">
 import customHeader from '/@/views/vent/comment/components/customHeader.vue';
-import { onBeforeMount, ref, onMounted, onUnmounted, reactive, toRaw } from 'vue';
+import { ref, onMounted, onUnmounted, reactive, nextTick, toRaw } from 'vue';
 import { list } from './grout.api';
 import BottomMenu from '/@/views/vent/comment/components/bottomMenu.vue';
 import groutHome from './components/groutHome.vue';
 import groutHistory from './components/groutHistory.vue';
 import groutHandleHistoryVue from './components/groutHandleHistory.vue';
 import groutAlarmHistory from './components/groutAlarmHistory.vue';
+import { useRouter } from 'vue-router';
 
 type DeviceType = { deviceType: string, deviceName: string, datalist: any[] };
 const activeKey = ref('monitor');
 const loading = ref(false);
+const { currentRoute } = useRouter();
 
-const monitorTable = ref()
 const historyTable = ref()
 const alarmHistoryTable = ref()
 const handlerHistoryTable = ref()
 
 const options = ref()
-// 默认初始是第一行
+const optionValue = ref('')
+const currentDeviceType = ref('')
+
 const selectRowIndex = ref(0);
 const dataSource = ref([])
 
-const optionValue = ref('')
+const deviceList = ref<DeviceType[]>([])
+const deviceActive = ref('')
+const deviceType = ref('')
+
+
 
 // 监测数据
 const selectData = reactive({});
@@ -66,13 +73,70 @@ function changeActive(activeValue) {
   activeKey.value = activeValue
 }
 
-onBeforeMount(() => {
+function deviceChange(index) {
+  deviceActive.value = deviceType.value = deviceList.value[index].deviceType
+}
 
-});
+// 查询关联设备列表
+async function getDeviceList() {
+  const res = await list({ devicetype: 'sys', systemID: optionValue.value });
+  const result = res.msgTxt;
+  const deviceArr = <DeviceType[]>[]
+  result.forEach(item => {
+    const data = item['datalist'].filter((data: any) => {
+      const readData = data.readData;
+      return Object.assign(data, readData);
+    })
+    if (item.type != 'sys') {
+      deviceArr.unshift({ deviceType: item.type, deviceName: item['typeName'] ? item['typeName'] : item['datalist'][0]['typeName'], datalist: data })
+    }
+  })
+  deviceList.value = deviceArr
+  deviceActive.value = deviceArr[0].deviceType
+  deviceChange(0)
+};
+
+async function getSysDataSource() {
+  const res = await list({ devicetype: 'pulping', pagetype: 'normal' });
+  dataSource.value = res.msgTxt[0].datalist || [];
+  dataSource.value.forEach((data: any) => {
+    const readData = data.readData;
+    data = Object.assign(data, readData);
+  });
+
+  if (!options.value) {
+    // 初始时选择第一条数据
+    options.value = dataSource.value
+    if (!optionValue.value) {
+      optionValue.value = dataSource.value[0]['deviceID']
+      Object.assign(selectData, dataSource.value[0])
+    } else {
+      const currentData = dataSource.value.find(item => item['deviceID'] === optionValue.value) || {}
+      Object.assign(selectData, currentData)
+    }
+  }
+  const data: any = toRaw(dataSource.value[selectRowIndex.value]); //maxarea
+  return data;
+};
+
+// 切换检测数据
+function getSelectRow(deviceID) {
+  const currentData = dataSource.value.find((item: any) => {
+    return item.deviceID == deviceID
+  })
+  if (currentData) {
+    optionValue.value = currentData['deviceID']
+    currentDeviceType.value = currentData['deviceType']
+    Object.assign(selectData, currentData)
+  }
+}
 
 onMounted(async() => {
-
+  if (currentRoute.value['query'] && currentRoute.value['query']['id']) optionValue.value = currentRoute.value['query']['id']
+  await getSysDataSource()
+  await getDeviceList()
 });
+
 onUnmounted(() => {
  
 });

+ 1 - 3
src/views/vent/monitorManager/mainFanMonitor/components/conditionAssistance.vue

@@ -1,5 +1,5 @@
 <template>
-  <BasicModal @register="register" title="风机运行工况辅助决策" :maskStyle="{backgroundColor: '#000000aa'}" width="1200px" v-bind="$attrs" @ok="onSubmit" @cancel="onSubmit" :destroyOnClose="true" :footer="null">
+  <BasicModal @register="register" title="风机运行工况辅助决策" :maskStyle="{backgroundColor: '#000000aa'}" width="1200px" v-bind="$attrs" @ok="onSubmit" @cancel="onSubmit" :canFullscreen="false" :destroyOnClose="true" :footer="null">
     <div class="modal-box">
       <div class="right-box">
         <!-- <div class="box-title">风机信息</div> -->
@@ -318,8 +318,6 @@
       let keyVal = ''
       // 遍历已知点数组,计算距离并更新最小距离和对应的点
       for (const [key, point] of points) {
-        debugger
-
         const distance = Math.sqrt((targetX - point.x) ** 2 + (targetY - point.y) ** 2);
         if (distance < minDistance) {
           minDistance = distance;

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

@@ -274,7 +274,7 @@
             <span class="data-title vent-margin-l-10"><span class="signal-round signal-round-blue vent-margin-r-8"></span>锁1开到位</span>
             <span class="data-title vent-margin-l-20"><span class="signal-round signal-round-blue vent-margin-r-8"></span>锁2开到位</span>
           </template>
-          <template v-else-if="selectData['Lock1Open'] == 0 && selectData['Lock1Close'] == 1 && selectData['Lock2Open'] == 0 && selectData['Lock2Close'] == 1">
+          <template v-else-if="selectData['Lock1Open'] == 0 && selectData['Lock1Close'] == 1 && selectData['Lock2Open'] == 0 && selectData['  '] == 1">
             <span class="data-title vent-margin-l-10"><span class="signal-round signal-round-gry vent-margin-r-8"></span>锁1关到位</span>
             <span class="data-title vent-margin-l-20"><span class="signal-round signal-round-gry vent-margin-r-8"></span>锁2关到位</span>
           </template>
@@ -500,6 +500,7 @@
           deviceid: selectData.deviceID,
           devicetype: selectData.deviceType,
           paramcode: paramcode,
+          password: passWord.value,
           testvalue: value,
         };
       }else{
@@ -507,6 +508,7 @@
           deviceid: selectData.deviceID,
           devicetype: selectData.deviceType,
           paramcode: paramcode,
+          password: passWord.value,
           value: value,
         };
       }
@@ -582,10 +584,10 @@
   };
   
   const handleOk = (flag?) => {
-    if (passWord.value !== '123456') {
-      createMessage.warning('密码不正确,请重新输入');
-      return;
-    }
+    // if (passWord.value !== '123456') {
+    //   createMessage.warning('密码不正确,请重新输入');
+    //   return;
+    // }
     if (modalType.value == 'startSmoke') {
       if ((selectData['Fan1StartStatus'] == 1 && selectData['Fan2StartStatus'] == 0)) {
         start('CtrlFan2Start').then(() => {

+ 51 - 50
src/views/vent/monitorManager/windowMonitor/dandaoFc.threejs.ts

@@ -16,9 +16,8 @@ class singleWindow {
   player1;
   player2;
   playerStartClickTime1 = new Date().getTime();
-  constructor(model, playerVal1) {
+  constructor(model) {
     this.model = model;
-    this.player1 = playerVal1;
     this.group.name = 'ddFc';
   }
   // // 重置摄像头
@@ -166,7 +165,7 @@ class singleWindow {
   initAnimation() {
     const meshArr01: THREE.Object3D[] = [];
     this.group?.children.forEach((obj) => {
-      if (obj.type === 'Mesh' && obj.name && obj.name.startsWith('shanye')) {
+      if (obj.type === 'Mesh' && obj.name && obj.name.startsWith('FCshanye')) {
         obj.rotateOnAxis(new THREE.Vector3(0, 1, 0), 0);
         meshArr01.push(obj);
       }
@@ -246,58 +245,60 @@ class singleWindow {
     }
   }
 
+  async initCamera(dom1?) {
+    const videoPlayer1 = dom1;
+    let monitorPlane: THREE.Mesh | null = null;
+    const canvas = await getTextCanvas(320, 180, '', 'noSinge.png');
+    const textMap = new THREE.CanvasTexture(canvas); // 关键一步
+    const textMaterial = new THREE.MeshBasicMaterial({
+      map: textMap, // 设置纹理贴图
+      transparent: true,
+      side: THREE.DoubleSide, // 这里是双面渲染的意思
+    });
+    textMaterial.blending = THREE.CustomBlending;
+    monitorPlane = this.group?.getObjectByName('noPlayer');
+    if (monitorPlane) {
+      monitorPlane.material = textMaterial;
+    } else {
+      const planeGeometry = new THREE.PlaneGeometry(100, 100); // 平面3维几何体PlaneGeometry
+      monitorPlane = new THREE.Mesh(planeGeometry, textMaterial);
+      textMaterial.dispose();
+      planeGeometry.dispose();
+    }
+    const videoPlayer = this.group.getObjectByName('player1');
+    if (videoPlayer) {
+      this.model.clearMesh(videoPlayer);
+      this.group.remove(videoPlayer);
+    }
+    const noPlayer1 = this.group.getObjectByName('noPlayer1');
+    if (noPlayer1) {
+      this.model.clearMesh(noPlayer1);
+      this.group.remove(noPlayer1);
+    }
+    if (!videoPlayer1 && videoPlayer1 === null) {
+      monitorPlane.name = 'noPlayer1';
+      monitorPlane.scale.set(0.015, 0.007, 0.011);
+      monitorPlane.position.set(4.04, 0.02, -0.46);
+      this.group?.add(monitorPlane);
+    } else if (videoPlayer1) {
+      const mesh = renderVideo(this.group, videoPlayer1, 'player1');
+      if (mesh) {
+        mesh?.scale.set(-0.038, 0.029, 1);
+        mesh?.position.set(-4.302, 0.15, -0.23);
+        mesh.rotation.y = -Math.PI;
+        this.group.add(mesh);
+      }
+    }
+  }
+
   mountedThree() {
     return new Promise((resolve) => {
-      this.model.setGLTFModel(['ddFc']).then((gltf) => {
-        this.group = gltf[0];
+      this.model.setGLTFModel(['ddFc', 'wall'], this.group).then(() => {
+        // this.group = gltf[0];
 
         this.setModalPosition();
         this.initAnimation();
-
-        setTimeout(async () => {
-          const videoPlayer1 = document.getElementById('fc-player1')?.getElementsByClassName('vjs-tech')[0];
-          if (videoPlayer1) {
-            const mesh = renderVideo(this.group, videoPlayer1, 'player1');
-            mesh?.scale.set(0.0382, 0.028, 0.022);
-            mesh?.position.set(-2.008, 0.148, -0.22);
-            this.group?.add(mesh);
-          } else {
-            const textArr = [
-              {
-                text: `无信号输入`,
-                font: 'normal 40px Arial',
-                color: '#009900',
-                strokeStyle: '#002200',
-                x: 170,
-                y: 40,
-              },
-            ];
-            getTextCanvas(560, 346, textArr, '').then((canvas: HTMLCanvasElement) => {
-              const textMap = new THREE.CanvasTexture(canvas); // 关键一步
-              const textMaterial = new THREE.MeshBasicMaterial({
-                map: textMap, // 设置纹理贴图
-                transparent: true,
-                side: THREE.DoubleSide, // 这里是双面渲染的意思
-              });
-              textMaterial.blending = THREE.CustomBlending;
-              const monitorPlane = this.group?.getObjectByName('noPlayer');
-              if (monitorPlane) {
-                monitorPlane.material = textMaterial;
-              } else {
-                const planeGeometry = new THREE.PlaneGeometry(100, 100); // 平面3维几何体PlaneGeometry
-                const planeMesh = new THREE.Mesh(planeGeometry, textMaterial);
-                planeMesh.name = 'noPlayer';
-                planeMesh.scale.set(0.011, 0.008, 0.011);
-                planeMesh.position.set(-1.99, -0.18, -0.23);
-                this.group?.add(planeMesh.clone());
-                textMaterial.dispose();
-                planeGeometry.dispose();
-              }
-              textMap.dispose()
-            });
-          }
-          resolve(null);
-        }, 0);
+        resolve(null);
       });
     });
   }

+ 46 - 44
src/views/vent/monitorManager/windowMonitor/index.vue

@@ -114,10 +114,7 @@
       </dv-border-box8>
     </div>
   </div>
-  <div style="z-index: -1; position: absolute; top: 50px; right: 10px; width: 300px; height: 280px; margin: auto" class="palyer1">
-    <LivePlayer id="fc-player1" ref="player1" :videoUrl="flvURL1()" muted live loading controls />
-    <LivePlayer id="fc-player2" ref="player2" :videoUrl="flvURL1()" muted live loading controls style="margin-top: 10px" />
-  </div>
+  <div ref="playerRef" style="z-index: 999; position: absolute; top: 100px; right: 10px; width: 300px; height: 280px; margin: auto"></div>
   <HandleModal :modal-is-show="modalIsShow" :modal-title="modalTitle" :modal-type="modalType" @handle-ok="handleOK" @handle-cancel="handleCancel" />
 </template>
 
@@ -130,25 +127,23 @@
   import AlarmHistoryTable from '../comment/AlarmHistoryTable.vue';
   import HandlerHistoryTable from '../comment/HandlerHistoryTable.vue';
   import HandleModal from './modal.vue';
-  import { mountedThree, destroy, addMonitorText, play, setModelType } from './window.threejs';
-  import { list, getTableList } from './window.api';
+  import { mountedThree, destroy, addMonitorText, play, setModelType, initCameraCanvas } from './window.threejs';
+  import { list, getTableList, cameraList, cameraAddrList } from './window.api';
   import { list as baseList } from '../../deviceManager/windWindowTabel/ventanalyWindow.api';
   import { chartsColumns } from './window.data';
   import { deviceControlApi } from '/@/api/vent/index';
   import lodash from 'lodash';
-  import LivePlayer from '@liveqing/liveplayer-v3';
   import { setDivHeight } from '/@/utils/event';
   import { BorderBox8 as DvBorderBox8 } from '@kjgl77/datav-vue3';
   import { useRouter } from 'vue-router';
+  import { deviceCameraInit } from '/@/utils/ventutil.ts'
 
   const { currentRoute } = useRouter();
 
   const MonitorDataTable = ref()
 
-  const player1 = ref(null);
-  const player2 = ref(null);
-
-
+  const playerRef = ref();
+  let webRtcServer: any[] = []
   const scroll = reactive({
     y: 240
   })
@@ -173,21 +168,6 @@
   const selectRowIndex = ref(-1);
   const dataSource = ref([]);
 
-  // webSocket 请求
-  // const dataSource = computed(() => {
-  //   const data = [...getRecordList()] || [];
-  //   Object.assign(selectData, toRaw(data[selectRowIndex.value]));
-  //   addMonitorText(selectData);
-  //   return data;
-  // });
-
-  const flvURL1 = () => {
-    // return `https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv`;
-    return 'http://localhost:3100/black'
-  };
-  const flvURL2 = () => {
-    return `https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv`;
-  };
   // 设备数据
   const controlType = ref(1);
 
@@ -265,8 +245,35 @@
     });
   };
 
+  async function getCamera() {
+    const res = await cameraList({ deviceid: selectData['deviceID'] })
+    const cameras: [] = res.records || []
+    let cameraAddrs: any[] = [], cameraNames: string[] = [];
+    if (cameras.length > 0) {
+      cameras.forEach(item => {
+        if (item['devicekind'] == 'toRtsp' || item['devicekind'] == 'toHLS') {
+          cameraNames.push(item['name'])
+        } else {
+          cameraAddrs.push({ name: item['name'], addr: item['addr'] })
+        }
+      })
+    }
+    if (cameraNames.length > 0) {
+      // 请求接口从装备院拿数据
+      const addrs: string[] = await cameraAddrList({ cameraNameList: cameraNames })
+      for (let i = 0; i < addrs.length; i++) {
+        cameraAddrs.push({ name: '摄像头' + i, addr: addrs[i] })
+      }
+    }
+    const obj = await deviceCameraInit(cameraAddrs, playerRef.value, webRtcServer)
+    webRtcServer = obj.webRtcServerList
+    const playerDoms = obj.playerDoms
+    // 注意前后门适应需要对应 //[0] 后门 [1]前门
+    await initCameraCanvas(...playerDoms)
+  }
+
   // 切换检测数据
-  const getSelectRow = (selectRow, index) => {
+  const getSelectRow = async (selectRow, index) => {
     if (!selectRow) return;
     selectRowIndex.value = index;
     loading.value = true;
@@ -279,6 +286,7 @@
       playAnimation(selectRow, baseData.maxarea, true);
       loading.value = false;
     });
+    await getCamera()
   };
 
   // 判断前后窗的面积是否发生改变,如果改变则开启动画
@@ -322,14 +330,15 @@
 
   const handleOK = (passWord, handlerState, windowAngleNum) => {
     windowAngle.value = windowAngleNum;
-    if (passWord !== '123456') {
-      message.warning('密码不正确,请重新输入');
-      return;
-    }
+    // if (passWord !== '123456') {
+    //   message.warning('密码不正确,请重新输入');
+    //   return;
+    // }
     const data = {
       deviceid: selectData.deviceID,
       devicetype: selectData.deviceType,
       paramcode: handlerState == 1 ? 'frontSetValue' : 'rearSetValue',
+      password: passWord,
       value: windowAngle.value,
     };
     deviceControlApi(data)
@@ -347,17 +356,6 @@
     modalType.value = '';
   };
 
-  const addPlayVideo = () => {
-    try {
-      if (player1.value && player2.value && player1.value.play && player2.value.play) {
-        if (!player1.value.paused()) player1.value.play();
-        if (!player2.value.paused()) player2.value.play();
-        document.body.removeEventListener('mousedown', addPlayVideo);
-      }
-    } catch (error) {
-      console.error('摄像头报错。。。。。')
-    }
-  };
 
   onBeforeMount(() => {
     // const sendVal = JSON.stringify({ pagetype: 'normal', devicetype: 'window', orgcode: '', ids: '', systemID: '' });
@@ -368,14 +366,13 @@
   onMounted(() => {
     loading.value = true;
     
-    mountedThree(player1.value, player2.value).then(async () => {
+    mountedThree().then(async () => {
       // await setModelType('singleWindow');
       getMonitor(true);
       loading.value = false;
       addMonitorText(selectData);
       
     });
-    document.body.addEventListener('mousedown', addPlayVideo, false);
   });
   onUnmounted(() => {
     destroy();
@@ -383,6 +380,11 @@
       clearTimeout(timer);
       timer = undefined;
     }
+    if (webRtcServer && webRtcServer.length > 0) {
+      webRtcServer.forEach(item => {
+        item.disconnect()
+      })
+    }
   });
 </script>
 <style lang="less" scoped>

+ 103 - 72
src/views/vent/monitorManager/windowMonitor/shuangdaoFc.threejs.ts

@@ -14,16 +14,11 @@ class doubleWindow {
     frontWindow: <THREE.Mesh[]>[],
     backWindow: <THREE.Mesh[]>[],
   };
-  player1;
-  player2;
   playerStartClickTime1 = new Date().getTime();
   playerStartClickTime2 = new Date().getTime();
 
-  constructor(model, playerVal1, playerVal2) {
+  constructor(model) {
     this.model = model;
-    this.player1 = playerVal1;
-    this.player2 = playerVal2;
-
     this.group.name = this.modelName;
   }
 
@@ -87,7 +82,7 @@ class doubleWindow {
         y: 256,
       },
       {
-        text: `${selectData.frontRearDifference}`,
+        text: `${selectData.frontRearDP}`,
         font: 'normal 28px Arial',
         color: '#009900',
         strokeStyle: '#002200',
@@ -156,7 +151,7 @@ class doubleWindow {
         planeMesh.position.set(2.65, 0.158, -0.23);
         this.group?.add(planeMesh);
       }
-      textMap.dispose()
+      textMap.dispose();
     });
   }
 
@@ -208,25 +203,6 @@ class doubleWindow {
     // 判断是否点击到视频
     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;
-      } else if (mesh.name === 'player2') {
-        if (new Date().getTime() - this.playerStartClickTime2 < 400) {
-          // 双击,视频放大
-          if (this.player2) {
-            this.player2.requestFullscreen();
-          }
-        }
-        this.playerStartClickTime2 = new Date().getTime();
-        return true;
-      }
       return false;
     });
   }
@@ -272,57 +248,112 @@ class doubleWindow {
     }
   }
 
+  async initCamera(dom1?, dom2?) {
+    const videoPlayer1 = dom1;
+    const videoPlayer2 = dom2;
+    let monitorPlane: THREE.Mesh | null = null;
+    if (!videoPlayer1 || !videoPlayer2) {
+      const textArr = [
+        {
+          text: `无信号输入`,
+          font: 'normal 40px Arial',
+          color: '#009900',
+          strokeStyle: '#002200',
+          x: 170,
+          y: 40,
+        },
+      ];
+      const canvas = await getTextCanvas(320, 180, '', 'noSinge.png');
+
+      let textMaterial: THREE.MeshBasicMaterial | null = null;
+      if (canvas) {
+        const textMap = new THREE.CanvasTexture(canvas); // 关键一步
+        textMaterial = new THREE.MeshBasicMaterial({
+          map: textMap, // 设置纹理贴图
+          transparent: true,
+          side: THREE.DoubleSide, // 这里是双面渲染的意思
+        });
+        textMaterial.blending = THREE.CustomBlending;
+
+        const planeGeometry = new THREE.PlaneGeometry(100, 100); // 平面3维几何体PlaneGeometry
+        monitorPlane = new THREE.Mesh(planeGeometry, textMaterial);
+
+        textMaterial.dispose();
+        planeGeometry.dispose();
+        textMap.dispose();
+      }
+    }
+    const player1 = this.group.getObjectByName('player1');
+    if (player1) {
+      this.model.clearMesh(player1);
+      this.group.remove(player1);
+    }
+    const noPlayer1 = this.group.getObjectByName('noPlayer1');
+    if (noPlayer1) {
+      this.model.clearMesh(noPlayer1);
+      this.group.remove(noPlayer1);
+    }
+    if (!videoPlayer1 && videoPlayer1 === null) {
+      if (monitorPlane && !this.group.getObjectByName('noPlayer1')) {
+        const planeMesh = monitorPlane.clone();
+        planeMesh.name = 'noPlayer1';
+        planeMesh.scale.set(0.0085, 0.0056, 0.012);
+        planeMesh.position.set(-4.23, 0.02, -0.39);
+        this.group?.add(planeMesh.clone());
+      }
+    } else if (videoPlayer1) {
+      try {
+        const mesh = renderVideo(this.group, videoPlayer1, 'player1');
+        if (mesh) {
+          mesh?.scale.set(-0.038, 0.029, 1);
+          mesh?.position.set(-4.302, 0.15, -0.23);
+          mesh.rotation.y = -Math.PI;
+          this.group.add(mesh);
+        }
+      } catch (error) {
+        console.log('视频信号异常');
+      }
+    }
+    const player2 = this.group.getObjectByName('player2');
+    if (player2) {
+      this.model.clearMesh(player2);
+      this.group.remove(player2);
+    }
+    const noPlayer2 = this.group.getObjectByName('noPlayer2');
+    if (noPlayer2) {
+      this.model.clearMesh(noPlayer2);
+      this.group.remove(noPlayer2);
+    }
+    if (!videoPlayer2 && videoPlayer2 === null) {
+      if (monitorPlane && !this.group.getObjectByName('noPlayer2')) {
+        const planeMesh = monitorPlane.clone();
+        planeMesh.name = 'noPlayer2';
+        planeMesh.scale.set(0.0085, 0.0056, 0.012);
+        planeMesh.position.set(4.29, 0.02, -0.41);
+        this.group?.add(planeMesh.clone());
+      }
+    } else if (videoPlayer2) {
+      try {
+        const mesh = renderVideo(this.group, videoPlayer2, 'player2');
+        if (mesh) {
+          mesh?.scale.set(-0.028, 0.0285, 1);
+          mesh?.position.set(4.298, 0.02, -0.4);
+          mesh.rotation.y = -Math.PI;
+          this.group.add(mesh);
+        }
+      } catch (error) {
+        console.log('视频信号异常');
+      }
+    }
+  }
+
   mountedThree() {
     return new Promise((resolve) => {
       this.model.setGLTFModel([this.modelName]).then((gltf) => {
         this.group = gltf[0];
         this.setModalPosition();
         this.initAnimation();
-
-        setTimeout(async () => {
-          const videoPlayer2 = document.getElementById('fc-player2')?.getElementsByClassName('vjs-tech')[0];
-          if (videoPlayer2) {
-            const mesh = renderVideo(this.group, videoPlayer2, 'player2');
-            mesh?.scale.set(0.0385, 0.028, 0.022);
-            mesh?.position.set(-4.307, 0.145, -0.22);
-            this.group?.add(mesh as THREE.Mesh);
-          } else {
-            const textArr = [
-              {
-                text: `无信号输入`,
-                font: 'normal 40px Arial',
-                color: '#009900',
-                strokeStyle: '#002200',
-                x: 170,
-                y: 40,
-              },
-            ];
-            getTextCanvas(560, 346, textArr, '').then((canvas: HTMLCanvasElement) => {
-              const textMap = new THREE.CanvasTexture(canvas); // 关键一步
-              const textMaterial = new THREE.MeshBasicMaterial({
-                map: textMap, // 设置纹理贴图
-                transparent: true,
-                side: THREE.DoubleSide, // 这里是双面渲染的意思
-              });
-              textMaterial.blending = THREE.CustomBlending;
-              const monitorPlane = this.group?.getObjectByName('noPlayer');
-              if (monitorPlane) {
-                monitorPlane.material = textMaterial;
-              } else {
-                const planeGeometry = new THREE.PlaneGeometry(100, 100); // 平面3维几何体PlaneGeometry
-                const planeMesh = new THREE.Mesh(planeGeometry, textMaterial);
-                planeMesh.name = 'noPlayer';
-                planeMesh.scale.set(0.011, 0.008, 0.011);
-                planeMesh.position.set(-4.28, -0.18, -0.23);
-                this.group?.add(planeMesh.clone());
-                textMaterial.dispose();
-                planeGeometry.dispose();
-              }
-              textMap.dispose();
-            });
-          }
-          resolve(null);
-        }, 0);
+        resolve(null);
       });
     });
   }

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

@@ -3,6 +3,8 @@ import { defHttp } from '/@/utils/http/axios';
 enum Api {
   list = '/ventanaly-device/monitor/device',
   baseList = '/safety/ventanalyWindow/list',
+  cameraList = '/safety/ventanalyCamera/list',
+  cameraAddrList = '/ventanaly-device/camera/info',
 }
 /**
  * 列表接口
@@ -15,3 +17,6 @@ export const list = (params) => defHttp.post({ url: Api.list, params });
  * @param params
  */
 export const getTableList = (params) => defHttp.get({ url: Api.baseList, params });
+
+export const cameraList = (params) => defHttp.get({ url: Api.cameraList, params });
+export const cameraAddrList = (params) => defHttp.post({ url: Api.cameraAddrList, params });

+ 11 - 4
src/views/vent/monitorManager/windowMonitor/window.threejs.ts

@@ -62,7 +62,6 @@ const addLight = () => {
   // gui.add(directionalLight.position, 'x', -1000, 1000);
   // gui.add(directionalLight.position, 'y', -1000, 1000);
   // gui.add(directionalLight.position, 'z', -1000, 1000);
-
 };
 
 // // 重置摄像头
@@ -117,6 +116,14 @@ export const play = (rotationParam, flag) => {
   }
 };
 
+export const initCameraCanvas = async (playerVal1?, playerVal2?) => {
+  if (windowType === 'singleWindow' && singleWindowObj) {
+    return await singleWindowObj.initCamera.call(singleWindowObj, playerVal1);
+  } else if (windowType === 'doubleWindow' && doubleWindowObj) {
+    return doubleWindowObj.initCamera.call(doubleWindowObj, playerVal1);
+  }
+};
+
 // 切换风窗类型
 export const setModelType = (type) => {
   // if (!model || !model.scene) return;
@@ -153,15 +160,15 @@ export const setModelType = (type) => {
   });
 };
 
-export const mountedThree = (playerVal1, playerVal2) => {
+export const mountedThree = () => {
   return new Promise(async (resolve) => {
     model = new UseThree('#window3D');
     if (!model || !model.renderer || !model.camera) return;
     model.setEnvMap('test1');
     model.camera.position.set(100, 0, 1000);
     // 单道、 双道
-    doubleWindowObj = new doubleWindow(model, playerVal1, playerVal2);
-    singleWindowObj = new singleWindow(model, playerVal1);
+    doubleWindowObj = new doubleWindow(model);
+    singleWindowObj = new singleWindow(model);
     await doubleWindowObj.mountedThree();
     await singleWindowObj.mountedThree();
 

+ 66 - 0
src/views/vent/monitorManager/windrectMonitor/components/modal.vue

@@ -0,0 +1,66 @@
+<template>
+  <a-modal v-model:visible="visible" :title="title" @ok="handleOk" @cancel="handleCancel">
+    <div class="modal-container">
+      <div class="vent-flex-row">
+        <ExclamationCircleFilled style="color: #ffb700; font-size: 30px" />
+        <div class="warning-text">您是否要进行{{ title }}操作?</div>
+      </div>
+      <div class="vent-flex-row input-box">
+        <div class="label">操作密码:</div>
+        <a-input size="small" type="password" v-model:value="passWord" />
+      </div>
+    </div>
+  </a-modal>
+</template>
+<script setup lang="ts">
+  import { watch, ref } from 'vue';
+  import { ExclamationCircleFilled } from '@ant-design/icons-vue';
+
+  const props = defineProps({
+    modalIsShow: {
+      type: Boolean,
+      default: false,
+    },
+    modalTitle: {
+      type: String,
+      default: '',
+    },
+    modalType: {
+      type: String,
+      default: '',
+    },
+  });
+
+  const emit = defineEmits(['handleOk', 'handleCancel']);
+
+  const visible = ref<Boolean>(false);
+  const title = ref<String>('');
+  const type = ref<String>('');
+  const passWord = ref('');
+
+  watch([() => props.modalIsShow, () => props.modalTitle, () => props.modalType], ([newVal, newModalTitle, newModalType]) => {
+    visible.value = newVal;
+    if (newModalTitle) title.value = newModalTitle;
+    if (newModalType) type.value = newModalType;
+    passWord.value = '';
+  });
+
+  function handleOk() {
+    //
+    emit('handleOk', passWord.value, type.value);
+  }
+  function handleCancel() {
+    //
+    emit('handleCancel');
+  }
+</script>
+<style scoped lang="less">
+  @ventSpace: zxm;
+
+  .label {
+    width: 80px;
+  }
+  .@{ventSpace}-input {
+    width: 150px;
+  }
+</style>

+ 58 - 53
src/views/vent/monitorManager/windrectMonitor/duishe.threejs.ts

@@ -19,9 +19,8 @@ class dsWindRect {
   lineLight;
   isRun = false;
 
-  constructor(model, playerVal1) {
+  constructor(model) {
     this.model = model;
-    this.player1 = playerVal1;
     this.group.name = this.modelName;
   }
   setModelType(deviceType) {
@@ -238,16 +237,16 @@ class dsWindRect {
     // 判断是否点击到视频
     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;
-      }
+      // 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;
     });
   }
@@ -329,6 +328,52 @@ class dsWindRect {
     }
   }
 
+  async initCamera(dom1?) {
+    const videoPlayer1 = dom1;
+    let monitorPlane: THREE.Mesh | null = null;
+    const canvas = await getTextCanvas(320, 180, '', 'noSinge.png');
+    const textMap = new THREE.CanvasTexture(canvas); // 关键一步
+    const textMaterial = new THREE.MeshBasicMaterial({
+      map: textMap, // 设置纹理贴图
+      transparent: true,
+      side: THREE.DoubleSide, // 这里是双面渲染的意思
+    });
+    textMaterial.blending = THREE.CustomBlending;
+    monitorPlane = this.group?.getObjectByName('noPlayer');
+    if (monitorPlane) {
+      monitorPlane.material = textMaterial;
+    } else {
+      const planeGeometry = new THREE.PlaneGeometry(100, 100); // 平面3维几何体PlaneGeometry
+      monitorPlane = new THREE.Mesh(planeGeometry, textMaterial);
+      textMaterial.dispose();
+      planeGeometry.dispose();
+    }
+    const videoPlayer = this.group.getObjectByName('player1');
+    if (videoPlayer) {
+      this.model.clearMesh(videoPlayer);
+      this.group.remove(videoPlayer);
+    }
+    const noPlayer1 = this.group.getObjectByName('noPlayer1');
+    if (noPlayer1) {
+      this.model.clearMesh(noPlayer1);
+      this.group.remove(noPlayer1);
+    }
+    if (!videoPlayer1 && videoPlayer1 === null) {
+      monitorPlane.name = 'noPlayer1';
+      monitorPlane.scale.set(0.0125, 0.007, 0.012);
+      monitorPlane.position.set(2.69, 0.02, -0.39);
+      this.group?.add(monitorPlane);
+    } else if (videoPlayer1) {
+      const mesh = renderVideo(this.group, videoPlayer1, 'player1');
+      if (mesh) {
+        mesh?.scale.set(0.042, 0.036, 1);
+        mesh?.position.set(2.685, 0.016, -0.38);
+        mesh.rotation.y = -Math.PI;
+        this.group.add(mesh);
+      }
+    }
+  }
+
   mountedThree() {
     return new Promise((resolve) => {
       this.model.setGLTFModel([this.modelName, 'dsgd', 'dsmove'], this.group).then((gltf) => {
@@ -337,47 +382,7 @@ class dsWindRect {
         this.setModalPosition();
         this.initAnimation();
         this.addLight();
-        setTimeout(async () => {
-          const videoPlayer1 = document.getElementById('cf-player1')?.getElementsByClassName('vjs-tech')[0];
-          if (videoPlayer1) {
-            const mesh = renderVideo(this.group, videoPlayer1, 'player1');
-            mesh?.scale.set(0.042, 0.036, 1);
-            mesh?.position.set(2.215, 0.016, -0.38);
-            this.group?.add(mesh as THREE.Mesh);
-          } else {
-            const textArr = [
-              {
-                text: `无信号输入`,
-                font: 'normal 40px Arial',
-                color: '#009900',
-                strokeStyle: '#002200',
-                x: 370,
-                y: 40,
-              },
-            ];
-            getTextCanvas(580, 346, textArr, '').then((canvas: HTMLCanvasElement) => {
-              const textMap = new THREE.CanvasTexture(canvas); // 关键一步
-              const textMaterial = new THREE.MeshBasicMaterial({
-                map: textMap, // 设置纹理贴图
-                transparent: true,
-                side: THREE.DoubleSide, // 这里是双面渲染的意思
-              });
-              textMaterial.blending = THREE.CustomBlending;
-              const monitorPlane = this.group?.getObjectByName('noPlayer');
-              if (monitorPlane) {
-                monitorPlane.material = textMaterial;
-              } else {
-                const planeGeometry = new THREE.PlaneGeometry(100, 100); // 平面3维几何体PlaneGeometry
-                const planeMesh = new THREE.Mesh(planeGeometry, textMaterial);
-                planeMesh.name = 'noPlayer';
-                planeMesh.scale.set(0.014, 0.009, 0.012);
-                planeMesh.position.set(2.25, -0.34, -0.39);
-                this.group?.add(planeMesh);
-              }
-            });
-          }
-          resolve(null);
-        }, 0);
+        resolve(null);
       });
     });
   }

+ 89 - 55
src/views/vent/monitorManager/windrectMonitor/index.vue

@@ -120,10 +120,7 @@
       </dv-border-box8>
     </div>
   </div>
-  <div style="z-index: -1; position: absolute; top: 50px; right: 10px; width: 300px; height: 280px; margin: auto" class="palyer">
-    <LivePlayer id="cf-player1" ref="player1" :videoUrl="flvURL1()" alt="无信号" muted live loading controls />
-    <LivePlayer id="cf-player2" ref="player2" :videoUrl="flvURL1()" alt="无信号" muted live loading controls style="margin-top: 10px" />
-  </div>
+  <div ref="playerRef" style="z-index: 999; position: absolute; top: 100px; right: 10px; width: 300px; height: 280px; margin: auto"></div>
 
   <BasicModal v-bind="$attrs" @register="registerModal" title="一键测风" width="900px" @ok="handleOk" @cancel="handleCancel">
     <div class="head-line">
@@ -141,6 +138,8 @@
       <ModalTable ref="modalTable" deviceType="windrect_list" />
     </div>
   </BasicModal>
+  <HandleModal :modal-is-show="modalIsShow" modal-title="启动测风" :modal-type="modalType"  @handle-ok="controlDevice"
+      @handle-cancel="handleCancelControl" />
 </template>
 
 <script setup lang="ts">
@@ -149,35 +148,36 @@
   import { BasicModal, useModalInner } from '/@/components/Modal';
   import MonitorTable from '../comment/MonitorTable.vue';
   import ModalTable from './components/modalTable.vue';
+  import HandleModal from './components/modal.vue';
   import ResultTable from './components/resultTable.vue';
   import HistoryTable from '../comment/HistoryTable.vue';
   import AlarmHistoryTable from '../comment/AlarmHistoryTable.vue';
   import HandlerHistoryTable from '../comment/HandlerHistoryTable.vue';
   import { deviceControlApi } from '/@/api/vent/index';
-  import { mountedThree, destroy, addMonitorText, play, setModelType, playCamera } from './windrect.threejs';
-  import LivePlayer from '@liveqing/liveplayer-v3';
-  import { list, pathList, deviceList, testWind } from './windrect.api';
+  import { mountedThree, destroy, addMonitorText, play, setModelType, playCamera, initCameraCanvas } from './windrect.threejs';
+  import { list, pathList, deviceList, testWind, cameraAddrList, cameraList } from './windrect.api';
   import { list as baseList } from '../../deviceManager/windfindingTabel/windfinding.api';
   import { message, Progress } from 'ant-design-vue';
   import { chartsColumns } from './windrect.data';
   import { setDivHeight } from '/@/utils/event';
   import { BorderBox8 as DvBorderBox8 } from '@kjgl77/datav-vue3';
   import { useRouter } from 'vue-router';
+  import { deviceCameraInit } from '/@/utils/ventutil.ts'
 
   const { currentRoute } = useRouter();
 
   const MonitorDataTable = ref()
-
+  let webRtcServer: any[] = []
 
   const scroll = reactive({
     y: 240
   })
-
+  const modalType = ref('')
+  const modalIsShow = ref(false)
   const modalTable = ref();
   const runNum = ref(5); //设备运行数量
   const criticalPathList = ref([]);
-  const player1 = ref<HTMLDivElement | null>(null);
-  const player2 = ref<HTMLDivElement | null>(null);
+  const playerRef = ref();
   const activeKey = ref('1');
   const loading = ref(false);
   // 默认初始是第一行
@@ -199,13 +199,6 @@
     sensorLeft: 0
   });
 
-  const flvURL1 = () => {
-    // return `https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv`;
-    return ''
-  };
-  const flvURL2 = () => {
-    return `https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/flv/xgplayer-demo-360p.flv`;
-  };
 
   // const dataSource = computed(() => {
   //   const data = [...getRecordList()] || [];
@@ -549,26 +542,40 @@
   };
   
   function clearPlay() {
-    const data = {
-      deviceid: selectData.deviceID,
-      devicetype: selectData.deviceType,
-      paramcode: 'autoClear',
-      value: null,
-      masterComputer: selectData.masterComputer,
-    };
-    deviceControlApi(data)
-    .then((res) => {
-      // 模拟时开启
-      if (res.success) {
-        message.success('自清洁功能启动成功!')
-      }
-    })
+    modalType.value = 'autoClear'
+    modalIsShow.value = true
   }
 
   function startRun() {
-    testWind({ ids: [selectData.deviceID], maxnum: runNum.value }).then((res) => {
-      message.success('开始测风。。。');
-    });
+    modalType.value = 'sing'
+    modalIsShow.value = true
+  }
+
+  async function getCamera() {
+    const res = await cameraList({ deviceid: selectData['deviceID'] })
+    const cameras: [] = res.records || []
+    let cameraAddrs: any[] = [], cameraNames: string[] = [];
+    if (cameras.length > 0) {
+      cameras.forEach(item => {
+        if (item['devicekind'] == 'toRtsp' || item['devicekind'] == 'toHLS') {
+          cameraNames.push(item['name'])
+        } else {
+          cameraAddrs.push({ name: item['name'], addr: item['addr'] })
+        }
+      })
+    }
+    if (cameraNames.length > 0) {
+      // 请求接口从装备院拿数据
+      const addrs: string[] = await cameraAddrList({ cameraNameList: cameraNames })
+      for (let i = 0; i < addrs.length; i++) {
+        cameraAddrs.push({ name: '摄像头' + i, addr: addrs[i] })
+      }
+    }
+    const obj = await deviceCameraInit(cameraAddrs, playerRef.value, webRtcServer)
+    webRtcServer = obj.webRtcServerList
+    const playerDoms = obj.playerDoms
+    // 注意前后门适应需要对应 //[0] 后门 [1]前门
+    await initCameraCanvas(...playerDoms)
   }
 
   // 切换检测数据
@@ -576,13 +583,12 @@
     if(selectRow){
       loading.value = true;
       selectRowIndex.value = index;
-      
-      // Object.assign(selectData, selectRow);
+      Object.assign(selectData, selectRow);
       let type = ''
       if(selectRow.deviceType == 'windrect_rect') {
         type = 'lmWindRect'
       }
-      if (selectRow.deviceType == 'windrect_fold') {
+      if (selectRow.deviceType == 'windrect_normal') {
         type = 'zdWindRect'
       }
       if (selectRow.deviceType == 'windrect_rect_single') {
@@ -606,27 +612,15 @@
       loading.value = false;
       deviceRunState = ''
       tanTouRunState = ''
+      getCamera()
     }
     
   };
 
-  function addPlayVideo(event) {
-    event.preventDefault();
-    if (player1.value.play && player2.value.play) {
-      player1.value.play();
-      player2.value.play();
-      document.body.removeEventListener('mousedown', addPlayVideo);
-    }
-  };
-
   /* 一键测风 */
   function handleOk() {
-    const ids = toRaw(modalTable.value.selectedRowKeys);
-    testWind({ ids: ids, maxnum: runNum.value }).then((res) => {
-      message.success(res);
-      setModalProps({ visible: false });
-      modalTable.value.clearSelectedRowKeys();
-    });
+    modalType.value = 'multiple'
+    modalIsShow.value = true
   };
 
   /* 打开一键测风弹窗 */
@@ -644,6 +638,42 @@
     modalTable.value.clearSelectedRowKeys();
   };
 
+  /* 关闭一键测风控制*/
+  function handleCancelControl() {
+    modalIsShow.value = false
+  };
+
+  function controlDevice(passWord, type) {
+    if(type == 'sing'){
+      testWind({ ids: [selectData.deviceID], maxnum: runNum.value, password: passWord }).then((res) => {
+        message.success('开始测风。。。');
+      });
+    }else if(type == 'multiple'){
+      const ids = toRaw(modalTable.value.selectedRowKeys);
+      testWind({ ids: ids, maxnum: runNum.value, password: passWord }).then((res) => {
+        message.success(res);
+        setModalProps({ visible: false });
+        modalTable.value.clearSelectedRowKeys();
+      });
+    }else if(type == 'autoClear') {
+      const data = {
+        deviceid: selectData.deviceID,
+        devicetype: selectData.deviceType,
+        paramcode: 'autoClear',
+        value: null,
+        password: passWord,
+        masterComputer: selectData.masterComputer,
+      };
+      deviceControlApi(data)
+      .then((res) => {
+        // 模拟时开启
+        if (res.success) {
+          message.success('自清洁功能启动成功!')
+        }
+      })
+    }
+  }
+
   /** 避灾路线上的测风装置 */
   async function getPathList() {
     const pathArr = await pathList({});
@@ -670,11 +700,10 @@
   onMounted(() => {
     loading.value = true;
     
-    mountedThree(player1.value, player2.value).then(async () => {
+    mountedThree().then(async () => {
       getMonitor(true);
       // loading.value = false;
     });
-    document.body.addEventListener('mousedown', addPlayVideo, false);
   });
 
   onUnmounted(() => {
@@ -683,6 +712,11 @@
       clearTimeout(timer);
       timer = undefined;
     }
+    if (webRtcServer.length > 0) {
+      webRtcServer.forEach(item => {
+        item.disconnect()
+      })
+    }
   });
 </script>
 <style scoped lang="less">

+ 67 - 64
src/views/vent/monitorManager/windrectMonitor/longmen.threejs.ts

@@ -16,10 +16,8 @@ class lmWindRect {
   playerStartClickTime2 = new Date().getTime();
   deviceRunState = '';
 
-  constructor(model, playerVal1, playerVal2) {
+  constructor(model) {
     this.model = model;
-    this.player1 = playerVal1;
-    this.player2 = playerVal2;
     this.group.name = this.modelName;
   }
 
@@ -247,25 +245,25 @@ class lmWindRect {
     // 判断是否点击到视频
     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;
-      } else if (mesh.name === 'player2') {
-        if (new Date().getTime() - this.playerStartClickTime2 < 400) {
-          // 双击,视频放大
-          if (this.player2) {
-            this.player2.requestFullscreen();
-          }
-        }
-        this.playerStartClickTime2 = new Date().getTime();
-        return true;
-      }
+      // if (mesh.name === 'player1') {
+      //   if (new Date().getTime() - this.playerStartClickTime1 < 400) {
+      //     // 双击,视频放大
+      //     if (this.player1) {
+      //       this.player1.requestFullscreen();
+      //     }
+      //   }
+      //   this.playerStartClickTime1 = new Date().getTime();
+      //   return true;
+      // } else if (mesh.name === 'player2') {
+      //   if (new Date().getTime() - this.playerStartClickTime2 < 400) {
+      //     // 双击,视频放大
+      //     if (this.player2) {
+      //       this.player2.requestFullscreen();
+      //     }
+      //   }
+      //   this.playerStartClickTime2 = new Date().getTime();
+      //   return true;
+      // }
       return false;
     });
   }
@@ -350,6 +348,52 @@ class lmWindRect {
     }
   }
 
+  async initCamera(dom1?) {
+    const videoPlayer1 = dom1;
+    let monitorPlane: THREE.Mesh | null = null;
+    const canvas = await getTextCanvas(320, 180, '', 'noSinge.png');
+    const textMap = new THREE.CanvasTexture(canvas); // 关键一步
+    const textMaterial = new THREE.MeshBasicMaterial({
+      map: textMap, // 设置纹理贴图
+      transparent: true,
+      side: THREE.DoubleSide, // 这里是双面渲染的意思
+    });
+    textMaterial.blending = THREE.CustomBlending;
+    monitorPlane = this.group?.getObjectByName('noPlayer');
+    if (monitorPlane) {
+      monitorPlane.material = textMaterial;
+    } else {
+      const planeGeometry = new THREE.PlaneGeometry(100, 100); // 平面3维几何体PlaneGeometry
+      monitorPlane = new THREE.Mesh(planeGeometry, textMaterial);
+      textMaterial.dispose();
+      planeGeometry.dispose();
+    }
+    const videoPlayer = this.group.getObjectByName('player1');
+    if (videoPlayer) {
+      this.model.clearMesh(videoPlayer);
+      this.group.remove(videoPlayer);
+    }
+    const noPlayer1 = this.group.getObjectByName('noPlayer1');
+    if (noPlayer1) {
+      this.model.clearMesh(noPlayer1);
+      this.group.remove(noPlayer1);
+    }
+    if (!videoPlayer1 && videoPlayer1 === null) {
+      monitorPlane.name = 'noPlayer1';
+      monitorPlane.scale.set(0.013, 0.007, 0.012);
+      monitorPlane.position.set(-2.74, 0.0, -0.39);
+      this.group?.add(monitorPlane);
+    } else if (videoPlayer1) {
+      const mesh = renderVideo(this.group, videoPlayer1, 'player1');
+      if (mesh) {
+        mesh?.scale.set(0.042, 0.036, 0.022);
+        mesh?.position.set(-2.74, 0.03, -0.39);
+        mesh.rotation.y = -Math.PI;
+        this.group.add(mesh);
+      }
+    }
+  }
+
   mountedThree() {
     return new Promise((resolve) => {
       this.model.setGLTFModel([this.modelName]).then((gltf) => {
@@ -357,48 +401,7 @@ class lmWindRect {
         this.setModalPosition();
         this.initAnimation();
         this.addLight();
-        setTimeout(async () => {
-          const videoPlayer1 = document.getElementById('cf-player1')?.getElementsByClassName('vjs-tech')[0];
-          if (videoPlayer1) {
-            const mesh = renderVideo(this.group, videoPlayer1, 'player1');
-            mesh?.scale.set(0.042, 0.036, 0.022);
-            mesh?.position.set(-2.74, 0.03, -0.39);
-            this.group?.add(mesh as THREE.Mesh);
-          } else {
-            // 视频无信号
-            const textArr = [
-              {
-                text: `无信号输入`,
-                font: 'normal 40px Arial',
-                color: '#009900',
-                strokeStyle: '#002200',
-                x: 170,
-                y: 40,
-              },
-            ];
-            getTextCanvas(560, 346, textArr, '').then((canvas: HTMLCanvasElement) => {
-              const textMap = new THREE.CanvasTexture(canvas); // 关键一步
-              const textMaterial = new THREE.MeshBasicMaterial({
-                map: textMap, // 设置纹理贴图
-                transparent: true,
-                side: THREE.DoubleSide, // 这里是双面渲染的意思
-              });
-              textMaterial.blending = THREE.CustomBlending;
-              const monitorPlane = this.group?.getObjectByName('noPlayer');
-              if (monitorPlane) {
-                monitorPlane.material = textMaterial;
-              } else {
-                const planeGeometry = new THREE.PlaneGeometry(100, 100); // 平面3维几何体PlaneGeometry
-                const planeMesh = new THREE.Mesh(planeGeometry, textMaterial);
-                planeMesh.name = 'noPlayer';
-                planeMesh.scale.set(0.012, 0.009, 0.012);
-                planeMesh.position.set(-2.72, -0.34, -0.39);
-                this.group?.add(planeMesh);
-              }
-            });
-          }
-          resolve(null);
-        }, 0);
+        resolve(null);
       });
     });
   }

+ 57 - 55
src/views/vent/monitorManager/windrectMonitor/longmenSide.threejs.ts

@@ -17,10 +17,8 @@ class lmWindRectSide {
   deviceRunState = '';
   tanTouRunState = '';
 
-  constructor(model, playerVal1, playerVal2) {
+  constructor(model) {
     this.model = model;
-    this.player1 = playerVal1;
-    this.player2 = playerVal2;
     this.group.name = this.modelName;
   }
 
@@ -247,17 +245,17 @@ class lmWindRectSide {
 
     intersects.find((intersect) => {
       const mesh = intersect.object;
-      if (mesh.name === 'player1') {
-        if (new Date().getTime() - this.playerStartClickTime1 < 400) {
-          // 双击,视频放大
-          if (this.player1) {
-            this.player1.requestFullscreen();
-          }
-        }
+      // if (mesh.name === 'player1') {
+      //   if (new Date().getTime() - this.playerStartClickTime1 < 400) {
+      //     // 双击,视频放大
+      //     if (this.player1) {
+      //       this.player1.requestFullscreen();
+      //     }
+      //   }
 
-        this.playerStartClickTime1 = new Date().getTime();
-        return true;
-      }
+      //   this.playerStartClickTime1 = new Date().getTime();
+      //   return true;
+      // }
       return false;
     });
     // console.log('999999999', this.model.camera.position, this.model.orbitControls);
@@ -379,6 +377,51 @@ class lmWindRectSide {
     }
   }
 
+  async initCamera(dom1?) {
+    const videoPlayer1 = dom1;
+    let monitorPlane: THREE.Mesh | null = null;
+    const canvas = await getTextCanvas(320, 180, '', 'noSinge.png');
+    const textMap = new THREE.CanvasTexture(canvas); // 关键一步
+    const textMaterial = new THREE.MeshBasicMaterial({
+      map: textMap, // 设置纹理贴图
+      transparent: true,
+      side: THREE.DoubleSide, // 这里是双面渲染的意思
+    });
+    textMaterial.blending = THREE.CustomBlending;
+    monitorPlane = this.group?.getObjectByName('noPlayer');
+    if (monitorPlane) {
+      monitorPlane.material = textMaterial;
+    } else {
+      const planeGeometry = new THREE.PlaneGeometry(100, 100); // 平面3维几何体PlaneGeometry
+      monitorPlane = new THREE.Mesh(planeGeometry, textMaterial);
+      textMaterial.dispose();
+      planeGeometry.dispose();
+    }
+    const videoPlayer = this.group.getObjectByName('player1');
+    if (videoPlayer) {
+      this.model.clearMesh(videoPlayer);
+      this.group.remove(videoPlayer);
+    }
+    const noPlayer1 = this.group.getObjectByName('noPlayer1');
+    if (noPlayer1) {
+      this.model.clearMesh(noPlayer1);
+      this.group.remove(noPlayer1);
+    }
+    if (!videoPlayer1 && videoPlayer1 === null) {
+      monitorPlane.name = 'noPlayer1';
+      monitorPlane.scale.set(0.013, 0.007, 0.012);
+      monitorPlane.position.set(-2.67, 0.0, -0.39);
+      this.group?.add(monitorPlane);
+    } else if (videoPlayer1) {
+      const mesh = renderVideo(this.group, videoPlayer1, 'player1');
+      if (mesh) {
+        mesh?.scale.set(0.042, 0.036, 0.022);
+        mesh?.position.set(-2.65, 0.03, -0.39);
+        mesh.rotation.y = -Math.PI;
+        this.group.add(mesh);
+      }
+    }
+  }
   mountedThree() {
     return new Promise((resolve) => {
       this.model.setGLTFModel([this.modelName]).then((gltf) => {
@@ -388,48 +431,7 @@ class lmWindRectSide {
         const probeBar = this.group?.getObjectByName('probe_bar') as THREE.Object3D;
         probeBar.position.setY(0.35);
         this.addLight();
-        setTimeout(async () => {
-          const videoPlayer1 = document.getElementById('cf-player1')?.getElementsByClassName('vjs-tech')[0];
-
-          if (videoPlayer1) {
-            const mesh = renderVideo(this.group, videoPlayer1, 'player1');
-            mesh?.scale.set(0.042, 0.036, 0.022);
-            mesh?.position.set(-2.65, 0.03, -0.39);
-            this.group?.add(mesh as THREE.Mesh);
-          } else {
-            const textArr = [
-              {
-                text: `无信号输入`,
-                font: 'normal 40px Arial',
-                color: '#009900',
-                strokeStyle: '#002200',
-                x: 170,
-                y: 40,
-              },
-            ];
-            getTextCanvas(560, 346, textArr, '').then((canvas: HTMLCanvasElement) => {
-              const textMap = new THREE.CanvasTexture(canvas); // 关键一步
-              const textMaterial = new THREE.MeshBasicMaterial({
-                map: textMap, // 设置纹理贴图
-                transparent: true,
-                side: THREE.DoubleSide, // 这里是双面渲染的意思
-              });
-              textMaterial.blending = THREE.CustomBlending;
-              const monitorPlane = this.group?.getObjectByName('noPlayer');
-              if (monitorPlane) {
-                monitorPlane.material = textMaterial;
-              } else {
-                const planeGeometry = new THREE.PlaneGeometry(100, 100); // 平面3维几何体PlaneGeometry
-                const planeMesh = new THREE.Mesh(planeGeometry, textMaterial);
-                planeMesh.name = 'noPlayer';
-                planeMesh.scale.set(0.012, 0.009, 0.012);
-                planeMesh.position.set(-2.63, -0.32, -0.39);
-                this.group?.add(planeMesh);
-              }
-            });
-          }
-          resolve(null);
-        }, 0);
+        resolve(null);
       });
     });
   }

+ 6 - 0
src/views/vent/monitorManager/windrectMonitor/windrect.api.ts

@@ -8,6 +8,8 @@ enum Api {
   resultList = '/safety/testwind/list',
   importExcel = '/sys/user/importExcel',
   exportXls = 'safety/testwindDetail/exportXls',
+  cameraList = '/safety/ventanalyCamera/list',
+  cameraAddrList = '/ventanaly-device/camera/info',
 }
 /**
  * 导出api
@@ -46,3 +48,7 @@ export const pathList = (params) => defHttp.get({ url: Api.pathList, params });
  */
 export const deviceList = (params) => defHttp.get({ url: Api.deviceList, params });
 
+export const cameraAddrList = (params) => defHttp.post({ url: Api.cameraAddrList, params });
+
+export const cameraList = (params) => defHttp.get({ url: Api.cameraList, params });
+

+ 17 - 5
src/views/vent/monitorManager/windrectMonitor/windrect.threejs.ts

@@ -92,6 +92,18 @@ export const play = (flag, isDirect = false) => {
   }
 };
 
+export const initCameraCanvas = async (playerVal1?) => {
+  if (windRectType === 'lmWindRect' && lmWindRectObj) {
+    return lmWindRectObj.initCamera.call(lmWindRectObj, playerVal1);
+  } else if (windRectType === 'zdWindRect' && zdWindRectObj) {
+    return zdWindRectObj.initCamera.call(zdWindRectObj, playerVal1);
+  } else if (windRectType.startsWith('dsWindRect') && dsWindRectObj) {
+    return dsWindRectObj.initCamera.call(dsWindRectObj, playerVal1);
+  } else if (windRectType === 'lmWindSide' && lmWindRectSideObj) {
+    lmWindRectSideObj.initCamera.call(lmWindRectSideObj, playerVal1);
+  }
+};
+
 export const playCamera = (flag) => {
   if (windRectType === 'lmWindSide') {
     lmWindRectSideObj.playCamera.call(lmWindRectSideObj, flag);
@@ -287,21 +299,21 @@ export const setModelType = (type) => {
   });
 };
 
-export const mountedThree = (playerVal1, playerVal2) => {
+export const mountedThree = () => {
   return new Promise(async (resolve) => {
     model = new UseThree('#window3D');
     model.setEnvMap('test1');
     model.renderer.toneMappingExposure = 1.0;
-    lmWindRectObj = new lmWindRect(model, playerVal1, playerVal2);
+    lmWindRectObj = new lmWindRect(model);
     await lmWindRectObj.mountedThree();
 
-    zdWindRectObj = new zdWindRect(model, playerVal1);
+    zdWindRectObj = new zdWindRect(model);
     await zdWindRectObj.mountedThree();
 
-    dsWindRectObj = new dsWindRect(model, playerVal1);
+    dsWindRectObj = new dsWindRect(model);
     await dsWindRectObj.mountedThree();
 
-    lmWindRectSideObj = new lmWindRectSide(model, playerVal1, playerVal2);
+    lmWindRectSideObj = new lmWindRectSide(model);
     await lmWindRectSideObj.mountedThree();
 
     ddWindRectObj = new ddWindRect(model);

+ 58 - 53
src/views/vent/monitorManager/windrectMonitor/zhedie.threejs.ts

@@ -18,9 +18,8 @@ class zdWindRect {
   player1;
   playerStartClickTime1 = new Date().getTime();
 
-  constructor(model, playerVal1) {
+  constructor(model) {
     this.model = model;
-    this.player1 = playerVal1;
     this.group.name = this.modelName;
   }
 
@@ -240,16 +239,16 @@ class zdWindRect {
     // 判断是否点击到视频
     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;
-      }
+      // 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;
     });
   }
@@ -303,6 +302,52 @@ class zdWindRect {
     // }
   }
 
+  async initCamera(dom1?) {
+    const videoPlayer1 = dom1;
+    let monitorPlane: THREE.Mesh | null = null;
+    const canvas = await getTextCanvas(320, 180, '', 'noSinge.png');
+    const textMap = new THREE.CanvasTexture(canvas); // 关键一步
+    const textMaterial = new THREE.MeshBasicMaterial({
+      map: textMap, // 设置纹理贴图
+      transparent: true,
+      side: THREE.DoubleSide, // 这里是双面渲染的意思
+    });
+    textMaterial.blending = THREE.CustomBlending;
+    monitorPlane = this.group?.getObjectByName('noPlayer');
+    if (monitorPlane) {
+      monitorPlane.material = textMaterial;
+    } else {
+      const planeGeometry = new THREE.PlaneGeometry(100, 100); // 平面3维几何体PlaneGeometry
+      monitorPlane = new THREE.Mesh(planeGeometry, textMaterial);
+      textMaterial.dispose();
+      planeGeometry.dispose();
+    }
+    const videoPlayer = this.group.getObjectByName('player1');
+    if (videoPlayer) {
+      this.model.clearMesh(videoPlayer);
+      this.group.remove(videoPlayer);
+    }
+    const noPlayer1 = this.group.getObjectByName('noPlayer1');
+    if (noPlayer1) {
+      this.model.clearMesh(noPlayer1);
+      this.group.remove(noPlayer1);
+    }
+    if (!videoPlayer1 && videoPlayer1 === null) {
+      monitorPlane.name = 'noPlayer1';
+      monitorPlane.scale.set(0.011, 0.006, 0.012);
+      monitorPlane.position.set(4.79, -0.2, -0.39);
+      this.group?.add(monitorPlane);
+    } else if (videoPlayer1) {
+      const mesh = renderVideo(this.group, videoPlayer1, 'player1');
+      if (mesh) {
+        mesh?.scale.set(0.0385, 0.028, 0.022);
+        mesh?.position.set(4.792, -0.16, -0.4);
+        mesh.rotation.y = -Math.PI;
+        this.group.add(mesh);
+      }
+    }
+  }
+
   mountedThree() {
     return new Promise((resolve) => {
       this.model.setGLTFModel([this.modelName]).then((gltf) => {
@@ -310,47 +355,7 @@ class zdWindRect {
         this.setModalPosition();
         this.initAnimation();
         this.addLight();
-        setTimeout(async () => {
-          const videoPlayer1 = document.getElementById('cf-player1')?.getElementsByClassName('vjs-tech')[0];
-          if (videoPlayer1) {
-            const mesh = renderVideo(this.group, videoPlayer1, 'player1');
-            mesh?.scale.set(0.0385, 0.028, 0.022);
-            mesh?.position.set(4.792, -0.16, -0.4);
-            if (mesh) this.group?.add(mesh);
-          } else {
-            const textArr = [
-              {
-                text: `无信号输入`,
-                font: 'normal 40px Arial',
-                color: '#009900',
-                strokeStyle: '#002200',
-                x: 170,
-                y: 40,
-              },
-            ];
-            getTextCanvas(560, 346, textArr, '').then((canvas: HTMLCanvasElement) => {
-              const textMap = new THREE.CanvasTexture(canvas); // 关键一步
-              const textMaterial = new THREE.MeshBasicMaterial({
-                map: textMap, // 设置纹理贴图
-                transparent: true,
-                side: THREE.DoubleSide, // 这里是双面渲染的意思
-              });
-              textMaterial.blending = THREE.CustomBlending;
-              const monitorPlane = this.group?.getObjectByName('noPlayer');
-              if (monitorPlane) {
-                monitorPlane.material = textMaterial;
-              } else {
-                const planeGeometry = new THREE.PlaneGeometry(100, 100); // 平面3维几何体PlaneGeometry
-                const planeMesh = new THREE.Mesh(planeGeometry, textMaterial);
-                planeMesh.name = 'noPlayer';
-                planeMesh.scale.set(0.012, 0.009, 0.012);
-                planeMesh.position.set(4.83, -0.5, -0.39);
-                this.group?.add(planeMesh);
-              }
-            });
-          }
-          resolve(null);
-        }, 0);
+        resolve(null);
       });
     });
   }

+ 1 - 0
types/config.d.ts

@@ -137,6 +137,7 @@ export interface ProjectConfig {
 }
 
 export interface GlobConfig {
+  logoUrl: string;
   // Site title
   title: string;
   // Service interface url