ZaiZai 1 سال پیش
والد
کامیت
e7c576c3e1
2فایلهای تغییر یافته به همراه89 افزوده شده و 41 حذف شده
  1. 2 1
      src/layout/index.vue
  2. 87 40
      src/plugins/HcSocket.js

+ 2 - 1
src/layout/index.vue

@@ -50,7 +50,7 @@ import { useAppStore } from '~src/store'
 import { getToken } from '~src/api/auth'
 import { useRoute, useRouter } from 'vue-router'
 import { initButtons } from '~sto/app'
-import { isNullES } from 'js-fast-way'
+import { isNullES, useClick } from 'js-fast-way'
 import { HcSocket } from '~src/plugins/HcSocket'
 import messageApi from '~api/tasks/message'
 
@@ -128,6 +128,7 @@ let socket
 const timeExamples = ref()
 const times = ref(10000)
 const cascaderSend = async ({ projectId, contractId }) => {
+    await useClick()
     //合同段id为空,清空定时器
     if (isNullES(contractId)) {
         if (!isNullES(timeExamples.value)) clearInterval(timeExamples.value)

+ 87 - 40
src/plugins/HcSocket.js

@@ -5,13 +5,24 @@ import { getObjValue, isNullES } from 'js-fast-way'
 class HcSocket {
 
     constructor(data, change) {
-        this.limit = 30
+        this.limit = 10
         this.interval = 10000
         this.param = getObjValue(data)
         this.onChange = change
         this.socket = null
-        this.create()
-        //this.moreTabs()
+        this.isReconnecting = false
+        this.connectionStatus = 'disconnected'
+        this.isManualClosed = false
+        if (this.validateParams()) {
+            this.create()
+            //this.handleMultipleTabs()
+        }
+    }
+
+    validateParams() {
+        const { projectId, contractId, userId } = this.param
+        const { socket: socketUrl, clientId } = website
+        return !(isNullES(socketUrl) || isNullES(clientId) || isNullES(projectId) || isNullES(contractId) || isNullES(userId))
     }
 
     //创建连接
@@ -19,39 +30,52 @@ class HcSocket {
         const { projectId, contractId, userId } = this.param
         const { socket: socketUrl, clientId } = website
 
-        if (isNullES(socketUrl) || isNullES(clientId) || isNullES(projectId) || isNullES(contractId) || isNullES(userId)) {
-            return
-        }
-
-        //拼接URL并登录socket
         const url = `${socketUrl}/blade-${clientId}/${projectId}/${contractId}/${userId}`
         this.socket = new WebSocket(url)
 
-        this.socket.onopen = ()=> {
-            console.log('WebSocket 链接成功')
-        }
+        this.socket.onopen = this.handleOpen.bind(this)
+        this.socket.onclose = this.handleClose.bind(this)
+        this.socket.onmessage = this.handleMessage.bind(this)
+        this.socket.onerror = this.handleError.bind(this)
+    }
+
+    handleOpen() {
+        console.log('WebSocket 链接成功')
+        this.connectionStatus = 'connected'
+        this.isManualClosed = false
+    }
 
-        this.socket.onclose = async () => {
-            console.log('WebSocket 链接已断开')
-            await this.reconnect()
+    handleClose() {
+        console.log('WebSocket 链接已断开')
+        this.connectionStatus = 'disconnected'
+        if (!this.isManualClosed) {
+            this.reconnect()
         }
+    }
 
-        this.socket.onmessage = ({ data })=> {
-            try {
-                const parsedData = JSON.parse(data)
-                if (typeof this.onChange === 'function') {
-                    this.onChange(parsedData)
-                }
-            } catch (error) {
-                console.error('解析 WebSocket 数据时出错:', error)
+    handleMessage({ data }) {
+        try {
+            const parsedData = JSON.parse(data)
+            if (typeof this.onChange === 'function') {
+                this.onChange(parsedData)
             }
+        } catch (error) {
+            console.error('解析 WebSocket 数据时出错:', error)
         }
     }
 
+    handleError(error) {
+        console.error('WebSocket 错误:', error)
+        this.connectionStatus = 'error'
+    }
+
     //发送消息
-    async send(data) {
-        if (!this.isSocket()) return
-        this.socket.send(data)
+    send(data) {
+        if (this.isSocket()) {
+            this.socket.send(data)
+        } else {
+            console.warn('消息发送失败')
+        }
     }
 
     //链接是否存在
@@ -61,31 +85,54 @@ class HcSocket {
 
     //尝试重连
     async reconnect(attempts = 0) {
-        if (attempts >= this.limit) return
-        if (isNullES(this.socket) || this.socket.readyState === WebSocket.CLOSED) {
+        if (this.isReconnecting || this.isManualClosed) return
+        this.isReconnecting = true
+
+        while (attempts < this.limit && !this.isSocket() && !this.isManualClosed) {
+            console.log(`重新链接中... (${attempts + 1}/${this.limit})`)
             this.create()
+            await new Promise(resolve => setTimeout(resolve, this.getReconnectInterval(attempts)))
+            attempts++
         }
-        await new Promise(resolve => setTimeout(resolve, this.interval))
-        if (!this.isSocket()) {
-            await this.reconnect(attempts + 1)
+
+        this.isReconnecting = false
+        if (!this.isSocket() && !this.isManualClosed) {
+            console.error('达到最大重连次数后仍然失败')
         }
     }
 
+    // 指数退避策略
+    getReconnectInterval(attempt) {
+        return Math.min(1000 * Math.pow(2, attempt), 30000)
+    }
+
+    handleMultipleTabs() {
+        document.addEventListener('visibilitychange', this.handleVisibilityChange.bind(this))
+    }
+
     // 处理多标签页问题
-    moreTabs() {
-        document.addEventListener('visibilitychange', () => {
-            if (document.visibilityState === 'visible' && !this.isSocket()) {
-                this.create()
-            } else if (document.visibilityState === 'hidden') {
-                this.close()
-            }
-        })
+    handleVisibilityChange() {
+        if (document.visibilityState === 'visible' && !this.isSocket() && !this.isManualClosed) {
+            this.create()
+        } else if (document.visibilityState === 'hidden') {
+            this.close()
+        }
     }
 
     //关闭或断开连接
     close() {
-        if (!this.isSocket()) return
-        this.socket.close()
+        this.isManualClosed = true
+        if (this.isSocket()) {
+            this.socket.close()
+        }
+        this.connectionStatus = 'disconnected'
+    }
+
+    destroy() {
+        this.close()
+        //document.removeEventListener('visibilitychange', this.handleVisibilityChange)
+        this.socket = null
+        this.onChange = null
     }
 }