罗广辉
2026-06-18 44dd9c4eb8a2489c63a5eb53fd4254bbb3510e95
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
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})
}