// src/utils/socket.js import { ElMessage } from 'element-plus' import { ROOTPATH2 } from '../comment/httpUrl.js' let WSS = null // 全局唯一 WebSocket 实例 let heartTimer = null // 心跳定时器 let reconnectTimer = null // 重连定时器 let reconnectCount = 0 // 当前重连次数 const MAX_RECONNECT = 10 // 最大重连次数 const RECONNECT_INTERVAL = 3000 // 重连间隔 3 秒 let manuallyClosed = false /** * 连接 WebSocket * @param {string} userId 当前用户 ID * @param {object} store Vuex store 实例 * @param {object} router Vue Router 实例 */ export function connectSocket(userId, store, router) { if (!userId) return manuallyClosed = false // 若已有连接则关闭旧连接 if (WSS) { try { WSS.close() } catch { } } // 生成 tabId let tabId = sessionStorage.getItem('tabId') if (!tabId) { tabId = Date.now() + '_' + Math.random().toString(36).slice(2) sessionStorage.setItem('tabId', tabId) } const wsUrl = `${ROOTPATH2}${userId}?tabId=${tabId}` WSS = new WebSocket(wsUrl) console.log('WebSocket 连接中:', wsUrl) /** 连接成功 */ WSS.onopen = () => { console.log('WebSocket 已连接:', wsUrl) reconnectCount = 0 // 启动心跳 if (heartTimer) clearInterval(heartTimer) heartTimer = setInterval(() => { if (WSS && WSS.readyState === WebSocket.OPEN) { WSS.send('HeartBeat') } }, 5000) } /** 接收消息 */ WSS.onmessage = (event) => { console.log('收到消息:', event.data) if (event.data === 'HeartBeat' || event.data === 'Pong') return; let msg try { msg = JSON.parse(event.data) } catch (e) { console.warn('非 JSON 消息:', event.data) return } if (msg.type === 'kickOut') { ElMessage({ message: msg.content || '您的账号已在其他设备登录', type: 'warning', duration: 1500 }) localStorage.removeItem('token') localStorage.removeItem('userId') localStorage.removeItem('userType') localStorage.removeItem('companyId') if (store) store.dispatch('SET_DATA') if (router) router.push({ name: 'login' }) } } /** 错误处理 */ WSS.onerror = (err) => { console.error('WebSocket 错误:', err) } /** 连接关闭 */ WSS.onclose = () => { console.log('WebSocket 已关闭') if (heartTimer) clearInterval(heartTimer) WSS = null // 自动重连 if (!manuallyClosed) { if (reconnectCount < MAX_RECONNECT) { reconnectCount++ console.warn(`WebSocket 断开,尝试第 ${reconnectCount} 次重连...`) reconnectTimer = setTimeout(() => { connectSocket(userId, store, router) }, RECONNECT_INTERVAL) } else { console.error('达到最大重连次数,停止重连') } } } } /** 获取 WebSocket 实例 */ export function getSocket() { return WSS } /** 发送消息 */ export function sendSocketMsg(data) { if (WSS && WSS.readyState === WebSocket.OPEN) { WSS.send(data) } else { console.warn('WebSocket 未连接,尝试重连后再发送') } } /** 关闭连接 */ export function closeSocket() { manuallyClosed = true if (heartTimer) clearInterval(heartTimer) if (reconnectTimer) clearTimeout(reconnectTimer) if (WSS) { try { WSS.close() } catch { } WSS = null } }