97 lines
2.5 KiB
TypeScript
97 lines
2.5 KiB
TypeScript
// useGlobalWebSocket.ts
|
|
import { ref } from 'vue';
|
|
import { ElMessage } from 'element-plus';
|
|
|
|
const websocket = ref<WebSocket | null>(null);
|
|
const isWebSocketConnected = ref(false);
|
|
let heartbeatInterval: number | null = null;
|
|
const rememberedAddress = localStorage.getItem('rememberedAddress') || '127.0.0.1';
|
|
|
|
// 连接 WebSocket
|
|
const connectWebSocket = () => {
|
|
websocket.value = new WebSocket(`ws://${rememberedAddress}:8080/ws/event`);
|
|
websocket.value.onopen = () => {
|
|
ElMessage.success('全局 WebSocket 连接成功');
|
|
isWebSocketConnected.value = true;
|
|
startHeartbeat();
|
|
};
|
|
websocket.value.onmessage = (event) => {
|
|
showNotification(event.data);
|
|
};
|
|
websocket.value.onclose = handleClose;
|
|
websocket.value.onerror = handleError;
|
|
};
|
|
|
|
// 关闭 WebSocket
|
|
const closeWebSocket = () => {
|
|
if (websocket.value) {
|
|
websocket.value.close();
|
|
ElMessage.info('全局 WebSocket 已关闭');
|
|
stopHeartbeat();
|
|
isWebSocketConnected.value = false;
|
|
}
|
|
};
|
|
|
|
// 心跳检测
|
|
const startHeartbeat = () => {
|
|
if (heartbeatInterval) return;
|
|
heartbeatInterval = window.setInterval(() => {
|
|
if (websocket.value && websocket.value.readyState === WebSocket.OPEN) {
|
|
websocket.value.send('ping');
|
|
}
|
|
}, 5000);
|
|
};
|
|
|
|
const stopHeartbeat = () => {
|
|
if (heartbeatInterval) {
|
|
clearInterval(heartbeatInterval);
|
|
heartbeatInterval = null;
|
|
}
|
|
};
|
|
|
|
// 处理连接关闭
|
|
const handleClose = () => {
|
|
ElMessage.warning('WebSocket 连接已关闭');
|
|
isWebSocketConnected.value = false;
|
|
stopHeartbeat();
|
|
localStorage.setItem('isPopupEnabled', 'False');
|
|
};
|
|
|
|
const handleError = () => {
|
|
ElMessage.error('WebSocket 连接出错');
|
|
isWebSocketConnected.value = false;
|
|
stopHeartbeat();
|
|
};
|
|
|
|
// 显示通知
|
|
const showNotification = (message: string) => {
|
|
if (Notification.permission === 'granted') {
|
|
new Notification('新消息', {
|
|
body: message,
|
|
icon: '/path/to/icon.png',
|
|
});
|
|
} else if (Notification.permission !== 'denied') {
|
|
Notification.requestPermission().then((permission) => {
|
|
if (permission === 'granted') {
|
|
new Notification('新消息', {
|
|
body: message,
|
|
icon: '/path/to/icon.png',
|
|
});
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
// 导出类型和方法
|
|
export interface GlobalWebSocket {
|
|
connectWebSocket: () => void;
|
|
closeWebSocket: () => void;
|
|
isWebSocketConnected: typeof isWebSocketConnected;
|
|
}
|
|
|
|
export const useGlobalWebSocket = (): GlobalWebSocket => ({
|
|
connectWebSocket,
|
|
closeWebSocket,
|
|
isWebSocketConnected,
|
|
});
|