findme-miniprogram-frontend/pages/social/friends/friends.js
2025-12-27 17:16:03 +08:00

726 lines
20 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 好友列表页面
const app = getApp();
const apiClient = require('../../../utils/api-client.js');
const friendAPI = require('../../../utils/friend-api.js');
const notificationManager = require('../../../utils/notification-manager.js');
const wsManager = require('../../../utils/websocket-manager-v2.js');
const nimPresenceManager = require('../../../utils/nim-presence-manager.js');
const { modernSystemInfo, initPageSystemInfo } = require('../../../utils/system-info-modern.js');
Page({
data: {
// 好友数据
friends: [],
filteredFriends: [],
// UI状态
loading: true,
refreshing: false,
searchKeyword: '',
searching: false,
searchResultCount: 0,
showSearchBar: false,
// 统计数据
newFriendRequests: 0,
totalFriendsCount: 0,
onlineFriendsCount: 0,
recentActiveCount: 0,
mutualFriendsCount: 0,
// 系统适配信息
systemInfo: {},
statusBarHeight: 0,
menuButtonHeight: 0,
menuButtonTop: 0,
navBarHeight: 0,
windowHeight: 0,
safeAreaBottom: 0,
// 添加好友提示
showAddTip: false,
userInfo: {},
// 事件处理状态
eventHandlingState: {
lastEventTime: 0,
eventThrottleMs: 300
}
},
onLoad: function (options) {
this.initSystemInfo();
this.checkAuthAndLoad();
// 注册在线状态变化监听
this.registerPresenceListener();
},
onShow: function () {
// 设置tabBar选中状态为"我的"索引3
try {
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
this.getTabBar().setData({ selected: 3 });
}
} catch (_) {}
// 检查是否需要刷新好友请求数量
const app = getApp();
if (app.globalData && app.globalData.needRefreshFriendRequests) {
app.globalData.needRefreshFriendRequests = false;
// 立即刷新好友请求数量
this.loadFriendRequestsCount();
}
// 刷新数据前先检查认证状态
this.checkAuthAndLoad();
},
// 初始化系统信息
initSystemInfo() {
const pageSystemInfo = initPageSystemInfo();
this.setData({
systemInfo: pageSystemInfo.systemInfo,
statusBarHeight: pageSystemInfo.statusBarHeight,
menuButtonHeight: pageSystemInfo.menuButtonHeight,
menuButtonTop: pageSystemInfo.menuButtonTop,
navBarHeight: pageSystemInfo.navBarHeight,
windowHeight: pageSystemInfo.windowHeight,
safeAreaBottom: pageSystemInfo.safeAreaBottom
});
},
// 检查认证状态并加载数据
async checkAuthAndLoad() {
try {
// 确保API客户端能获取到token
const currentToken = apiClient.getToken();
if (!currentToken) {
console.error('用户未登录,跳转到登录页');
wx.reLaunch({
url: '/pages/login/login'
});
return;
}
// 获取用户信息 - 确保有完整的用户数据
await this.loadUserInfo();
// 🔥 初始化WebSocket好友功能用于实时接收好友请求通知
this.initWebSocketFriendFeatures();
// 开始加载数据
this.loadFriends();
this.loadFriendRequestsCount();
} catch (error) {
console.error('认证检查失败:', error);
wx.reLaunch({
url: '/pages/login/login'
});
}
},
// 加载用户信息
async loadUserInfo() {
try {
// 先从全局数据获取
let userInfo = getApp().globalData.userInfo;
// 如果全局没有完整信息从API获取
if (!userInfo || !userInfo.user || !userInfo.user.customId) {
const response = await apiClient.getUserInfo();
if (response && response.code === 0) {
userInfo = {
...userInfo,
user: response.data
};
// 更新全局数据
getApp().globalData.userInfo = userInfo;
}
}
this.setData({
userInfo: userInfo
});
} catch (error) {
console.error('❌ 获取用户信息失败:', error);
// 不影响主要功能,继续加载好友列表
}
},
// 加载好友列表 - 参考Flutter app的实现
async loadFriends() {
try {
this.setData({ loading: true });
const response = await friendAPI.getFriendList();
if (response && response.code === 0) {
const friends = response.data || [];
// 处理好友数据参考Flutter app的数据结构
const processedFriends = this.processFriendsData(friends);
this.setData({
friends: processedFriends,
filteredFriends: processedFriends,
totalFriendsCount: processedFriends.length,
loading: false
});
// 计算在线好友数和其他统计
this.calculateFriendStats(processedFriends);
// 🔥 订阅好友的在线状态通过NIM实现
this.subscribeFriendsPresence(processedFriends);
} else {
throw new Error(response?.message || '获取好友列表失败');
}
} catch (error) {
console.error('❌ 加载好友列表失败:', error);
this.setData({ loading: false });
// 未登录用户静默跳转到登录页
const app = getApp();
if (!app.globalData.isLoggedIn) {
setTimeout(() => {
wx.reLaunch({ url: '/pages/login/login' });
}, 500);
return;
}
// 已登录用户显示错误提示
wx.showToast({
title: '加载好友失败',
icon: 'none',
duration: 2000
});
}
},
// 处理好友数据 - 参考Flutter app的数据结构
processFriendsData(friends) {
return friends.map(friend => {
// 适配不同的字段名参考Flutter app的FriendModel
const nickname = friend.nickname || friend.username || friend.name || '未知用户';
const customId = friend.customId || friend.customID || friend.id;
return {
id: customId,
customId: customId,
name: nickname,
nickname: nickname,
avatar: friend.avatar || '', // 头像URL
personalSignature: friend.signature || friend.bio || friend.personalSignature || '',
isOnline: friend.isOnline || false,
isVip: friend.isVip || false,
gender: friend.gender || null, // male, female, null
remark: friend.remark || '',
relation: friend.relation || '好友',
location: friend.location || '',
distance: friend.distance || 0,
lastActiveTime: friend.lastActiveTime || '',
tags: friend.tags || [],
hasMutualFriends: friend.mutualFriends > 0,
isBirthdayToday: false, // 可以根据实际情况计算
isNewFriend: friend.isNewFriend || false
};
});
},
// 计算好友统计数据
calculateFriendStats(friends) {
const onlineCount = friends.filter(f => f.isOnline).length;
const recentActiveCount = friends.filter(f => {
if (!f.lastActiveTime) return false;
const oneHourAgo = Date.now() - (60 * 60 * 1000);
return new Date(f.lastActiveTime).getTime() > oneHourAgo;
}).length;
const mutualCount = friends.filter(f => f.hasMutualFriends).length;
this.setData({
onlineFriendsCount: onlineCount,
recentActiveCount: recentActiveCount,
mutualFriendsCount: mutualCount
});
},
// 注册在线状态变化监听
registerPresenceListener() {
try {
// 移除旧的监听器(如果存在)
nimPresenceManager.off('presence_changed', this.handlePresenceChanged);
// 注册新的监听器通过NIM实现在线状态
nimPresenceManager.on('presence_changed', this.handlePresenceChanged.bind(this));
} catch (error) {
console.error('注册在线状态监听失败:', error);
}
},
// 订阅好友的在线状态
async subscribeFriendsPresence(friends) {
try {
if (!friends || friends.length === 0) {
return;
}
// 提取所有好友的customId
const userIds = friends
.map(f => f.customId || f.id)
.filter(Boolean);
if (userIds.length > 0) {
// 通过NIM订阅在线状态immediateSync=true 确保首次订阅时立即返回在线状态
await nimPresenceManager.subscribe(userIds, 7 * 24 * 3600, true);
// 订阅后立即从缓存更新在线状态
this.updateFriendsPresenceFromCache();
}
} catch (error) {
console.error('订阅好友在线状态失败:', error);
}
},
// 从缓存更新好友的在线状态
updateFriendsPresenceFromCache() {
try {
let friends = [...this.data.friends];
let hasChanges = false;
friends.forEach(friend => {
const userId = friend.customId || friend.id;
if (!userId) return;
const presence = nimPresenceManager.getUserPresence(userId);
if (presence) {
friend.isOnline = presence.online;
hasChanges = true;
}
});
if (hasChanges) {
this.setData({
friends: friends,
filteredFriends: this.data.searchKeyword ?
this.filterFriendsByKeyword(friends, this.data.searchKeyword) : friends
});
// 重新计算统计数据
this.calculateFriendStats(friends);
}
} catch (error) {
console.error('更新好友在线状态失败:', error);
}
},
// 处理在线状态变化
handlePresenceChanged(data) {
try {
const { userId, isOnline } = data;
let friends = [...this.data.friends];
let hasChanges = false;
friends.forEach(friend => {
const friendId = friend.customId || friend.id;
if (friendId === userId) {
friend.isOnline = isOnline;
hasChanges = true;
}
});
if (hasChanges) {
this.setData({
friends: friends,
filteredFriends: this.data.searchKeyword ?
this.filterFriendsByKeyword(friends, this.data.searchKeyword) : friends
});
// 重新计算统计数据
this.calculateFriendStats(friends);
}
} catch (error) {
console.error('处理在线状态变化失败:', error);
}
},
// 辅助方法:根据关键词过滤好友(增强版)
filterFriendsByKeyword(friends, keyword) {
if (!keyword || !keyword.trim()) {
return friends;
}
const searchText = keyword.toLowerCase().trim();
return friends.filter(friend => {
// 1. 匹配备注名(优先级最高)
const remark = (friend.remark || '').toLowerCase();
if (remark.includes(searchText)) {
return true;
}
// 2. 匹配昵称
const nickname = (friend.nickname || '').toLowerCase();
if (nickname.includes(searchText)) {
return true;
}
// 3. 匹配自定义ID
const customId = (friend.customId || '').toLowerCase();
if (customId.includes(searchText)) {
return true;
}
// 4. 匹配个性签名
const signature = (friend.personalSignature || friend.bio || '').toLowerCase();
if (signature.includes(searchText)) {
return true;
}
// 5. 匹配手机号(如果有)
const phone = (friend.phone || '').toLowerCase();
if (phone.includes(searchText)) {
return true;
}
return false;
});
},
// 获取好友请求数量 - 参考Flutter app的实现
async loadFriendRequestsCount() {
try {
const response = await friendAPI.getFriendRequestCount();
if (response && response.code === 0) {
const count = response.data?.count || 0;
this.setData({
newFriendRequests: count
});
// 同步自定义TabBar角标好友
try {
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
this.getTabBar().setFriendsBadge(count);
}
} catch (_) {}
// 同步通知管理器的未读计数
try { notificationManager.setFriendsUnreadCount(count); } catch (_) {}
}
} catch (error) {
console.error('❌ 获取好友请求数量失败:', error);
// 不影响主要功能只是数量显示为0
this.setData({
newFriendRequests: 0
});
}
},
// 搜索输入(实时搜索)
onSearchInput(e) {
const keyword = e.detail.value;
this.setData({
searchKeyword: keyword,
searching: true
});
// 防抖处理
if (this.searchTimer) {
clearTimeout(this.searchTimer);
}
this.searchTimer = setTimeout(() => {
this.filterFriends(keyword);
}, 300);
},
// 过滤好友
filterFriends(keyword) {
const filtered = this.filterFriendsByKeyword(this.data.friends, keyword);
this.setData({
filteredFriends: filtered,
searchResultCount: filtered.length,
searching: false
});
// 记录搜索历史(非空且有结果)
if (keyword && keyword.trim() && filtered.length > 0) {
this.saveSearchHistory(keyword.trim());
}
},
// 清除搜索
clearSearch() {
this.setData({
searchKeyword: '',
searchResultCount: 0,
searching: false
});
this.filterFriends('');
},
// 显示搜索栏
showSearch() {
this.setData({ showSearchBar: true });
},
// 隐藏搜索栏
hideSearch() {
this.clearSearch();
this.setData({ showSearchBar: false });
},
// 保存搜索历史
saveSearchHistory(keyword) {
try {
let history = wx.getStorageSync('friendSearchHistory') || [];
// 移除重复项
history = history.filter(item => item !== keyword);
// 添加到开头
history.unshift(keyword);
// 最多保存10条
history = history.slice(0, 10);
wx.setStorageSync('friendSearchHistory', history);
} catch (error) {
console.error('保存搜索历史失败:', error);
}
},
// 获取搜索历史
getSearchHistory() {
try {
return wx.getStorageSync('friendSearchHistory') || [];
} catch (error) {
console.error('获取搜索历史失败:', error);
return [];
}
},
// 清除搜索历史
clearSearchHistory() {
try {
wx.removeStorageSync('friendSearchHistory');
wx.showToast({
title: '已清除搜索历史',
icon: 'success'
});
} catch (error) {
console.error('清除搜索历史失败:', error);
}
},
// 下拉刷新
async onRefresh() {
this.setData({ refreshing: true });
try {
await this.loadFriends();
await this.loadFriendRequestsCount();
wx.showToast({
title: '刷新成功',
icon: 'success',
duration: 1000
});
} catch (error) {
wx.showToast({
title: '刷新失败',
icon: 'none'
});
} finally {
this.setData({ refreshing: false });
}
},
// 打开好友资料
openFriendProfile(e) {
const friend = e.currentTarget.dataset.friend;
wx.navigateTo({
url: `/subpackages/social/friend-detail/friend-detail?customId=${friend.customId}`
});
},
// 好友请求 - 修改后的名称
openNewFriends() {
// 进入前刷新一次,确保角标与列表同步
try { this.loadFriendRequestsCount(); } catch (_) {}
wx.navigateTo({
url: '/subpackages/social/friend-requests/friend-requests'
});
},
// 建群 - 修改后的功能
openGroupChats() {
wx.navigateTo({
url: '/subpackages/group/create-group/create-group'
});
},
// 添加好友 - 跳转到搜索页面
addFriend() {
wx.navigateTo({
url: '/subpackages/social/search/search'
});
},
// 🔥 初始化WebSocket好友功能监听好友请求实时通知
initWebSocketFriendFeatures() {
try {
if (this._wsFriendInited) return;
this._wsFriendInited = true;
console.log('🔌 初始化WebSocket好友事件监听器');
// 绑定处理函数到 this方便后续移除
this.handleNotificationMessage = this.handleNotificationMessage.bind(this);
// 监听通知消息(包含好友请求)
wsManager.on('notification', this.handleNotificationMessage);
} catch (error) {
console.error('初始化WebSocket好友功能失败:', error);
}
},
// 处理通知消息
handleNotificationMessage(msg) {
try {
console.log('🔔 收到通知消息:', msg);
const data = msg?.data || msg;
// 判断是否为好友通知
if (data?.type === 'friend_notification') {
this.handleFriendNotification(data);
} else if (data?.type === 'friend_request_notification') {
this.handleFriendRequestNotification(data);
}
} catch (error) {
console.error('处理通知消息失败:', error);
}
},
// 处理好友通知包含request/accepted/rejected/count_update
handleFriendNotification(data) {
try {
console.log('🆕 处理好友通知:', data);
const subType = data?.subType;
const senderName = data?.senderName || '用户';
const pendingCount = data?.pendingCount || 0;
switch (subType) {
case 'request':
// 新好友请求
wx.showToast({
title: `${senderName} 请求添加您为好友`,
icon: 'none',
duration: 3000
});
this.updateBadge(pendingCount);
break;
case 'accepted':
// 好友请求被接受
wx.showToast({
title: `${senderName} 已接受您的好友申请`,
icon: 'success',
duration: 2000
});
this.updateBadge(pendingCount);
// 刷新好友列表
this.loadFriends();
break;
case 'rejected':
// 好友请求被拒绝
wx.showToast({
title: `${senderName} 已拒绝您的好友申请`,
icon: 'none',
duration: 2000
});
this.updateBadge(pendingCount);
break;
case 'count_update':
// 待处理数量更新
this.updateBadge(pendingCount);
break;
default:
console.warn('未知的好友通知子类型:', subType);
// 默认刷新数量
this.loadFriendRequestsCount();
}
} catch (error) {
console.error('处理好友通知失败:', error);
}
},
// 处理连接时的待处理好友请求通知
handleFriendRequestNotification(data) {
try {
console.log('📋 处理待处理好友请求通知:', data);
const pendingCount = data?.pendingCount || 0;
this.updateBadge(pendingCount);
} catch (error) {
console.error('处理待处理好友请求通知失败:', error);
}
},
// 更新小红点角标
updateBadge(count) {
try {
// 更新页面数据
this.setData({
newFriendRequests: count
});
// 同步自定义TabBar角标
if (typeof this.getTabBar === 'function' && this.getTabBar()) {
this.getTabBar().setFriendsBadge(count);
}
// 同步通知管理器的未读计数
notificationManager.setFriendsUnreadCount(count);
console.log('✅ 已更新好友请求角标:', count);
} catch (error) {
console.error('更新角标失败:', error);
}
},
// 页面卸载
onUnload() {
// 移除在线状态监听器
try {
nimPresenceManager.off('presence_changed', this.handlePresenceChanged);
} catch (error) {
console.error('移除在线状态监听器失败:', error);
}
// 移除 WebSocket 通知监听器
try {
if (this.handleNotificationMessage) {
wsManager.off('notification', this.handleNotificationMessage);
console.log('✅ 已移除 WebSocket 通知监听器');
}
} catch (error) {
console.error('移除 WebSocket 通知监听器失败:', error);
}
}
});