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})
|
}
|