import 'dart:convert'; import 'package:get/get.dart'; import 'package:im_flutter_sdk/im_flutter_sdk.dart'; import '../../im/im_manager.dart'; import '../../model/mine/user_base_data.dart'; import '../mine/user_controller.dart'; import 'chat_controller.dart'; // 扩展类用于存储用户信息(包括业务系统的信息) class ExtendedUserInfo { final String userId; final String? nickName; final String? avatarUrl; ExtendedUserInfo({ required this.userId, this.nickName, this.avatarUrl, }); // 从 EMUserInfo 创建 factory ExtendedUserInfo.fromEMUserInfo(EMUserInfo emUserInfo) { return ExtendedUserInfo( userId: emUserInfo.userId, nickName: emUserInfo.nickName, avatarUrl: emUserInfo.avatarUrl, ); } // 从 UserBaseData 创建 factory ExtendedUserInfo.fromUserBaseData(UserBaseData userBaseData, {String? avatarUrl}) { return ExtendedUserInfo( userId: userBaseData.userId, nickName: userBaseData.nickName, avatarUrl: avatarUrl, ); } } // 筛选类型枚举 enum FilterType { none, // 无筛选 lastChatTime, // 最后聊天时间 unread, // 未读消息 online, // 当前在线 } class ConversationController extends GetxController { // 会话列表数据 final conversations = [].obs; // 加载状态 final isLoading = false.obs; // 错误消息 final errorMessage = ''.obs; // 用户信息缓存(userId -> ExtendedUserInfo) final Map _userInfoCache = {}; // 筛选类型 final filterType = FilterType.none.obs; // 总未读数 final totalUnreadCount = 0.obs; /// 缓存用户信息(公开方法,供 ChatController 调用) void cacheUserInfo(String userId, ExtendedUserInfo userInfo) { _userInfoCache[userId] = userInfo; if (Get.isLogEnable) { Get.log('✅ [ConversationController] 已缓存用户信息: userId=$userId, nickName=${userInfo.nickName}'); } } /// 从缓存获取用户信息(公开方法,供 UI 调用) ExtendedUserInfo? getCachedUserInfo(String userId) { return _userInfoCache[userId]; } @override void onInit() { super.onInit(); // 初始化时检查 IM 登录状态,如果已登录则加载会话列表 _checkAndLoadConversations(); } /// 检查 IM 登录状态并加载会话列表 Future _checkAndLoadConversations() async { // 如果已登录,直接加载 if (IMManager.instance.isLoggedIn) { await loadConversations(); return; } // 如果未登录,等待登录完成(最多等待 10 秒) if (Get.isLogEnable) { Get.log('⏳ [ConversationController] IM 未登录,等待登录完成...'); } int retryCount = 0; const maxRetries = 20; // 最多重试 20 次(每次 500ms,总共 10 秒) while (retryCount < maxRetries && !IMManager.instance.isLoggedIn) { await Future.delayed(Duration(milliseconds: 500)); retryCount++; } if (IMManager.instance.isLoggedIn) { if (Get.isLogEnable) { Get.log('✅ [ConversationController] IM 已登录,开始加载会话列表'); } await loadConversations(); } else { if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] IM 登录超时,显示错误提示'); } errorMessage.value = 'IM 未登录,请稍后重试'; isLoading.value = false; } } /// 加载会话列表 Future loadConversations() async { if (isLoading.value) return; // 检查 IM 登录状态 if (!IMManager.instance.isLoggedIn) { if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] IM 未登录,无法加载会话列表'); } errorMessage.value = 'IM 未登录,无法加载会话列表'; isLoading.value = false; return; } try { isLoading.value = true; errorMessage.value = ''; // 从IMManager获取会话列表 final List convList = await IMManager.instance .getConversations(); // 先提取用户信息并缓存,然后再更新会话列表 // 这样可以确保在列表渲染时,用户信息已经在缓存中了 await _extractUserInfoFromConversations(convList); // 更新会话列表(在用户信息提取完成后) conversations.value = convList; // 计算总未读数 await _updateTotalUnreadCount(); // 使用GetX日志系统 if (Get.isLogEnable) { Get.log('Loaded ${convList.length} conversations'); } } catch (e) { // 使用GetX日志系统 if (Get.isLogEnable) { Get.log('Failed to load conversations: $e'); } errorMessage.value = '加载会话列表失败,请稍后重试'; } finally { isLoading.value = false; } } /// 从所有会话的历史消息中提取用户信息并缓存 /// 这样应用重启后也能恢复用户信息 /// 注意:只提取对方(接收到的消息)的用户信息,不提取自己的信息 Future _extractUserInfoFromConversations(List convList) async { try { for (var conversation in convList) { try { // conversation.id 是对方用户ID final targetUserId = conversation.id; // 如果缓存中已有该用户信息,跳过 if (_userInfoCache.containsKey(targetUserId)) continue; // 获取会话的最新消息(增加数量以提高找到用户信息的概率) final messages = await conversation.loadMessages( loadCount: 50, // 从20增加到50,提高找到用户信息的概率 ); if (Get.isLogEnable) { Get.log('🔍 [ConversationController] 开始提取用户信息: userId=$targetUserId, 消息数量=${messages.length}'); } // 从消息中提取用户信息 // 接收消息:提取发送者信息(sender_ 前缀) // 发送消息:提取接收者信息(receiver_ 前缀) // 遍历所有消息,找到最新的包含用户信息的消息 ExtendedUserInfo? foundUserInfo; for (var message in messages) { Map? attributes; try { attributes = message.attributes; } catch (e) { if (Get.isLogEnable) { Get.log(' ⚠️ 无法访问消息 attributes: msgId=${message.msgId}, error=$e'); } continue; } if (attributes == null || attributes.isEmpty) { if (Get.isLogEnable) { Get.log(' ⚠️ 消息 attributes 为空: msgId=${message.msgId}, direction=${message.direction}'); } continue; } if (Get.isLogEnable) { Get.log(' 📨 检查消息: msgId=${message.msgId}, direction=${message.direction}, from=${message.from}, to=${message.to}, attributes keys=${attributes.keys.toList()}'); } if (message.direction == MessageDirection.RECEIVE) { // 接收到的消息:从扩展字段中提取发送者信息(sender_ 前缀) final fromUserId = message.from; if (fromUserId != null && fromUserId == targetUserId) { // 优先使用 sender_ 前缀的字段(发送者信息) final nickName = attributes['sender_nickName'] as String? ?? attributes['nickName'] as String?; final avatarUrl = attributes['sender_avatarUrl'] as String? ?? attributes['avatarUrl'] as String?; if (nickName != null || avatarUrl != null) { // 如果找到用户信息,保存(但继续遍历以找到最新的) foundUserInfo = ExtendedUserInfo( userId: targetUserId, nickName: nickName, avatarUrl: avatarUrl, ); if (Get.isLogEnable) { Get.log('✅ [ConversationController] 从接收消息找到用户信息: userId=$targetUserId, nickName=$nickName, msgId=${message.msgId}'); } // 继续遍历,找到最新的消息(因为消息是按时间倒序的,第一个就是最新的) break; } } } else if (message.direction == MessageDirection.SEND) { // 发送的消息:从扩展字段中提取接收者信息(receiver_ 前缀) final toUserId = message.to; if (toUserId != null && toUserId == targetUserId) { // 使用 receiver_ 前缀的字段(接收者信息) final nickName = attributes['receiver_nickName'] as String?; final avatarUrl = attributes['receiver_avatarUrl'] as String?; if (nickName != null || avatarUrl != null) { // 如果找到用户信息,保存(但继续遍历以找到最新的) foundUserInfo = ExtendedUserInfo( userId: targetUserId, nickName: nickName, avatarUrl: avatarUrl, ); if (Get.isLogEnable) { Get.log('✅ [ConversationController] 从发送消息找到用户信息: userId=$targetUserId, nickName=$nickName, msgId=${message.msgId}'); } // 继续遍历,找到最新的消息(因为消息是按时间倒序的,第一个就是最新的) break; } } } } // 如果找到了用户信息,保存到缓存 if (foundUserInfo != null) { _userInfoCache[targetUserId] = foundUserInfo; } // 如果从消息中提取不到用户信息,尝试从环信获取(作为备选) if (!_userInfoCache.containsKey(targetUserId)) { try { var data = await IMManager.instance.getContacts(targetUserId); var emUserInfo = data[targetUserId]; if (emUserInfo != null && (emUserInfo.nickName?.isNotEmpty ?? false)) { final extendedInfo = ExtendedUserInfo.fromEMUserInfo(emUserInfo); _userInfoCache[targetUserId] = extendedInfo; if (Get.isLogEnable) { Get.log('✅ [ConversationController] 从环信获取到用户信息: userId=$targetUserId, nickName=${extendedInfo.nickName}'); } } } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] 从环信获取用户信息失败: $e'); } } } } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] 从会话提取用户信息失败: ${conversation.id}, 错误: $e'); } } } } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] 批量提取用户信息失败: $e'); } } } /// 刷新会话列表 Future refreshConversations() async { // 如果IM未登录,先尝试登录 if (!IMManager.instance.isLoggedIn) { if (Get.isLogEnable) { Get.log('🔄 [ConversationController] IM未登录,尝试重新登录...'); } try { // 尝试获取token并登录 if (Get.isRegistered()) { final userController = Get.find(); final token = await userController.getHxUserToken(); if (token != null) { // 等待登录完成(最多等待5秒) int waitCount = 0; const maxWait = 10; // 最多等待10次,每次500ms,总共5秒 while (waitCount < maxWait && !IMManager.instance.isLoggedIn) { await Future.delayed(Duration(milliseconds: 500)); waitCount++; } if (IMManager.instance.isLoggedIn) { if (Get.isLogEnable) { Get.log('✅ [ConversationController] IM登录成功,开始加载会话列表'); } // 登录成功后加载会话列表 await loadConversations(); return; } else { if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] IM登录超时'); } errorMessage.value = 'IM登录超时,请稍后重试'; isLoading.value = false; return; } } else { if (Get.isLogEnable) { Get.log('❌ [ConversationController] 获取IM token失败'); } errorMessage.value = '获取IM token失败,请稍后重试'; isLoading.value = false; return; } } else { if (Get.isLogEnable) { Get.log('❌ [ConversationController] UserController未注册'); } errorMessage.value = 'IM未登录,请稍后重试'; isLoading.value = false; return; } } catch (e) { if (Get.isLogEnable) { Get.log('❌ [ConversationController] 重试登录失败: $e'); } errorMessage.value = '重试登录失败,请稍后重试'; isLoading.value = false; return; } } else { // 如果已登录,直接加载会话列表 await loadConversations(); } } /// 清除会话列表和用户信息缓存(用于退出登录时) void clearConversations() { conversations.clear(); _userInfoCache.clear(); errorMessage.value = ''; isLoading.value = false; if (Get.isLogEnable) { Get.log('✅ [ConversationController] 已清除会话列表和用户信息缓存'); } } /// 获取会话的最新消息 String getLastMessageContent(EMMessage? message) { if (message == null) { return '暂无消息'; } // 检查消息是否发送失败(发送的消息且状态为FAIL) if (message.direction == MessageDirection.SEND && message.status == MessageStatus.FAIL) { return '[发送失败]'; } if(message.body.type == MessageType.TXT){ final body = message.body as EMTextMessageBody; final content = body.content; // 检查是否是CALL消息 if (content != null && content.startsWith('[CALL:]')) { try { final jsonStr = content.substring(7); // 移除 '[CALL:]' 前缀 final callInfo = jsonDecode(jsonStr) as Map; final callType = callInfo['callType'] as String?; if (callType == 'video') { return '[视频通话]'; } else if (callType == 'voice') { return '[语音通话]'; } } catch (e) { // 解析失败,返回原始内容 if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] 解析CALL消息失败: $e'); } } } // 检查是否是GIFT消息 if (content != null && content.startsWith('[GIFT:]')) { return '[礼物]'; } return content ?? ''; }else if(message.body.type == MessageType.IMAGE){ return '[图片]'; }else if(message.body.type == MessageType.VOICE){ return '[语音]'; }else if(message.body.type == MessageType.VIDEO){ return '[视频]'; }else if(message.body.type == MessageType.FILE){ return '[文件]'; }else if(message.body.type == MessageType.LOCATION){ return '[位置]'; }else if(message.body.type == MessageType.CUSTOM){ final body = message.body as EMCustomMessageBody; // 检查是否是分享房间类型 if(body.event == 'live_room_invite'){ return '[分享房间]'; } return '[自定义消息]'; } return '暂无消息'; } /// 获取会话的未读消息数量 Future getUnreadCount(EMConversation conversation) async { try { // 简化实现,返回0 return await conversation.unreadCount(); } catch (e) { if (Get.isLogEnable) { Get.log('Error getting unread count: $e'); } return 0; } } /// 更新总未读数(内部方法) Future _updateTotalUnreadCount() async { try { int total = 0; for (var conversation in conversations) { final unreadCount = await getUnreadCount(conversation); total += unreadCount; } totalUnreadCount.value = total; if (Get.isLogEnable) { Get.log('✅ [ConversationController] 总未读数已更新: $total'); } } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] 更新总未读数失败: $e'); } totalUnreadCount.value = 0; } } /// 刷新总未读数(公开方法,供外部调用) Future refreshTotalUnreadCount() async { await _updateTotalUnreadCount(); } /// 格式化消息时间 String formatMessageTime(int timestamp) { DateTime messageTime = DateTime.fromMillisecondsSinceEpoch(timestamp); DateTime now = DateTime.now(); // 检查是否是今天 if (messageTime.year == now.year && messageTime.month == now.month && messageTime.day == now.day) { // 今天显示时:分 return '${messageTime.hour.toString().padLeft(2, '0')}:${messageTime.minute.toString().padLeft(2, '0')}'; } // 检查是否是昨天 DateTime yesterday = now.subtract(Duration(days: 1)); if (messageTime.year == yesterday.year && messageTime.month == yesterday.month && messageTime.day == yesterday.day) { return '昨天'; } // 其他日期显示月-日 return '${messageTime.month.toString().padLeft(2, '0')}-${messageTime.day.toString().padLeft(2, '0')}'; } Future loadContact(String userId) async{ try { // 1. 先从缓存中查找(优先级最高) if (_userInfoCache.containsKey(userId)) { final cachedUser = _userInfoCache[userId]!; if (Get.isLogEnable) { Get.log('✅ [ConversationController] 从缓存获取到用户信息: $userId, nickName=${cachedUser.nickName}, avatarUrl=${cachedUser.avatarUrl}'); } return cachedUser; } // 2. 尝试从会话的历史消息中提取用户信息(从消息扩展字段) // 这是最重要的数据源,因为用户信息存储在消息扩展字段中 // 注意:conversation.id 是对方用户ID,应该从接收到的消息中提取对方的信息 try { final conversation = await EMClient.getInstance.chatManager.getConversation( userId, type: EMConversationType.Chat, createIfNeed: false, ); if (conversation != null) { // 获取最近的消息(增加数量以提高找到用户信息的概率) final messages = await conversation.loadMessages( loadCount: 50, // 从20增加到50,提高找到用户信息的概率 ); // 从消息中查找用户信息(只查找接收到的消息,因为那是对方的用户信息) // conversation.id 是对方用户ID,所以应该从接收到的消息中提取对方的信息 if (Get.isLogEnable) { Get.log('🔍 [ConversationController] 开始从会话历史消息查找用户信息: userId=$userId, 消息数量=${messages.length}'); } // 先打印所有消息的详细信息,用于调试 if (Get.isLogEnable) { for (var msg in messages) { final fromId = msg.from; final toId = msg.to; final direction = msg.direction; Map? attrs; try { attrs = msg.attributes; } catch (e) { attrs = null; } Get.log(' 📨 消息: msgId=${msg.msgId}, 方向=$direction, from=$fromId, to=$toId, attributes=$attrs'); } } for (var message in messages) { Map? attributes; try { attributes = message.attributes; } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] 无法访问 message.attributes: $e'); } continue; } if (attributes == null || attributes.isEmpty) { continue; } if (message.direction == MessageDirection.RECEIVE) { // 接收到的消息:从扩展字段中提取发送者信息(sender_ 前缀) // conversation.id 是对方用户ID,应该从接收到的消息中提取发送者(对方)的信息 final fromUserId = message.from; if (fromUserId != null && fromUserId == userId) { // 优先使用 sender_ 前缀的字段(发送者信息) final nickName = attributes['sender_nickName'] as String? ?? attributes['nickName'] as String?; final avatarUrl = attributes['sender_avatarUrl'] as String? ?? attributes['avatarUrl'] as String?; if (Get.isLogEnable) { Get.log('🔍 [ConversationController] 从接收消息提取发送者信息: msgId=${message.msgId}, fromUserId=$fromUserId, nickName=$nickName, avatarUrl=$avatarUrl'); } if (nickName != null || avatarUrl != null) { final extendedInfo = ExtendedUserInfo( userId: userId, nickName: nickName, avatarUrl: avatarUrl, ); _userInfoCache[userId] = extendedInfo; if (Get.isLogEnable) { Get.log('✅ [ConversationController] 从接收消息扩展字段获取到对方用户信息: userId=$userId, nickName=$nickName'); } return extendedInfo; } } } else if (message.direction == MessageDirection.SEND) { // 发送的消息:从扩展字段中提取接收者信息(receiver_ 前缀) // conversation.id 是对方用户ID,应该从发送的消息中提取接收者(对方)的信息 final toUserId = message.to; if (toUserId != null && toUserId == userId) { // 使用 receiver_ 前缀的字段(接收者信息) final nickName = attributes['receiver_nickName'] as String?; final avatarUrl = attributes['receiver_avatarUrl'] as String?; if (Get.isLogEnable) { Get.log('🔍 [ConversationController] 从发送消息提取接收者信息: msgId=${message.msgId}, toUserId=$toUserId, nickName=$nickName, avatarUrl=$avatarUrl'); } if (nickName != null || avatarUrl != null) { final extendedInfo = ExtendedUserInfo( userId: userId, nickName: nickName, avatarUrl: avatarUrl, ); _userInfoCache[userId] = extendedInfo; if (Get.isLogEnable) { Get.log('✅ [ConversationController] 从发送消息扩展字段获取到对方用户信息: userId=$userId, nickName=$nickName'); } return extendedInfo; } } } } if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] 在会话历史消息中未找到用户信息: userId=$userId'); } } } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] 从会话消息提取用户信息失败: $e'); } } // 3. 如果从消息扩展字段获取不到,尝试从环信获取用户信息(作为备选) try { var data = await IMManager.instance.getContacts(userId); var emUserInfo = data[userId]; if (emUserInfo != null && (emUserInfo.nickName?.isNotEmpty ?? false)) { final extendedInfo = ExtendedUserInfo.fromEMUserInfo(emUserInfo); _userInfoCache[userId] = extendedInfo; if (Get.isLogEnable) { Get.log('✅ [ConversationController] 从环信获取到用户信息: $userId, nickName=${extendedInfo.nickName}'); } return extendedInfo; } } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] 从环信获取用户信息失败: $e'); } } // 4. 如果都获取不到,返回一个基本的 ExtendedUserInfo(至少显示用户ID) final fallbackInfo = ExtendedUserInfo(userId: userId); _userInfoCache[userId] = fallbackInfo; if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] 未从任何来源获取到用户信息,使用默认值: $userId'); } return fallbackInfo; } catch (e) { if (Get.isLogEnable) { Get.log('❌ [ConversationController] 获取用户信息失败: $userId, 错误: $e'); } // 即使出错也返回一个基本的 ExtendedUserInfo final fallbackInfo = ExtendedUserInfo(userId: userId); _userInfoCache[userId] = fallbackInfo; return fallbackInfo; } } Future lastMessage(EMConversation conversation) async{ try { // 优先尝试从ChatController获取最后一条消息(如果ChatController还在内存中) // 这样可以获取到失败状态的消息(SDK可能不会保存失败消息) try { final tag = 'chat_${conversation.id}'; if (Get.isRegistered(tag: tag)) { final chatController = Get.find(tag: tag); if (chatController.messages.isNotEmpty) { // 获取最后一条消息(列表末尾,按时间戳排序后最后一条是最新的) // 注意:messages列表是按时间戳从旧到新排序的,所以last是最新的 final lastMsg = chatController.messages.last; if (Get.isLogEnable) { Get.log('✅ [ConversationController] 从ChatController获取最后一条消息: msgId=${lastMsg.msgId}, status=${lastMsg.status}, direction=${lastMsg.direction}, content=${lastMsg.body.type == MessageType.TXT ? (lastMsg.body as EMTextMessageBody).content : lastMsg.body.type}'); } return lastMsg; } } } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] 从ChatController获取最后一条消息失败: $e'); } } // 如果ChatController不存在或没有消息,从SDK获取 final sdkMessage = await conversation.latestMessage(); if (Get.isLogEnable) { if (sdkMessage != null) { Get.log('✅ [ConversationController] 从SDK获取最后一条消息: msgId=${sdkMessage.msgId}, status=${sdkMessage.status}, direction=${sdkMessage.direction}'); } else { Get.log('⚠️ [ConversationController] SDK返回的最后一条消息为null'); } } return sdkMessage; } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] 获取最后一条消息失败: $e'); } return null; } } /// 删除会话 Future deleteConversation(String conversationId) async { try { final success = await IMManager.instance.deleteConversation( conversationId, ); if (success) { conversations.removeWhere((element) => element.id == conversationId); } return success; } catch (e) { if (Get.isLogEnable) { Get.log('删除会话失败: $e'); } return false; } } /// 设置筛选类型 void setFilterType(FilterType type) { filterType.value = type; if (Get.isLogEnable) { Get.log('✅ [ConversationController] 设置筛选类型: $type'); } } /// 获取筛选后的会话列表 Future> getFilteredConversations() async { List filteredList = List.from(conversations); switch (filterType.value) { case FilterType.none: // 无筛选,按默认顺序返回 break; case FilterType.lastChatTime: // 按最后聊天时间排序(最新的在前) // 先获取所有消息的时间戳 final List> conversationTimes = await Future.wait( filteredList.map((conv) async { final message = await lastMessage(conv); final time = message?.serverTime ?? 0; return MapEntry(conv, time); }), ); // 按时间戳排序(降序,最新的在前) conversationTimes.sort((a, b) => b.value.compareTo(a.value)); filteredList = conversationTimes.map((entry) => entry.key).toList(); break; case FilterType.unread: // 只显示有未读消息的会话 final List> conversationUnreads = await Future.wait( filteredList.map((conv) async { final unreadCount = await getUnreadCount(conv); return MapEntry(conv, unreadCount); }), ); // 过滤出有未读消息的会话 final unreadConversations = conversationUnreads .where((entry) => entry.value > 0) .toList(); // 按未读数量排序(未读数多的在前) unreadConversations.sort((a, b) => b.value.compareTo(a.value)); filteredList = unreadConversations.map((entry) => entry.key).toList(); break; case FilterType.online: // 只显示在线用户的会话 final List onlineConversations = await Future.wait( filteredList.map((conv) async { final isOnline = await _checkUserOnline(conv); return isOnline ? conv : null; }), ); filteredList = onlineConversations .whereType() .toList(); break; } return filteredList; } /// 检查用户是否在线 Future _checkUserOnline(EMConversation conversation) async { try { // 获取会话的最新消息 final message = await lastMessage(conversation); if (message == null) { return false; } // 从消息扩展字段中获取在线状态 Map? attributes; try { attributes = message.attributes; } catch (e) { return false; } if (attributes == null || attributes.isEmpty) { return false; } // 检查在线状态字段 // 接收消息:检查 sender_isOnline // 发送消息:检查 receiver_isOnline String? isOnlineStr; String? lastActiveTimeStr; if (message.direction == MessageDirection.RECEIVE) { isOnlineStr = attributes['sender_isOnline'] as String?; lastActiveTimeStr = attributes['sender_lastActiveTime'] as String?; } else { isOnlineStr = attributes['receiver_isOnline'] as String?; lastActiveTimeStr = attributes['receiver_lastActiveTime'] as String?; } if (isOnlineStr == 'true') { // 进一步检查最后活跃时间(5分钟内认为在线) if (lastActiveTimeStr != null) { try { final lastActiveTime = int.parse(lastActiveTimeStr); final now = DateTime.now().millisecondsSinceEpoch; final diff = now - lastActiveTime; // 5分钟内认为在线(5 * 60 * 1000 毫秒) return diff < 5 * 60 * 1000; } catch (e) { // 解析失败,使用 isOnline 字段 return true; } } else { return true; } } return false; } catch (e) { if (Get.isLogEnable) { Get.log('⚠️ [ConversationController] 检查用户在线状态失败: $e'); } return false; } } }