wujianwei
2025-08-14 22976afc564c4b5b911026c6540ad48db43e2166
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
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { getToken } from './auth';
 
 
type WsCallbacks = {
  onMessage?: (data: any) => void;
  onError?: (error: Event) => void;
  onClose?: (event: CloseEvent) => void;
};
export function useWebSocket( callbacks: WsCallbacks = {},options?:{heartbeatInterval?:number;// 心跳间隔时间
    timeout?:number;// 时间
  }) {
  const {heartbeatInterval=3000,timeout=10000} = options || {};
    // 新增重连控制变量
    let isReconnecting = false;
    let activeRetries = 0;
    const maxRetries = 3;
    
  let heartbeatTimer:number|null = null;
  let lastActivity = Date.now();
  const ws = ref<WebSocket>();
  const isConnected = ref(false);
  // 心跳定时器逻辑
  const resetHeartbeat = () => {
    if (heartbeatTimer !== null) {
      clearInterval(heartbeatTimer);
    }
    heartbeatTimer = setInterval(() => {
      if (ws.value?.readyState === WebSocket.OPEN) {
         // 重置重试次数
         activeRetries = 0;
        ws.value.send(JSON.stringify({ type: 'ping' }));
        if (Date.now() - lastActivity > timeout) {
          console.log(`心跳超时(${timeout}ms),触发重连`);
          reconnect();
        }
      }
    }, heartbeatInterval) as unknown as number;
  };
  // 更新最后活跃时间
  const updateActivity = () => {
    lastActivity = Date.now();
  };
  const enhancedCallbacks = {
    ...callbacks,
    onMessage: (data: any) => {
      updateActivity();
      callbacks.onMessage?.(data);
    },
    onError: (error: Event) => {
      callbacks.onError?.(error);
      reconnect();
    }
  };
 
  // 初始化WebSocket连接
  const connect = () => {
    const token = getToken();
    const fullUrl = `/ws?token=${token}`;
    
    ws.value = new WebSocket(fullUrl);
    
    ws.value.onopen = () => {
      isConnected.value = true;
      resetHeartbeat();  // 连接成功后启动心跳
    };
// 修改WebSocket事件处理逻辑
ws.value.onmessage = (e) => {
  try {
    const response = JSON.parse(e.data);
    if (response.type === 'pong') {
      updateActivity();
      return;
    }
    enhancedCallbacks.onMessage?.(response.data); // 改用增强回调
  } catch (error:any) {
    enhancedCallbacks.onError?.(error); // 改用增强回调
  }
};
 
ws.value.onerror = (error) => {
  enhancedCallbacks.onError?.(error); // 改用增强回调
};
 
ws.value.onclose = (event) => {
  isConnected.value = false;
  enhancedCallbacks.onClose?.(event); // 改用增强回调
};
  };
  // 自动重连机制
  const reconnect = ( delay = 3000) => {
    if (!isReconnecting && activeRetries < maxRetries) {
      isReconnecting = true;
      activeRetries++;
      
      setTimeout(() => {
        if (ws.value) {
          ws.value.close(); // 先关闭旧连接
        }
        connect();
        isReconnecting = false;
      }, delay);
    }
  };
 
  onMounted(() => {
    if (!ws.value || ws.value.readyState === WebSocket.CLOSED) {
      connect();
    }
  });
 
  onBeforeUnmount(() => {
    if (heartbeatTimer) {
      clearInterval(heartbeatTimer);
    }
    if (ws.value && isConnected.value) {
      ws.value.close();
    }
  });
 
  return {
    ws,
    isConnected,
    reconnect
  };
}