|
@@ -29,24 +29,17 @@ class TIMPresenceManager {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 初始化并连接
|
|
|
|
|
- * @param {String} userId 当前用户ID
|
|
|
|
|
|
|
+ * 初始化
|
|
|
*/
|
|
*/
|
|
|
async init(userId) {
|
|
async init(userId) {
|
|
|
- if (this.isConnected || !userId) {
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
this.userId = userId;
|
|
this.userId = userId;
|
|
|
|
|
|
|
|
- // 1. 建立 WebSocket 连接
|
|
|
|
|
- this.connectWebSocket();
|
|
|
|
|
|
|
+ console.log('🚀 初始化 tim-presence-manager,用户ID:', userId);
|
|
|
|
|
|
|
|
- // 2. 监听 TIM 连接状态变更
|
|
|
|
|
- this.listenTIMConnectionStatus();
|
|
|
|
|
|
|
+ // 连接 WebSocket(接收服务端推送的状态变更)
|
|
|
|
|
+ this.connectWebSocket();
|
|
|
|
|
|
|
|
- // 3. 监听 TIM 用户状态更新
|
|
|
|
|
- this.listenTIMUserStatus();
|
|
|
|
|
|
|
+ console.log('✅ tim-presence-manager 初始化完成');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -150,17 +143,27 @@ class TIMPresenceManager {
|
|
|
|
|
|
|
|
// 监听用户状态更新事件
|
|
// 监听用户状态更新事件
|
|
|
this.timStatusListener = (event) => {
|
|
this.timStatusListener = (event) => {
|
|
|
- console.log('👥 收到 TIM 用户状态更新:', event.data);
|
|
|
|
|
|
|
+ console.log('=== 👥 收到 TIM 用户状态更新事件 ===');
|
|
|
|
|
+ console.log(' - 事件数据:', JSON.stringify(event.data, null, 2));
|
|
|
|
|
|
|
|
const { userStatusList } = event.data;
|
|
const { userStatusList } = event.data;
|
|
|
|
|
|
|
|
if (userStatusList && userStatusList.length > 0) {
|
|
if (userStatusList && userStatusList.length > 0) {
|
|
|
|
|
+ console.log(` - 状态变更用户数: ${userStatusList.length}`);
|
|
|
|
|
+
|
|
|
userStatusList.forEach(item => {
|
|
userStatusList.forEach(item => {
|
|
|
const userId = item.userID;
|
|
const userId = item.userID;
|
|
|
|
|
+ console.log(` - 用户 ${userId}:`);
|
|
|
|
|
+ console.log(` 原始状态类型: ${item.statusType}`);
|
|
|
|
|
+ console.log(` USER_STATUS_ONLINE: ${TIM.TYPES.USER_STATUS_ONLINE}`);
|
|
|
|
|
+ console.log(` USER_STATUS_OFFLINE: ${TIM.TYPES.USER_STATUS_OFFLINE}`);
|
|
|
|
|
+
|
|
|
const status = item.statusType === TIM.TYPES.USER_STATUS_ONLINE ? 'online' : 'offline';
|
|
const status = item.statusType === TIM.TYPES.USER_STATUS_ONLINE ? 'online' : 'offline';
|
|
|
|
|
+ console.log(` 判断结果: ${status}`);
|
|
|
|
|
|
|
|
// 更新本地缓存
|
|
// 更新本地缓存
|
|
|
this.onlineStatusCache.set(String(userId), status === 'online');
|
|
this.onlineStatusCache.set(String(userId), status === 'online');
|
|
|
|
|
+ console.log(` 已更新缓存: ${status === 'online'}`);
|
|
|
|
|
|
|
|
// 通知状态变化
|
|
// 通知状态变化
|
|
|
this.notifyStatusChange(String(userId), status);
|
|
this.notifyStatusChange(String(userId), status);
|
|
@@ -168,11 +171,15 @@ class TIMPresenceManager {
|
|
|
// 也可以通过 WS 上报给服务端,保证服务端状态一致
|
|
// 也可以通过 WS 上报给服务端,保证服务端状态一致
|
|
|
this.reportFriendStatus(userId, status);
|
|
this.reportFriendStatus(userId, status);
|
|
|
});
|
|
});
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.warn(' ⚠️ userStatusList 为空或不存在');
|
|
|
}
|
|
}
|
|
|
|
|
+ console.log('=== 状态更新处理完成 ===');
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
timManager.tim.on(TIM.EVENT.USER_STATUS_UPDATED, this.timStatusListener);
|
|
timManager.tim.on(TIM.EVENT.USER_STATUS_UPDATED, this.timStatusListener);
|
|
|
- console.log('✅ 已监听 TIM 用户状态更新');
|
|
|
|
|
|
|
+ console.log('✅ 已监听 TIM 用户状态更新事件');
|
|
|
|
|
+ console.log(' - 事件名称:', TIM.EVENT.USER_STATUS_UPDATED);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -234,32 +241,121 @@ class TIMPresenceManager {
|
|
|
async subscribeUserStatus(userIdList) {
|
|
async subscribeUserStatus(userIdList) {
|
|
|
if (!timManager.tim || !timManager.isLogin) {
|
|
if (!timManager.tim || !timManager.isLogin) {
|
|
|
console.warn('⚠️ TIM 未登录,无法订阅用户状态');
|
|
console.warn('⚠️ TIM 未登录,无法订阅用户状态');
|
|
|
|
|
+ console.warn(' - timManager.tim:', !!timManager.tim);
|
|
|
|
|
+ console.warn(' - timManager.isLogin:', timManager.isLogin);
|
|
|
|
|
+
|
|
|
|
|
+ // 使用 HTTP 轮询作为备用方案
|
|
|
|
|
+ console.log('💡 启用 HTTP 轮询备用方案');
|
|
|
|
|
+ this.startHttpPolling(userIdList);
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ console.log('📡 开始订阅用户状态...');
|
|
|
|
|
+ console.log(' - 订阅用户列表:', userIdList);
|
|
|
|
|
+ console.log(' - TIM SDK 版本:', timManager.tim.VERSION);
|
|
|
|
|
+
|
|
|
try {
|
|
try {
|
|
|
const result = await timManager.tim.subscribeUserStatus({
|
|
const result = await timManager.tim.subscribeUserStatus({
|
|
|
userIDList: userIdList.map(id => String(id))
|
|
userIDList: userIdList.map(id => String(id))
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
- console.log('✅ 订阅用户状态成功:', result);
|
|
|
|
|
|
|
+ console.log('✅ 订阅用户状态成功!');
|
|
|
|
|
+ console.log(' - 完整结果:', JSON.stringify(result, null, 2));
|
|
|
|
|
|
|
|
// 订阅成功后,初始化这些用户的状态
|
|
// 订阅成功后,初始化这些用户的状态
|
|
|
if (result.data && result.data.successUserList) {
|
|
if (result.data && result.data.successUserList) {
|
|
|
|
|
+ console.log('📋 成功订阅的用户列表:', result.data.successUserList.length, '个');
|
|
|
|
|
+
|
|
|
result.data.successUserList.forEach(user => {
|
|
result.data.successUserList.forEach(user => {
|
|
|
|
|
+ console.log(` - 用户 ${user.userID}:`);
|
|
|
|
|
+ console.log(` 状态类型: ${user.statusType}`);
|
|
|
|
|
+ console.log(` USER_STATUS_ONLINE 常量:`, timManager.tim.TIM.TYPES.USER_STATUS_ONLINE);
|
|
|
|
|
+ console.log(` USER_STATUS_OFFLINE 常量:`, timManager.tim.TIM.TYPES.USER_STATUS_OFFLINE);
|
|
|
|
|
+
|
|
|
const status = user.statusType === timManager.tim.TIM.TYPES.USER_STATUS_ONLINE ? 'online' : 'offline';
|
|
const status = user.statusType === timManager.tim.TIM.TYPES.USER_STATUS_ONLINE ? 'online' : 'offline';
|
|
|
|
|
+ console.log(` 最终判断状态: ${status}`);
|
|
|
|
|
+
|
|
|
this.onlineStatusCache.set(String(user.userID), status === 'online');
|
|
this.onlineStatusCache.set(String(user.userID), status === 'online');
|
|
|
this.notifyStatusChange(String(user.userID), status);
|
|
this.notifyStatusChange(String(user.userID), status);
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 检查失败列表
|
|
|
|
|
+ if (result.data && result.data.failureUserList && result.data.failureUserList.length > 0) {
|
|
|
|
|
+ console.warn('⚠️ 部分用户订阅失败:', result.data.failureUserList);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
return result;
|
|
return result;
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
console.error('❌ 订阅用户状态失败:', error);
|
|
console.error('❌ 订阅用户状态失败:', error);
|
|
|
|
|
+ console.error(' - 错误详情:', error.message);
|
|
|
|
|
+ console.error(' - 错误代码:', error.code);
|
|
|
|
|
+
|
|
|
|
|
+ // 如果订阅失败,启用 HTTP 轮询备用方案
|
|
|
|
|
+ if (error.code === 70402 || error.code === 70403) {
|
|
|
|
|
+ console.log('💡 TIM 在线状态功能未开启,启用 HTTP 轮询备用方案');
|
|
|
|
|
+ this.startHttpPolling(userIdList);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
throw error;
|
|
throw error;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * HTTP 轮询备用方案(当 TIM 订阅失败时使用)
|
|
|
|
|
+ * @param {Array<String>} userIdList 用户ID列表
|
|
|
|
|
+ */
|
|
|
|
|
+ startHttpPolling(userIdList) {
|
|
|
|
|
+ console.log('🔄 启动 HTTP 轮询,间隔 30 秒');
|
|
|
|
|
+
|
|
|
|
|
+ // 立即查询一次
|
|
|
|
|
+ this.pollUserStatus(userIdList);
|
|
|
|
|
+
|
|
|
|
|
+ // 每 30 秒轮询一次
|
|
|
|
|
+ this.pollingTimer = setInterval(() => {
|
|
|
|
|
+ this.pollUserStatus(userIdList);
|
|
|
|
|
+ }, 30000);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 轮询用户状态
|
|
|
|
|
+ */
|
|
|
|
|
+ async pollUserStatus(userIdList) {
|
|
|
|
|
+ for (const userId of userIdList) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const [err, res] = await uni.request({
|
|
|
|
|
+ url: 'http://localhost:8083/api/online/checkStatus',
|
|
|
|
|
+ method: 'GET',
|
|
|
|
|
+ data: { userId }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ if (!err && res.data && res.data.code === 200) {
|
|
|
|
|
+ const isOnline = res.data.data.online || false;
|
|
|
|
|
+ const oldStatus = this.onlineStatusCache.get(String(userId));
|
|
|
|
|
+
|
|
|
|
|
+ // 只有状态变化时才通知
|
|
|
|
|
+ if (oldStatus !== isOnline) {
|
|
|
|
|
+ this.onlineStatusCache.set(String(userId), isOnline);
|
|
|
|
|
+ this.notifyStatusChange(String(userId), isOnline ? 'online' : 'offline');
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error(`查询用户 ${userId} 状态失败:`, error);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 停止 HTTP 轮询
|
|
|
|
|
+ */
|
|
|
|
|
+ stopHttpPolling() {
|
|
|
|
|
+ if (this.pollingTimer) {
|
|
|
|
|
+ clearInterval(this.pollingTimer);
|
|
|
|
|
+ this.pollingTimer = null;
|
|
|
|
|
+ console.log('🛑 已停止 HTTP 轮询');
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 取消订阅用户状态
|
|
* 取消订阅用户状态
|
|
|
* @param {Array<String>} userIdList 用户ID列表
|
|
* @param {Array<String>} userIdList 用户ID列表
|
|
@@ -449,6 +545,7 @@ class TIMPresenceManager {
|
|
|
*/
|
|
*/
|
|
|
disconnect() {
|
|
disconnect() {
|
|
|
this.stopHeartbeat();
|
|
this.stopHeartbeat();
|
|
|
|
|
+ this.stopHttpPolling(); // 停止 HTTP 轮询
|
|
|
|
|
|
|
|
if (this.reconnectTimer) {
|
|
if (this.reconnectTimer) {
|
|
|
clearTimeout(this.reconnectTimer);
|
|
clearTimeout(this.reconnectTimer);
|