浏览代码

首页视频数量修改3/4 加入webTRC流

dedsudiyu 1 天之前
父节点
当前提交
f7bf72ade5
共有 4 个文件被更改,包括 161 次插入14 次删除
  1. 1 1
      .env.production
  2. 20 12
      src/components/LabStats/videoStats.vue
  3. 140 0
      src/components/LabStats/webRTC.vue
  4. 0 1
      src/components/videoForMod/videoForMod.vue

+ 1 - 1
.env.production

@@ -5,7 +5,7 @@ NODE_ENV=production
 VUE_APP_TITLE=中国安全生产科学研究院实验室安全智慧化管控中心
 
 # 接口基础地址
-VUE_APP_BASE_API=http://192.168.166.11/api
+VUE_APP_BASE_API=https://192.168.166.11/api
 
 # 接口超时时间(毫秒)
 VUE_APP_TIMEOUT=20000

+ 20 - 12
src/components/LabStats/videoStats.vue

@@ -4,6 +4,7 @@
     <div class="corner-deco bl"></div><div class="corner-deco br"></div>
     <div class="panel-title">实验室视频监控</div>
     <div class="video-content">
+      <webRTC v-if="webRtcType"></webRTC>
       <videoForMod v-for="(item,index) in modList" :key="index"
                    :deviceNo="item.deviceNo"></videoForMod>
     </div>
@@ -12,9 +13,10 @@
 <script>
   import { getVideoList,laboratoryLabScreenScreenConfigGet,iotDeviceList } from '@/api/index'
   import videoForMod from '@/components/videoForMod/videoForMod.vue'
+  import webRTC from './webRTC.vue'
   export default {
     name: 'videoStats',
-    components: { videoForMod },
+    components: { videoForMod,webRTC },
     data () {
       return {
         width:470,
@@ -22,6 +24,7 @@
         modList:[],
         pollTimer:null,
         page:1,
+        webRtcType:false,
       }
     },
     created(){
@@ -57,9 +60,17 @@
           if (res.code === 200) {
             this.$set(this,'modList',[]);
             if(res.data.effective){
+              this.$set(this,'webRtcType',true);
               this.$set(this,'page',1);
-              this.$set(this,'modList',res.data.items);
+              let list = [];
+              for(let i=0;i<res.data.items.length;i++){
+                if(i<3){
+                  list.push(res.data.items[i])
+                }
+              }
+              this.$set(this,'modList',list);
             }else{
+              this.$set(this,'webRtcType',false);
               this.iotDeviceList();
             }
           }
@@ -141,18 +152,15 @@
     z-index: 2;
     flex: 1;
     min-height: 0;
-    .H5PlayerVideo:nth-child(1){
-      margin-right:10px;
-      margin-bottom:10px;
-    }
-    .H5PlayerVideo:nth-child(2){
-      margin-bottom:10px;
+    .videoForMod:nth-child(2){
+      margin-left:10px;
     }
-    .H5PlayerVideo:nth-child(3){
-      margin-right:10px;
+    .videoForMod:nth-child(3){
+      margin-top:5px;
     }
-    .H5PlayerVideo:nth-child(4){
-
+    .videoForMod:nth-child(4){
+      margin-top:5px;
+      margin-left:10px;
     }
   }
 </style>

+ 140 - 0
src/components/LabStats/webRTC.vue

@@ -0,0 +1,140 @@
+<!-- rtc流组件 -->
+<template>
+    <div class="webRTC">
+      <video
+        ref="videoElement"
+        autoplay
+        muted
+        playsinline
+        style="width:470px;height:290px;background-color: #000; display: block;"
+      ></video>
+      <p class="right-text">AI</p>
+    </div>
+</template>
+<script>
+  const OFFER_URL = 'https://192.168.166.11/offer'
+  const RETRY_INTERVAL = 5000 // 失败后 5 秒重连
+  export default {
+    name: 'webRTC',
+    data() {
+      return {
+        pc: null,
+        retryTimer: null
+      }
+    },
+    mounted() {
+      console.log('screenType',this.screenType);
+      this.connect()
+    },
+    beforeDestroy() {
+      this._clearRetry()
+      this._cleanup()
+    },
+    methods: {
+      async connect() {
+        this._cleanup()
+
+        try {
+          this.pc = new RTCPeerConnection({
+            iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
+            iceTransportPolicy: 'all'
+          })
+
+          this.pc.ontrack = (event) => {
+            this.$refs.videoElement.srcObject = event.streams[0]
+          }
+
+          this.pc.onconnectionstatechange = () => {
+            const state = this.pc && this.pc.connectionState
+            if (state === 'failed' || state === 'disconnected' || state === 'closed') {
+              this._scheduleRetry()
+            }
+          }
+
+          this.pc.addTransceiver('video', { direction: 'recvonly' })
+          this.pc.addTransceiver('audio', { direction: 'recvonly' })
+
+          const offer = await this.pc.createOffer()
+          await this.pc.setLocalDescription(offer)
+          await this._waitIceGathering()
+
+          const response = await fetch(OFFER_URL, {
+            method: 'POST',
+            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+            body: JSON.stringify({
+              sdp: this.pc.localDescription.sdp,
+              type: this.pc.localDescription.type
+            })
+          })
+
+          if (!response.ok) throw new Error(`HTTP ${response.status}`)
+
+          const answer = await response.json()
+          await this.pc.setRemoteDescription(new RTCSessionDescription(answer))
+
+        } catch (e) {
+          console.error('[WebRTC] 连接失败,准备重连:', e)
+          this._scheduleRetry()
+        }
+      },
+
+      _scheduleRetry() {
+        this._cleanup()
+        this._clearRetry()
+        this.retryTimer = setTimeout(() => this.connect(), RETRY_INTERVAL)
+      },
+
+      _clearRetry() {
+        if (this.retryTimer) {
+          clearTimeout(this.retryTimer)
+          this.retryTimer = null
+        }
+      },
+
+      _cleanup() {
+        if (this.pc) {
+          this.pc.ontrack = null
+          this.pc.onconnectionstatechange = null
+          this.pc.close()
+          this.pc = null
+        }
+        if (this.$refs.videoElement) {
+          this.$refs.videoElement.srcObject = null
+        }
+      },
+
+      _waitIceGathering() {
+        return new Promise((resolve) => {
+          if (this.pc.iceGatheringState === 'complete') return resolve()
+          const check = () => {
+            if (this.pc && this.pc.iceGatheringState === 'complete') {
+              this.pc.removeEventListener('icegatheringstatechange', check)
+              resolve()
+            }
+          }
+          this.pc.addEventListener('icegatheringstatechange', check)
+          setTimeout(resolve, 5000)
+        })
+      }
+    }
+  }
+</script>
+<style scoped lang="scss">
+    .webRTC {
+      width:470px;
+      height:290px;
+      display: inline-block;
+      position: relative;
+      .right-text{
+        position: absolute;
+        top:5px;
+        right:5px;
+        background: rgba(255, 240, 200, 0.9);
+        color: #d48806;
+        border:1px solid #ffd591;
+        padding:0 5px;
+        border-radius:4px;
+        font-size:12px;
+      }
+    }
+</style>

+ 0 - 1
src/components/videoForMod/videoForMod.vue

@@ -77,6 +77,5 @@
       display: inline-block;
       width:470px;
       height:290px;
-      margin:0 0 0 5px;
     }
 </style>