391 lines
11 KiB
JavaScript
Raw Normal View History

2025-06-06 03:08:19 +08:00
import store from '@/config/store';
import base from '@/config/baseUrl';
class IMWebSocket {
constructor() {
this.socketUrl = base.socketUrl || "ws://q.sjqqzc.top:8586";
this.socket = null;
this.isConnected = false;
this.reconnectCount = 0;
this.maxReconnectCount = 5;
this.reconnectTimer = null;
this.heartbeatTimer = null;
this.messageHandlers = new Set();
// 存储联系人列表
this.contactList = new Map(); // key: contact_id, value: contact_info
// 存储未读消息数
this.unreadCount = new Map(); // key: contact_id, value: unread_count
// 存储最后一条消息
this.lastMessage = new Map(); // key: contact_id, value: last_message
// 绑定方法到实例
this.connect = this.connect.bind(this);
this.disconnect = this.disconnect.bind(this);
this.reconnect = this.reconnect.bind(this);
this.send = this.send.bind(this);
this.startHeartbeat = this.startHeartbeat.bind(this);
this.stopHeartbeat = this.stopHeartbeat.bind(this);
}
// 初始化连接
init() {
if (!this.socketUrl) {
console.warn('WebSocket URL not configured');
return;
}
this.connect();
}
// 建立连接
connect() {
if (this.socket) {
this.disconnect();
}
this.socket = uni.connectSocket({
url: this.socketUrl,
success: () => {
console.log('WebSocket连接创建成功');
},
fail: (err) => {
console.error('WebSocket连接创建失败:', err);
this.reconnect();
}
});
// 监听连接打开
uni.onSocketOpen(() => {
console.log('WebSocket连接已打开');
this.isConnected = true;
this.reconnectCount = 0;
this.sendAuth();
this.startHeartbeat();
});
// 监听消息
uni.onSocketMessage((res) => {
try {
const message = JSON.parse(res.data);
this.handleMessage(message);
} catch (e) {
console.error('消息解析错误:', e);
}
});
// 监听连接关闭
uni.onSocketClose(() => {
console.log('WebSocket连接已关闭');
this.isConnected = false;
this.stopHeartbeat();
this.reconnect();
});
// 监听错误
uni.onSocketError((err) => {
console.error('WebSocket错误:', err);
this.isConnected = false;
this.reconnect();
});
}
// 断开连接
disconnect() {
this.stopHeartbeat();
if (this.socket) {
uni.closeSocket();
this.socket = null;
}
this.isConnected = false;
}
// 重连机制
reconnect() {
if (this.reconnectCount >= this.maxReconnectCount) {
console.log('达到最大重连次数');
return;
}
if (this.reconnectTimer) {
clearTimeout(this.reconnectTimer);
}
this.reconnectTimer = setTimeout(() => {
this.reconnectCount++;
console.log(`${this.reconnectCount}次重连`);
this.connect();
}, 3000);
}
// 发送认证信息
sendAuth() {
if (store.state.userInfo.token) {
this.send({
type: 'auth',
token: store.state.userInfo.token
});
}
}
// 发送消息
send(data) {
if (!this.isConnected) {
console.warn('WebSocket未连接');
return false;
}
if (typeof data === 'object') {
data = JSON.stringify(data);
}
return new Promise((resolve, reject) => {
uni.sendSocketMessage({
data,
success: () => resolve(true),
fail: (err) => {
console.error('发送消息失败:', err);
reject(err);
}
});
});
}
// 启动心跳
startHeartbeat() {
this.stopHeartbeat();
this.heartbeatTimer = setInterval(() => {
this.send({ type: 'ping' }).catch(() => {
this.reconnect();
});
}, 30000);
}
// 停止心跳
stopHeartbeat() {
if (this.heartbeatTimer) {
clearInterval(this.heartbeatTimer);
this.heartbeatTimer = null;
}
}
// 处理接收到的消息
handleMessage(message) {
if(!message.type || message.type == "ok" || message.type == "pong"){
return ;
}
console.log(message)
// 更新联系人列表
this.updateContactList(message);
// 更新未读消息数
this.updateUnreadCount(message);
// 更新最后一条消息
this.updateLastMessage(message);
// 发送通知
this.sendNotification(message);
// 通知所有注册的消息处理器
this.messageHandlers.forEach(handler => {
try {
handler(message);
} catch (e) {
console.error('消息处理错误:', e);
}
});
}
// 更新联系人列表
async updateContactList(message) {
const contactId = message.from_user.uid;
const contactType = message.target_type;
const contactKey = `${contactType}_${contactId}`;
// 如果联系人不在列表中,获取联系人信息
if (!this.contactList.has(contactKey)) {
try {
const res = await uni.$http.get('/api/chat/contact_info', {
contact_id: contactId,
contact_type: contactType
});
if (res.data) {
this.contactList.set(contactKey, {
...res.data,
type: contactType,
id: contactId
});
// 触发联系人列表更新事件
this.emitContactListUpdate();
}
} catch (error) {
console.error('获取联系人信息失败:', error);
}
}
}
// 更新未读消息数
updateUnreadCount(message) {
const contactId = message.from_user.id;
const contactType = message.target_type;
const contactKey = `${contactType}_${contactId}`;
// 如果当前不在聊天页面,增加未读数
const currentPage = getCurrentPages();
const isInChatPage = currentPage.some(page =>
page.route === 'pages/im/chat' &&
page.$page.options.target_id === contactId+'' &&
page.$page.options.target_type === contactType
);
console.warn(isInChatPage);
if (!isInChatPage) {
const currentCount = this.unreadCount.get(contactKey) || 0;
this.unreadCount.set(contactKey, currentCount + 1);
// 触发未读消息更新事件
this.emitUnreadCountUpdate();
}
}
// 更新最后一条消息
updateLastMessage(message) {
const contactId = message.from_user.uid;
const contactType = message.target_type;
const contactKey = `${contactType}_${contactId}`;
this.lastMessage.set(contactKey, {
content: message.content,
type: message.type,
create_time: message.create_time
});
// 触发最后消息更新事件
this.emitLastMessageUpdate();
}
// 发送通知
sendNotification(message) {
// #ifdef APP-PLUS
const currentPage = getCurrentPages();
const isInChatPage = currentPage.some(page =>
page.route === 'pages/im/chat' &&
page.$page.options.target_id === message.from_user.uid.toString() &&
page.$page.options.target_type === message.target_type
);
// 如果不在聊天页面,发送通知
if (!isInChatPage) {
const contact = this.contactList.get(`${message.target_type}_${message.from_user.uid}`);
const title = contact ? contact.username : '新消息';
let content = '';
// 根据消息类型设置通知内容
switch (message.type) {
case 'text':
content = message.content;
break;
case 'image':
content = '[图片]';
break;
default:
content = '[新消息]';
}
// 创建通知
plus.push.createMessage(content, {
title: title,
payload: {
type: 'chat',
target_id: message.from_user.uid,
target_type: message.target_type
}
}, {
sound: 'system',
cover: true
});
}
// #endif
}
// 获取联系人列表
getContactList() {
return Array.from(this.contactList.values());
}
// 获取未读消息数
getUnreadCount(contactId, contactType) {
return this.unreadCount.get(`${contactType}_${contactId}`) || 0;
}
// 获取最后一条消息
getLastMessage(contactId, contactType) {
return this.lastMessage.get(`${contactType}_${contactId}`);
}
// 清除未读消息数
clearUnreadCount(contactId, contactType) {
const contactKey = `${contactType}_${contactId}`;
this.unreadCount.delete(contactKey);
this.emitUnreadCountUpdate();
}
// 事件发射器
emitContactListUpdate() {
uni.$emit('im:contactListUpdate', this.getContactList());
}
emitUnreadCountUpdate() {
uni.$emit('im:unreadCountUpdate', Object.fromEntries(this.unreadCount));
}
emitLastMessageUpdate() {
uni.$emit('im:lastMessageUpdate', Object.fromEntries(this.lastMessage));
}
// 注册联系人列表更新监听
onContactListUpdate(callback) {
uni.$on('im:contactListUpdate', callback);
}
// 注册未读消息数更新监听
onUnreadCountUpdate(callback) {
uni.$on('im:unreadCountUpdate', callback);
}
// 注册最后消息更新监听
onLastMessageUpdate(callback) {
uni.$on('im:lastMessageUpdate', callback);
}
// 移除监听器
offContactListUpdate(callback) {
uni.$off('im:contactListUpdate', callback);
}
offUnreadCountUpdate(callback) {
uni.$off('im:unreadCountUpdate', callback);
}
offLastMessageUpdate(callback) {
uni.$off('im:lastMessageUpdate', callback);
}
// 注册消息处理器
onMessage(handler) {
if (typeof handler === 'function') {
this.messageHandlers.add(handler);
}
}
// 移除消息处理器
offMessage(handler) {
this.messageHandlers.delete(handler);
}
}
// 创建单例
const im = new IMWebSocket();
export default im;