Files
cashier-web/src/utils/websocket.ts

188 lines
5.5 KiB
TypeScript

import qs from "qs";
import { useUserStoreHook } from "@/store";
import { ElMessage, ElMessageBox } from "element-plus";
const user = useUserStoreHook();
export interface ApifoxModel {
account: string;
operate_type: string;
shop_id: string;
table_code?: string;
type: string;
[property: string]: string | number | undefined; // 限制额外属性类型
}
export type msgType = 'add' | 'reduce' | 'remove' | 'edit' | 'init' | 'cleanup' | 'del' | 'rottable' | 'batch' | 'disconnect' | 'clearOrder';
class WebSocketManager {
private client: WebSocket | null = null;
private connected: boolean = false;
private shop_id = user.userInfo.shopId ? String(user.userInfo.shopId) : '';
private autoConnect: boolean = true;
private initParams: ApifoxModel = {
type: 'manage',
account: this.shop_id || '', // 提供默认值
operate_type: 'init',
table_code: '',
shop_id: this.shop_id || '', // 提供默认值
};
private onMessage: (message: any) => void = () => { };
private messageHandlers: Map<string, ((message: string) => void)[]> = new Map();
private type: string = 'manage';
private reconnectAttempts = 0;
private maxReconnectAttempts = 10; // 自定义最大重试次数
private reconnectDelay = 5000; // 重试延迟(单位:毫秒)
private timer: any | null = null;
private reconnectTimer: any | null = null
// 初始化 WebSocket 客户端
setupWebSocket() {
const endpoint = import.meta.env.VITE_APP_WS_ENDPOINT;
if (!endpoint) {
console.warn("WebSocket 已被禁用,请在配置文件中配置 VITE_APP_WS_ENDPOINT");
return;
}
if (this.client && this.connected) {
console.log("客户端已存在并且连接正常");
return this.client;
}
const url = qs.stringify(this.initParams);
this.client = new WebSocket(endpoint + '?' + url);
this.client.onopen = () => {
this.connected = true;
console.log("WebSocket 连接已建立");
this.sendMessage(this.initParams);
this.clearTimer();
this.timer = setInterval(() => {
this.sendMessage({ type: "ping_interval", set: 'manage' });
}, 1000 * 10);
};
this.client.onclose = () => {
this.clearTimer();
this.connected = false;
console.log("WebSocket 连接已断开");
if (this.autoConnect) {
this.reconnect(); // 自动重连
}
};
this.client.onerror = (error: Event) => {
this.clearTimer();
console.error("WebSocket 发生错误:", error);
this.reconnect(); // 自动重连
};
this.client.onmessage = (event: MessageEvent) => {
try {
const message = JSON.parse(event.data);
if (message && message.msg_id) {
this.onMessageHandler({ msg_id: message.msg_id });
}
this.onMessage(message);
} catch (e) {
console.error("消息解析失败:", e);
}
};
}
// 消息回执
public onMessageHandler(data: any) {
if (this.client && this.connected) {
this.client.send(JSON.stringify({ ...data, type: 'receipt' }));
}
}
// 订阅主题
public subscribeToTopic(initParams: ApifoxModel, onMessage: (message: any) => void) {
console.log(`正在订阅主题: `, initParams);
this.initParams = { ...this.initParams, ...initParams };
this.disconnect();
this.setupWebSocket();
this.onMessage = onMessage;
this.autoConnect = true
}
public sendMessage(message: any) {
if (!this.client || !this.connected) {
// ElMessage.error('发送失败,已重新连接,请重新操作');
this.reconnect();
return;
}
if (message.operate_type == 'disconnect') {
this.disconnect();
return
}
const msg = JSON.stringify({ ...this.initParams, ...message });
try {
this.client?.send(msg);
} catch (error) {
console.error("发送消息失败:", error);
// ElMessage.error('发送失败,已重新连接,请重新操作');
this.reconnect();
}
}
public canSendMessage() {
return this.client && this.connected;
}
// 断开 WebSocket 连接
public disconnect() {
if (this.client && this.connected) {
console.log("断开 WebSocket 连接");
this.clearTimer();
this.client.close();
this.client = null;
this.connected = false;
this.autoConnect = false;
}
}
// 自动重连机制
private reconnect() {
if (!this.autoConnect) {
return;
}
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
console.log(`尝试第 ${this.reconnectAttempts} 次重连...`);
this.reconnectTimer = setTimeout(() => {
this.setupWebSocket();
}, this.reconnectDelay);
} else {
clearTimeout(this.reconnectTimer);
console.error("达到最大重连次数,停止重连");
ElMessageBox.confirm('达到最大重连次数' + this.maxReconnectAttempts + '次,已停止重连,是否立即重连?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
callback: (action: string) => {
console.log(action);
if (action == 'confirm') {
this.setupWebSocket();
this.reconnectAttempts = 0;
}
}
});
}
}
// 清除定时器
private clearTimer() {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
if (this.reconnectTimer) {
clearInterval(this.reconnectTimer);
this.reconnectTimer = null;
}
}
}
export default new WebSocketManager();