完成AI问答模块

This commit is contained in:
2025-07-08 21:42:38 +08:00
parent 38f67616fc
commit 9f8f113e43
35 changed files with 1563 additions and 146 deletions

176
src/utils/websocket.ts Normal file
View File

@@ -0,0 +1,176 @@
/**
* WebSocket连接管理类
*/
export class WebSocketManager {
private ws: WebSocket | null = null;
private url: string;
private reconnectAttempts = 0;
private maxReconnectAttempts = 5;
private reconnectInterval = 3000;
private heartbeatInterval: NodeJS.Timeout | null = null;
private heartbeatTimer = 30000; // 30秒心跳
// 事件回调
private onMessageCallback?: (data: any) => void;
private onOpenCallback?: () => void;
private onCloseCallback?: () => void;
private onErrorCallback?: (error: Event) => void;
constructor(url: string) {
this.url = url;
}
/**
* 连接WebSocket
*/
connect(): Promise<void> {
return new Promise((resolve, reject) => {
try {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
console.log('WebSocket连接成功');
this.reconnectAttempts = 0;
this.startHeartbeat();
this.onOpenCallback?.();
resolve();
};
this.ws.onmessage = (event) => {
console.log(event,'event>>>')
try {
const data = JSON.parse(event.data);
this.onMessageCallback?.(data);
} catch (error) {
console.error('解析WebSocket消息失败:', error);
}
};
this.ws.onclose = () => {
console.log('WebSocket连接关闭');
this.stopHeartbeat();
this.onCloseCallback?.();
this.handleReconnect();
};
this.ws.onerror = (error) => {
console.error('WebSocket连接错误:', error);
this.onErrorCallback?.(error);
reject(error);
};
} catch (error) {
reject(error);
}
});
}
/**
* 发送消息
*/
send(message: any): void {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(typeof message === 'string' ? message : JSON.stringify(message));
} else {
console.warn('WebSocket未连接无法发送消息');
}
}
/**
* 关闭连接
*/
close(): void {
this.stopHeartbeat();
if (this.ws) {
this.ws.close();
this.ws = null;
}
}
/**
* 重连处理
*/
private handleReconnect(): void {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
console.log(`尝试重连WebSocket (${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
setTimeout(() => {
this.connect().catch(error => {
console.error('重连失败:', error);
});
}, this.reconnectInterval);
} else {
console.error('WebSocket重连次数已达上限');
}
}
/**
* 开始心跳
*/
private startHeartbeat(): void {
this.heartbeatInterval = setInterval(() => {
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify({ type: 'ping' }));
}
}, this.heartbeatTimer);
}
/**
* 停止心跳
*/
private stopHeartbeat(): void {
if (this.heartbeatInterval) {
clearInterval(this.heartbeatInterval);
this.heartbeatInterval = null;
}
}
/**
* 设置消息回调
*/
onMessage(callback: (data: any) => void): void {
this.onMessageCallback = callback;
}
/**
* 设置连接成功回调
*/
onOpen(callback: () => void): void {
this.onOpenCallback = callback;
}
/**
* 设置连接关闭回调
*/
onClose(callback: () => void): void {
this.onCloseCallback = callback;
}
/**
* 设置错误回调
*/
onError(callback: (error: Event) => void): void {
this.onErrorCallback = callback;
}
/**
* 获取连接状态
*/
getReadyState(): number {
return this.ws?.readyState ?? WebSocket.CLOSED;
}
/**
* 是否已连接
*/
isConnected(): boolean {
return this.ws?.readyState === WebSocket.OPEN;
}
}
/**
* 创建WebSocket连接
*/
export function createWebSocket(url: string): WebSocketManager {
return new WebSocketManager(url);
}