feat: ✨ 字典实时同步和首页添加在线用户统计
This commit is contained in:
176
src/hooks/useWebSocketOnlineUsers.ts
Normal file
176
src/hooks/useWebSocketOnlineUsers.ts
Normal file
@@ -0,0 +1,176 @@
|
||||
import { ref, onMounted, onUnmounted, watch } from "vue";
|
||||
import { useStomp } from "./useStomp";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
export interface OnlineUserStats {
|
||||
type: string; // 事件类型
|
||||
count: number; // 当前在线用户数量
|
||||
users?: any[]; // 用户列表(可选)
|
||||
timestamp: number; // 时间戳
|
||||
}
|
||||
|
||||
/**
|
||||
* 在线用户WebSocket Hook
|
||||
* 用于订阅后端推送的在线用户数量变化
|
||||
*/
|
||||
export function useWebSocketOnlineUsers() {
|
||||
// 在线用户数量
|
||||
const onlineUserCount = ref(0);
|
||||
|
||||
// 最后更新时间戳
|
||||
const lastUpdateTime = ref(0);
|
||||
|
||||
// 连接状态
|
||||
const isConnected = ref(false);
|
||||
|
||||
// 连接正在尝试中
|
||||
const isConnecting = ref(false);
|
||||
|
||||
// 使用Stomp客户端
|
||||
const { connect, subscribe, unsubscribe, disconnect, isConnected: stompConnected } = useStomp();
|
||||
|
||||
// 订阅ID
|
||||
let subscriptionId = "";
|
||||
|
||||
// 重连次数
|
||||
let reconnectCount = 0;
|
||||
// 最大重连次数
|
||||
const maxReconnectAttempts = 5;
|
||||
// 重连计时器
|
||||
let reconnectTimer: any = null;
|
||||
|
||||
// 监听Stomp连接状态
|
||||
watch(stompConnected, (connected) => {
|
||||
if (connected && isConnecting.value) {
|
||||
isConnected.value = true;
|
||||
isConnecting.value = false;
|
||||
reconnectCount = 0;
|
||||
|
||||
// 一旦连接成功,立即订阅主题
|
||||
subscribeToOnlineUsers();
|
||||
console.log("WebSocket连接成功,已订阅在线用户主题");
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 订阅在线用户主题
|
||||
*/
|
||||
const subscribeToOnlineUsers = () => {
|
||||
if (!stompConnected.value) return;
|
||||
|
||||
// 如果已经订阅,先取消订阅
|
||||
if (subscriptionId) {
|
||||
unsubscribe(subscriptionId);
|
||||
}
|
||||
|
||||
// 订阅在线用户主题
|
||||
subscriptionId = subscribe("/topic/online-users", (message) => {
|
||||
try {
|
||||
const data: OnlineUserStats = JSON.parse(message.body);
|
||||
|
||||
// 只有在消息类型为ONLINE_USERS_CHANGE时更新数据
|
||||
if (data.type === "ONLINE_USERS_CHANGE") {
|
||||
onlineUserCount.value = data.count || 0;
|
||||
lastUpdateTime.value = data.timestamp || Date.now();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("解析在线用户数据失败:", error);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 初始化WebSocket连接并订阅在线用户主题
|
||||
*/
|
||||
const initWebSocket = () => {
|
||||
if (isConnecting.value) return;
|
||||
|
||||
isConnecting.value = true;
|
||||
|
||||
// 连接WebSocket
|
||||
connect();
|
||||
|
||||
// 设置连接超时
|
||||
const connectionTimeout = setTimeout(() => {
|
||||
if (!isConnected.value) {
|
||||
console.warn("WebSocket连接超时,尝试重连");
|
||||
attemptReconnect();
|
||||
}
|
||||
}, 5000);
|
||||
|
||||
// 监听连接状态变化,连接成功后清除超时计时器
|
||||
const unwatch = watch(stompConnected, (connected) => {
|
||||
if (connected) {
|
||||
clearTimeout(connectionTimeout);
|
||||
unwatch();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 尝试重新连接
|
||||
*/
|
||||
const attemptReconnect = () => {
|
||||
if (reconnectCount >= maxReconnectAttempts) {
|
||||
console.error(`已达到最大重连次数(${maxReconnectAttempts}),停止重连`);
|
||||
isConnecting.value = false;
|
||||
ElMessage.error("WebSocket连接失败,请稍后刷新页面重试");
|
||||
return;
|
||||
}
|
||||
|
||||
reconnectCount++;
|
||||
console.log(`尝试重连(${reconnectCount}/${maxReconnectAttempts})...`);
|
||||
|
||||
// 使用指数退避策略增加重连间隔
|
||||
const delay = Math.min(1000 * Math.pow(2, reconnectCount), 30000);
|
||||
|
||||
// 清除之前的计时器
|
||||
if (reconnectTimer) {
|
||||
clearTimeout(reconnectTimer);
|
||||
}
|
||||
|
||||
// 设置重连计时器
|
||||
reconnectTimer = setTimeout(() => {
|
||||
connect();
|
||||
}, delay);
|
||||
};
|
||||
|
||||
/**
|
||||
* 关闭WebSocket连接
|
||||
*/
|
||||
const closeWebSocket = () => {
|
||||
if (subscriptionId) {
|
||||
unsubscribe(subscriptionId);
|
||||
subscriptionId = "";
|
||||
}
|
||||
|
||||
// 清除重连计时器
|
||||
if (reconnectTimer) {
|
||||
clearTimeout(reconnectTimer);
|
||||
reconnectTimer = null;
|
||||
}
|
||||
|
||||
disconnect();
|
||||
isConnected.value = false;
|
||||
isConnecting.value = false;
|
||||
};
|
||||
|
||||
// 组件挂载时初始化WebSocket
|
||||
onMounted(() => {
|
||||
initWebSocket();
|
||||
});
|
||||
|
||||
// 组件卸载时关闭WebSocket
|
||||
onUnmounted(() => {
|
||||
closeWebSocket();
|
||||
});
|
||||
|
||||
return {
|
||||
onlineUserCount,
|
||||
lastUpdateTime,
|
||||
isConnected,
|
||||
isConnecting,
|
||||
initWebSocket,
|
||||
closeWebSocket,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user