Bläddra i källkod

+ 视频跟随前端

chen.cheng 6 månader sedan
förälder
incheckning
a7cf4a19a4

+ 1 - 2
package.json

@@ -15,8 +15,7 @@
     "lint": "eslint --ext .js,.vue src"
   },
   "husky": {
-    "hooks": {
-    }
+    "hooks": {}
   },
   "lint-staged": {
     "src/**/*.{js,vue}": [

+ 36 - 13
src/components/VideoTrail/index.vue

@@ -15,20 +15,27 @@
       <div class="trail-videos">
         <video-obj
             v-for="item in videoList"
-            :key="item.id"
-            :stream="ws"
+            :key="item.key"
+            :stream="item.video.liveStream"
             :lastTime="0"
         />
       </div>
     </div>
+    <socket-message
+        v-if="this.fingerprint.visitorId"
+        :onMessage="onMessage"
+        :ws="`/pkb/uwb/trail?client=${this.fingerprint.visitorId}&deviceId=${deviceId}`"
+    />
   </div>
 </template>
 
 <script>
 import VideoObj from "@/components/Video/index.vue";
+import SocketMessage from "@/components/WebsocketMessage/index.vue";
+import FingerprintJS from "@fingerprintjs/fingerprintjs";
 
 export default {
-  components: {VideoObj},
+  components: {SocketMessage, VideoObj},
   name: "video-trail",
   props: {
     ws: {
@@ -43,14 +50,22 @@ export default {
   },
   data() {
     return {
-      videoList: []
+      videoList: [],
+      fingerprint: "",
+      deviceId: "845D3",
+      timer: null // 新增定时器变量
     };
   },
   // 组件卸载前清空图层信息
   beforeDestroy() {
+    if (this.timer) {
+      clearInterval(this.timer); // 清除定时器
+    }
   },
   created() {
-
+    this.getBrowserFingerprint();
+    this.removeOldVideos(); // 添加调用
+    this.timer = setInterval(this.removeOldVideos, 60000); // 每分钟调用一次,并将定时器赋值给timer变量
   },
   mounted() {
     this.init();
@@ -59,21 +74,29 @@ export default {
     init() {
 
     },
-    updateVideoList(newVideo) {
-      const videoIndex = this.videoList.findIndex(video => video.id === newVideo.id);
+    onMessage(newVideo) {
+      const {msg: video} = newVideo
+      video.srcTimestamp = Date.now();
+      video.key = `${video.key}_${video.fenceId}`;
+      const videoIndex = this.videoList.findIndex(item => item.key === video.key);
       if (videoIndex !== -1) {
         this.videoList.splice(videoIndex, 1);
       }
-      this.videoList.unshift(newVideo);
-
-      // 删除超过20分钟的视频
+      this.videoList.unshift(video);
+    },
+    removeOldVideos() {
       const currentTime = Date.now();
-      while (this.videoList.length > 0 && (currentTime - this.videoList[this.videoList.length - 1].timestamp) > 20 * 60 * 1000) {
+      while (this.videoList.length > 0 && (currentTime - this.videoList[this.videoList.length - 1].srcTimestamp) > 20 * 60 * 1000) {
         this.videoList.pop();
       }
     },
-    onMessage() {
-
+    async getBrowserFingerprint() {
+      try {
+        const fp = await FingerprintJS.load();
+        this.fingerprint = await fp.get();
+      } catch (error) {
+        console.error('Error loading fingerprint generator:', error);
+      }
     },
   },
 };

+ 49 - 38
src/components/WebsocketMessage/index.vue

@@ -9,61 +9,72 @@ export default {
   props: {
     onMessage: {
       type: Function,
-      default: function () {
-      },
+      required: true,
     },
     ws: {
       type: String,
-      default: '',
-    },
-  },
-  watch: {
-    ws(val) {
-      this.init();
+      required: true,
     },
   },
   data() {
     return {
       socket: null,
       url: prefix,
+      reconnectInterval: 5000, // 重连间隔时间(毫秒)
+      maxReconnectAttempts: 10, // 最大重连次数
+      reconnectAttempts: 0, // 当前重连次数
     };
   },
-  // 组件卸载前清空图层信息
-  beforeDestroy() {
-    this.socket.close();
-  },
-  created() {
-
-  },
   mounted() {
-    this.init();
+    this.connect();
+  },
+  beforeDestroy() {
+    this.disconnect();
   },
   methods: {
-    init() {
-      if (!this.ws) {
-        return;
-      }
-      if (this.ws && this.socket) {
+    connect() {
+      this.socket = new WebSocket(`${prefix}${this.ws}`);
+      this.socket.onopen = this.onOpen;
+      this.socket.onmessage = this.onMessageReceived;
+      this.socket.onerror = this.onError;
+      this.socket.onclose = this.onClose;
+    },
+    disconnect() {
+      if (this.socket) {
         this.socket.close();
-        return;
+        this.socket = null;
       }
-      this.socket = new WebSocket(`${prefix}${this.ws}`);
-      this.socket.onopen = () => {
-        console.log('连接成功:', this.ws);
-      };
-      // 监听socket错误信息
-      this.socket.onerror = (e) => {
-        console.log('%c FXY', 'color:#f6b2b1;font-size:50px', e);
-        console.log('socket连接失败');
-      };
-      // 监听socket关闭监听
-      this.socket.onclose = () => {
-        console.log('socket连接关闭');
-      };
-      this.socket.onmessage = (a) => {
-        this.onMessage(a);
-      };
     },
+    onOpen() {
+      console.log('WebSocket connection established');
+      this.reconnectAttempts = 0; // 重置重连次数
+    },
+    onMessageReceived(event) {
+      const data = JSON.parse(event.data);
+      this.onMessage(data);
+    },
+    onError(error) {
+      console.error('WebSocket error:', error);
+    },
+    onClose(event) {
+      console.log('WebSocket closed:', event);
+      this.reconnect();
+    },
+    reconnect() {
+      if (this.socket && this.socket.readyState === WebSocket.CLOSED) {
+        if (this.reconnectAttempts < this.maxReconnectAttempts) {
+          console.log(`Reconnecting in ${this.reconnectInterval}ms...`);
+          setTimeout(() => {
+            this.reconnectAttempts++;
+            this.connect();
+          }, this.reconnectInterval);
+        } else {
+          console.error('Max reconnect attempts reached');
+        }
+      } else {
+        console.log('WebSocket is not closed, no need to reconnect');
+      }
+    }
   },
 };
 </script>

+ 1 - 1
src/views/bd/fenceEvt/index.vue

@@ -216,7 +216,7 @@ export default {
         ...components,
       };
       const fingerprintId = FingerprintJS.hashComponents(extendedComponents);
-      this.ws = `/ws/evt/${fingerprintId}`;
+      this.ws = `/pkbs/evt/${fingerprintId}`;
     },
     onMessage(a) {
       const data = JSON.parse(a.data);