import {
|
CommonUtils
|
} from "@/utils/common.js";
|
|
class WebSocketServices {
|
constructor() {
|
this.wsInstance = null; // WebSocket 实例
|
this.isConnecting = false; // 连接中状态(避免并发重连)
|
this.isConnected = false; // 已连接状态
|
this.isReconnectStopped = false; // 停止重连标记
|
this.wsUrl = CommonUtils.httpFormatWs(); // WebSocket 基础地址
|
|
// 超时校验配置
|
this.businessMessageInterval = 5 * 60 * 1000;
|
this.noMessageTimeout = this.businessMessageInterval + 2 * 60 * 1000;
|
this.noMessageTimer = null; // 无消息超时定时器
|
|
// 监听函数引用
|
this.openListener = null;
|
this.messageListener = null;
|
this.closeListener = null;
|
this.errorListener = null;
|
|
// 缓存用户信息
|
this.currentUserId = "";
|
this.currentUserName = "";
|
}
|
|
/**
|
* 建立 WebSocket 连接
|
* @param {string/number} userId - 用户ID(必填)
|
* @param {string} userName - 用户名(必填)
|
* @param {number} count - 当前重连次数
|
* @param {number} limit - 最大重连次数(默认3次)
|
*/
|
createConnect(userId, userName, count = 0, limit = 3) {
|
// 登录建立连接时,需要重新获取http地址,可能会变更
|
this.wsUrl = CommonUtils.httpFormatWs();
|
// 缓存用户信息(用于重连)
|
this.currentUserId = userId;
|
this.currentUserName = userName;
|
|
// 前置校验:避免无效连接和并发重连
|
if (this.isConnecting || this.isConnected) return;
|
if (!userId && userId !== 0) { // 兼容 userId 为 0 的合法场景
|
CommonUtils.showTips({
|
message: "用户标识不能为空,无法建立WebSocket连接"
|
});
|
return;
|
}
|
if (count > limit) {
|
CommonUtils.showTips({
|
message: `WebSocket 重连次数超出最大限制(${limit}次),已停止重连`,
|
});
|
this.isReconnectStopped = true;
|
return;
|
}
|
|
console.log(`[WebSocket] 开始建立连接(第 ${count || 0} 次)`, {
|
wsUrl: this.wsUrl,
|
userId,
|
userName,
|
});
|
|
// 清除历史残留:监听+定时器
|
this.clearAllListeners();
|
this.clearNoMessageTimer();
|
|
// 发起连接
|
this.isConnecting = true;
|
this.wsInstance = uni.connectSocket({
|
url: `${this.wsUrl}?userId=${encodeURIComponent(userId)}&userName=${encodeURIComponent(userName)}`,
|
fail: (error) => {
|
console.error("[WebSocket] 连接发起失败", error);
|
this.isConnecting = false;
|
this.triggerReconnect(count);
|
},
|
});
|
|
// 监听连接成功:启动无消息超时校验
|
this.openListener = uni.onSocketOpen((res) => {
|
console.log("[WebSocket] 连接建立成功", res);
|
this.isConnecting = false;
|
this.isConnected = true;
|
this.isReconnectStopped = false;
|
this.startNoMessageCheck();
|
count = 0;
|
});
|
|
this.messageListener = uni.onSocketMessage((res) => {
|
try {
|
const message = JSON.parse(res.data);
|
console.log("[WebSocket] 收到业务消息", message);
|
|
// 重置无消息定时器(有业务消息=连接正常)
|
this.resetNoMessageTimer();
|
|
// 处理业务消息
|
if (message.Type === "MessageUnRead") { // 未读消息
|
let payload = {
|
pagePath: "/pages/ZLGL/OA_WorkLink/OA_WorkLinkBillList",
|
itemId: 0
|
}
|
const content = JSON.parse(message.Content);
|
this.showTaskTip(`您有${content.length}条消息需要处理!`, payload);
|
// this.emit("message", content); // 支持外部监听
|
} else if (message.Type === "Message") {
|
const content = JSON.parse(message.Content)
|
let payload = {
|
pagePath: "/pages/ZLGL/OA_WorkLink/OA_WorkLinkBillList",
|
itemId: 0
|
}
|
this.showTaskTip(content[0]["内容"], payload, content[0]["主题"]);
|
|
}
|
} catch (error) {
|
console.error("[WebSocket] 消息解析失败", error, res.data);
|
}
|
});
|
|
// 监听连接关闭:仅异常关闭触发重连
|
this.closeListener = uni.onSocketClose((res) => {
|
console.log("[WebSocket] 连接关闭", res);
|
this.isConnecting = false;
|
this.isConnected = false;
|
this.clearNoMessageTimer();
|
|
// 正常关闭(code=1000)或主动停止重连时,不重连
|
if (!this.isReconnectStopped && res.code !== 1000) {
|
this.triggerReconnect(count);
|
}
|
});
|
|
// 监听连接错误:触发重连
|
this.errorListener = uni.onSocketError((error) => {
|
console.error("[WebSocket] 连接错误", error);
|
this.isConnecting = false;
|
this.clearNoMessageTimer();
|
if (!this.isReconnectStopped) {
|
this.triggerReconnect(count);
|
}
|
});
|
}
|
|
/**
|
* 统一触发重连(延迟3秒)
|
* @param {number} count - 当前重连次数
|
*/
|
triggerReconnect(count) {
|
console.log(`[WebSocket] 准备第 ${count + 1} 次重连`);
|
setTimeout(() => {
|
this.createConnect(this.currentUserId, this.currentUserName, count + 1);
|
}, 3000);
|
}
|
|
/**
|
* 启动“无业务消息”超时校验
|
*/
|
startNoMessageCheck() {
|
this.clearNoMessageTimer();
|
this.noMessageTimer = setTimeout(() => {
|
console.warn("[WebSocket] 7分钟未收到业务消息,判定连接失效,主动重连");
|
this.closeSocket();
|
this.createConnect(this.currentUserId, this.currentUserName);
|
}, this.noMessageTimeout);
|
}
|
|
/**
|
* 收到业务消息后,重置无消息定时器
|
*/
|
resetNoMessageTimer() {
|
this.startNoMessageCheck();
|
}
|
|
/**
|
* 清除无消息定时器
|
*/
|
clearNoMessageTimer() {
|
if (this.noMessageTimer) {
|
clearTimeout(this.noMessageTimer);
|
this.noMessageTimer = null;
|
}
|
}
|
|
/**
|
* 清除所有 Socket 监听
|
*/
|
clearAllListeners() {
|
if (this.openListener) {
|
uni.offSocketOpen(this.openListener);
|
this.openListener = null;
|
}
|
if (this.messageListener) {
|
uni.offSocketMessage(this.messageListener);
|
this.messageListener = null;
|
}
|
if (this.closeListener) {
|
uni.offSocketClose(this.closeListener);
|
this.closeListener = null;
|
}
|
if (this.errorListener) {
|
uni.offSocketError(this.errorListener);
|
this.errorListener = null;
|
}
|
}
|
|
/**
|
* 主动关闭 WebSocket 连接 (登出时关闭WebSocket连接)
|
*/
|
closeSocket() {
|
this.isReconnectStopped = true;
|
this.clearAllListeners();
|
this.clearNoMessageTimer();
|
|
if (this.wsInstance) {
|
uni.closeSocket({
|
success: () => console.log("[WebSocket] 主动关闭连接成功"),
|
fail: (error) => console.error("[WebSocket] 主动关闭连接失败", error),
|
});
|
this.wsInstance = null;
|
}
|
|
this.isConnected = false;
|
this.isConnecting = false;
|
}
|
|
|
showTaskTip(Content, payloads, Title = "重要通知") {
|
// #ifdef APP-PLUS || APP
|
let content = Content;
|
let options = {
|
title: Title,
|
cover: true, // 是否覆盖上一次的通知
|
when: new Date(), // 通知显示时间
|
icon: "../static/logo.png",
|
largeIcon: "../static/logo.png"
|
};
|
// TODO 跳转到指定页
|
let payload = JSON.stringify(payloads);
|
console.log('payload: ', payload);
|
|
plus.push.createMessage(content, payload, options);
|
// #endif
|
}
|
}
|
|
export default new WebSocketServices()
|