import {useUserStore} from "@/store/index.js"; import {getEnvObj} from "@/utils/index.js"; import useAppStore from "../store/modules/app/index.js"; let socketTask = null let heartbeatTimer = null // SocketTask 没有稳定的 readyState,这里用事件维护连接状态。 let isSocketOpen = false const HEARTBEAT_INTERVAL = 30000 export function useGlobalWS() { const userStore = useUserStore(); const appStore = useAppStore(); const userId = computed(() => userStore?.userInfo?.user_id) const access_token = computed(() => userStore?.userInfo?.access_token) const {VITE_APP_WS_API_URL} = getEnvObj() // 后端正常业务消息是 JSON;心跳或异常数据不应该中断消息监听。 function parseSocketMessage(data) { try { return JSON.parse(data) } catch (err) { console.warn('ws消息解析失败:', data) return null } } // 心跳响应只用于保活,不进入业务刷新/退出登录逻辑。 function isHeartbeatMessage(payload) { return payload?.type === 'pong' || payload?.type === 'ping' } // 消息处理 function messageHandler(payload) { if (!payload || isHeartbeatMessage(payload)) return switch (payload.biz_code) { case 'JOB_ISREFRESH': appStore.setJobUpdateKeyAdd() break case 'DEVICE_ISREFRESH': appStore.setDeviceUpdateKeyAdd() break case 'DOWNLOAD_PROGRESS': break case 'LOGOUT_USER': userStore.setUserInfo(null) uni.reLaunch({ url: '/pages/login/index' }) break default: break; } } // 关闭ws function closeWS() { stopHeartbeat() isSocketOpen = false const currentSocketTask = socketTask socketTask = null currentSocketTask?.close({ success: () => { console.log('ws关闭连接'); }, }) } // 初始化ws function initWS() { // 关闭,再连接ws closeWS() if (!access_token.value) return const url = VITE_APP_WS_API_URL + `?x-auth-token=${encodeURI(access_token?.value)}` + `&model_type=3&workspace-id=${userId.value}` // 创建连接 const currentSocketTask = uni.connectSocket({ url: url, success: () => { console.log('ws连接成功'); }, fail: (err) => { console.error('ws连接失败:', err); } }); socketTask = currentSocketTask // 消息监听 currentSocketTask.onMessage((result) => { // 旧连接的异步回调可能晚于新连接触发,忽略旧实例事件。 if (socketTask !== currentSocketTask) return messageHandler(parseSocketMessage(result.data)) }) //================================== // 监听连接打开 currentSocketTask.onOpen(() => { // 连接成功后才启动心跳,避免连接中/已关闭时发送失败。 if (socketTask !== currentSocketTask) return console.log('✅ WebSocket连接已建立') isSocketOpen = true // reconnectAttempts = 0 // 连接成功后重置重连次数 // 可以在这里发送心跳或订阅消息 startHeartbeat() }) // 监听连接关闭 currentSocketTask.onClose((res) => { // 关闭后必须停掉心跳,否则定时器会持续发送到失效连接。 if (socketTask !== currentSocketTask) return console.log(`WebSocket连接关闭,代码: ${res.code}, 原因: ${res.reason}`) isSocketOpen = false stopHeartbeat() // 根据不同的关闭代码处理 if (res.code === 1000) { // 正常关闭 console.log('连接正常关闭') } else if (res.code === 1006) { // 异常关闭 console.log('连接异常关闭,尝试重连...') } else if (res.code === 1011) { // 服务器内部错误 console.log('服务器内部错误(1011),延迟重连...') } else { console.log('其他原因关闭,尝试重连...') } }) // 监听错误 currentSocketTask.onError((err) => { if (socketTask !== currentSocketTask) return console.error('WebSocket发生错误:', err) isSocketOpen = false stopHeartbeat() }) } function startHeartbeat() { stopHeartbeat() heartbeatTimer = setInterval(() => { if (socketTask && isSocketOpen) { // 保持和 PC 端一致,按 JSON ping 包保活。 socketTask.send({ data: JSON.stringify({ type: 'ping', timestamp: Date.now() }), fail: (err) => { console.error('ws心跳发送失败:', err) isSocketOpen = false stopHeartbeat() } }); } }, HEARTBEAT_INTERVAL) } function stopHeartbeat() { if (heartbeatTimer) { clearInterval(heartbeatTimer) heartbeatTimer = null } } watch(access_token, initWS, {immediate: true}) }