feat: add web application

This commit is contained in:
richjohnrambo
2026-10-10 20:55:59 +08:00
parent 3eb5d78875
commit 50fcfd2d3d
571 changed files with 73992 additions and 135 deletions
+188
View File
@@ -0,0 +1,188 @@
import { SocketEnum } from '@/enums/socketEnum';
import { useUserStoreWidthOut } from '@/store/modules/user';
import { isJsonString } from '@/utils/is';
import { registerGlobalMessage } from '@/utils/websocket/registerMessage';
// WebSocket消息格式
export interface WebSocketMessage {
event: string;
data: any;
code: number;
timestamp: number;
}
let socket: WebSocket;
let isActive: boolean;
const messageHandler: Map<string, Function> = new Map();
export default () => {
const heartCheck = {
timeout: 5000,
timeoutObj: setTimeout(() => {}),
serverTimeoutObj: setInterval(() => {}),
reset: function () {
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
return this;
},
start: function () {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const self = this;
clearTimeout(this.timeoutObj);
clearTimeout(this.serverTimeoutObj);
this.timeoutObj = setTimeout(function () {
socket.send(
JSON.stringify({
event: SocketEnum.EventPing,
})
);
self.serverTimeoutObj = setTimeout(function () {
console.log('[WebSocket] 关闭服务');
socket.close();
}, self.timeout);
}, this.timeout);
},
};
const useUserStore = useUserStoreWidthOut();
let lockReconnect = false;
let timer: ReturnType<typeof setTimeout>;
const createSocket = () => {
console.log('[WebSocket] createSocket...');
if (useUserStore.token === '' || useUserStore.config?.wsAddr == '') {
console.error('[WebSocket] 用户未登录,稍后重试...');
resetReconnect();
return;
}
try {
socket = new WebSocket(`${useUserStore.config?.wsAddr}?authorization=${useUserStore.token}`);
init();
if (lockReconnect) {
lockReconnect = false;
}
} catch (e) {
console.error(`[WebSocket] createSocket err: ${e}`);
resetReconnect();
return;
}
};
const resetReconnect = () => {
if (lockReconnect) {
lockReconnect = false;
}
reconnect();
};
const reconnect = () => {
console.log('[WebSocket] lockReconnect:' + lockReconnect);
if (lockReconnect) return;
lockReconnect = true;
clearTimeout(timer);
timer = setTimeout(() => {
createSocket();
}, 1000 * 10);
};
const init = () => {
socket.onopen = function (_) {
console.log('[WebSocket] 已连接');
heartCheck.reset().start();
isActive = true;
};
socket.onmessage = function (event) {
isActive = true;
// console.log('WebSocket:收到一条消息', event.data);
if (!isJsonString(event.data)) {
console.log('[WebSocket] message incorrect format:' + JSON.stringify(event));
return;
}
heartCheck.reset().start();
const message = JSON.parse(event.data) as WebSocketMessage;
onMessage(message);
};
socket.onerror = function (_) {
console.log('[WebSocket] 发生错误');
reconnect();
isActive = false;
};
socket.onclose = function (_) {
console.log('[WebSocket] 已关闭');
heartCheck.reset();
reconnect();
isActive = false;
};
window.onbeforeunload = function () {
socket.close();
isActive = false;
};
};
createSocket();
registerGlobalMessage();
};
function onMessage(message: WebSocketMessage) {
let handled = false;
messageHandler.forEach((value: Function, key: string) => {
if (message.event === key || key === '*') {
handled = true;
value.call(null, message);
}
});
if (!handled) {
console.log('[WebSocket] messageHandler not registered. message:' + JSON.stringify(message));
}
}
// 发送消息
export function sendMsg(event: string, data: any = null, isRetry = true) {
if (socket === undefined || !isActive) {
if (!isRetry) {
console.log('[WebSocket] 连接异常,发送失败!');
return;
}
console.log('[WebSocket] 连接异常,等待重试..');
setTimeout(() => {
sendMsg(event, data);
}, 200);
return;
}
try {
socket.send(JSON.stringify({ event, data }));
} catch (err: any) {
console.log('[WebSocket] 发送消息失败,err:', err.message);
if (!isRetry) {
return;
}
console.log('[WebSocket] 等待重试..');
setTimeout(() => {
sendMsg(event, data);
}, 100);
}
}
// 添加消息处理
export function addOnMessage(key: string, value: Function): void {
messageHandler.set(key, value);
}
// 移除消息处理
export function removeOnMessage(key: string): boolean {
return messageHandler.delete(key);
}
// 查看所有消息处理
export function getAllOnMessage(): Map<string, Function> {
return messageHandler;
}
@@ -0,0 +1,32 @@
import { TABS_ROUTES } from '@/store/mutation-types';
import { SocketEnum } from '@/enums/socketEnum';
import { useUserStoreWidthOut } from '@/store/modules/user';
import { notificationStoreWidthOut } from '@/store/modules/notification';
import { addOnMessage, WebSocketMessage } from '@/utils/websocket/index';
// 注册全局消息监听
export function registerGlobalMessage() {
// 心跳
addOnMessage(SocketEnum.EventPing, function (_message: WebSocketMessage) {
// console.log('ping..');
});
// 强制退出
addOnMessage(SocketEnum.EventKick, function (_message: WebSocketMessage) {
const useUserStore = useUserStoreWidthOut();
useUserStore.logout().then(() => {
// 移除标签页
localStorage.removeItem(TABS_ROUTES);
location.reload();
});
});
// 消息通知
addOnMessage(SocketEnum.EventNotice, function (message: WebSocketMessage) {
const notificationStore = notificationStoreWidthOut();
notificationStore.triggerNewMessages(message.data);
});
// 更多全局消息处理都可以在这里注册
// ...
}