refactor(ConversationList): streamline conversation list handling and enhance unread count management
- Removed debug display for unread count in ConversationListRow to clean up UI. - Updated updateConversationCacheUnreadCount to optionally handle myLastReadSeq for better synchronization of read status. - Refactored message service to unify offset and cursor pagination methods, improving data fetching consistency. - Introduced a new method to normalize unread counts based on read cursor, ensuring accurate display of unread messages. - Consolidated conversation list source implementations to simplify remote data fetching logic.
This commit is contained in:
@@ -353,6 +353,18 @@ class MessageManager {
|
||||
this.state.conversationList = list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当已读游标已追上 last_seq 时,强制未读为 0(修复本地 SQLite 中 unread_count 与已读状态不一致)
|
||||
*/
|
||||
private normalizeConversationUnreadFromReadCursor(conv: ConversationResponse): ConversationResponse {
|
||||
const lastSeq = Number(conv.last_seq || 0);
|
||||
const myRead = Number(conv.my_last_read_seq ?? 0);
|
||||
if (lastSeq > 0 && myRead >= lastSeq && (conv.unread_count || 0) > 0) {
|
||||
return { ...conv, unread_count: 0 };
|
||||
}
|
||||
return conv;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将游标接口返回的单条会话写入 Map(统一 string id、尊重 pendingReadMap 已读保护)
|
||||
*/
|
||||
@@ -368,6 +380,7 @@ class MessageManager {
|
||||
} else {
|
||||
next = { ...conv, id };
|
||||
}
|
||||
next = this.normalizeConversationUnreadFromReadCursor(next);
|
||||
this.state.conversations.set(id, next);
|
||||
}
|
||||
|
||||
@@ -776,14 +789,6 @@ class MessageManager {
|
||||
const normalizedConversationId = this.normalizeConversationId(conversation_id);
|
||||
const currentUserId = this.getCurrentUserId();
|
||||
|
||||
// 【调试日志】追踪消息来源和重复问题
|
||||
|
||||
// 0. 如果是ACK消息,直接跳过不增加未读数(ACK是发送确认,不是新消息)
|
||||
if (_isAck) {
|
||||
// 但仍然需要更新消息列表(因为ACK包含完整消息内容)
|
||||
// 继续处理但不增加未读数
|
||||
}
|
||||
|
||||
// 1. 消息去重检查 - 防止ACK消息和正常消息重复处理
|
||||
if (this.isMessageProcessed(id)) {
|
||||
return;
|
||||
@@ -813,7 +818,6 @@ class MessageManager {
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}).catch(error => {
|
||||
console.error('[MessageManager][ERROR] 获取发送者信息失败:', { userId: sender_id, error });
|
||||
@@ -858,16 +862,13 @@ class MessageManager {
|
||||
const isCurrentUserMessage = sender_id === currentUserId;
|
||||
const isActiveConversation = normalizedConversationId === this.state.currentConversationId;
|
||||
|
||||
// 【调试日志】追踪未读数增加逻辑
|
||||
|
||||
// 修复:确保当前用户发送的消息不会增加未读数
|
||||
// 确保当前用户发送的消息不会增加未读数
|
||||
// 同时确保currentUserId有效(避免undefined === undefined的情况)
|
||||
// ACK消息(发送确认)也不应该增加未读数
|
||||
const shouldIncrementUnread = !isCurrentUserMessage && !isActiveConversation && !!currentUserId && !_isAck;
|
||||
|
||||
if (shouldIncrementUnread) {
|
||||
this.incrementUnreadCount(normalizedConversationId);
|
||||
} else {
|
||||
}
|
||||
|
||||
// 6. 如果是当前活动会话,自动标记已读
|
||||
@@ -1315,9 +1316,11 @@ class MessageManager {
|
||||
const isPending = !!readRecord;
|
||||
// 使用智能合并:如果服务器返回 unread_count > 0 但本地有更晚的已读记录,保留本地状态
|
||||
const shouldPreserveLocalRead = isPending && (detail.unread_count || 0) > 0;
|
||||
const safeDetail = shouldPreserveLocalRead
|
||||
? { ...(detail as ConversationResponse), id: normalizedId, unread_count: 0 }
|
||||
: { ...(detail as ConversationResponse), id: normalizedId };
|
||||
const safeDetail = this.normalizeConversationUnreadFromReadCursor(
|
||||
shouldPreserveLocalRead
|
||||
? { ...(detail as ConversationResponse), id: normalizedId, unread_count: 0 }
|
||||
: { ...(detail as ConversationResponse), id: normalizedId }
|
||||
);
|
||||
this.state.conversations.set(normalizedId, safeDetail);
|
||||
this.updateConversationList();
|
||||
|
||||
@@ -1681,6 +1684,25 @@ class MessageManager {
|
||||
this.state.totalUnreadCount = unreadData?.total_unread_count ?? 0;
|
||||
this.state.systemUnreadCount = systemUnreadData?.unread_count ?? 0;
|
||||
|
||||
// 服务端汇总未读为 0 时,清掉内存/本地缓存中残留的逐会话红点(常见于仅暖机了 SQLite 旧数据)
|
||||
if (this.state.totalUnreadCount === 0 && this.state.conversations.size > 0) {
|
||||
let anyCleared = false;
|
||||
for (const [cid, conv] of this.state.conversations) {
|
||||
if ((conv.unread_count || 0) > 0) {
|
||||
this.state.conversations.set(cid, { ...conv, unread_count: 0 });
|
||||
anyCleared = true;
|
||||
}
|
||||
}
|
||||
if (anyCleared) {
|
||||
this.updateConversationList();
|
||||
this.persistConversationListCache();
|
||||
this.notifySubscribers({
|
||||
type: 'conversations_updated',
|
||||
payload: { conversations: this.state.conversationList },
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.notifySubscribers({
|
||||
type: 'unread_count_updated',
|
||||
@@ -1824,10 +1846,11 @@ class MessageManager {
|
||||
lastReadSeq: seq,
|
||||
});
|
||||
|
||||
// 2. 乐观更新本地状态(立即反映到UI)
|
||||
// 2. 乐观更新本地状态(立即反映到UI;同步已读游标避免与 last_seq 不一致)
|
||||
const updatedConv: ConversationResponse = {
|
||||
...conversation,
|
||||
unread_count: 0,
|
||||
my_last_read_seq: Math.max(Number(conversation.my_last_read_seq || 0), seq),
|
||||
};
|
||||
this.state.conversations.set(normalizedId, updatedConv);
|
||||
this.state.totalUnreadCount = Math.max(0, this.state.totalUnreadCount - prevUnreadCount);
|
||||
|
||||
Reference in New Issue
Block a user