Pinia 通过 state(messages、activeChatId、unreadMap、lastReadAtMap)、actions(addMessage、switchToChat、markAsRead)和 getters(totalUnreadCount、getUnreadByChatId、hasUnreadInActiveChat)统一管理聊天未读状态,并同步服务端与本地持久化。

Pinia 管理即时通讯聊天窗口中的未读消息状态,核心在于把“谁发了什么消息”“当前会话是谁”“哪些消息还没被对方看到或自己点开”这些信息集中建模、响应式更新,并与 UI 解耦。它不是只存一个数字,而是维护一套可推导、可追踪、可持久化的状态逻辑。
定义未读状态的核心字段
在 chat store 中,state 至少需包含:
- messages:消息数组,每条含 id、senderId、content、timestamp、isRead(布尔值,默认 false)
- activeChatId:当前打开的对话 ID,用于判断“当前是否在看这个会话”
-
unreadMap:对象格式,如
{ 'user_123': 5, 'group_456': 2 },记录每个会话的未读数 - lastReadAtMap:记录每个会话中用户最后阅读时间戳,用于服务端比对新消息
用 actions 实现未读数自动更新
未读状态不能靠手动加减,要靠业务动作触发逻辑更新:
- 收到新消息时:
addMessage(msg)判断若msg.senderId !== currentUser.id && activeChatId !== msg.chatId,则unreadMap[msg.chatId] = (unreadMap[msg.chatId] || 0) + 1 - 切换到某会话时:
switchToChat(chatId)把activeChatId设为该 ID,并清空对应unreadMap[chatId](设为 0),同时更新lastReadAtMap[chatId]为当前时间 - 批量已读(如群公告、系统消息):
markAsRead(chatId, beforeTimestamp)遍历 messages 标记符合条件的消息isRead = true,再重新统计未读数
用 getters 派生实时未读总数和会话级提示
避免在组件里重复计算,统一用 getters 输出:
-
totalUnreadCount:返回Object.values(unreadMap).reduce((a, b) => a + b, 0) -
getUnreadByChatId:接收 chatId 参数,返回unreadMap[chatId] || 0,供联系人列表显示红点 -
hasUnreadInActiveChat:返回!!unreadMap[activeChatId] && unreadMap[activeChatId] > 0,控制聊天窗口顶部是否显示“有未读消息”提示条
配合消息持久化与服务端同步
未读状态必须和服务端对齐,否则离线后会错乱:
- 初始化时调用
fetchUnreadStatus()action,从接口拉取最新unreadMap和lastReadAtMap - 每次标记已读后,主动调用 API 上报
markRead(chatId, timestamp),确保服务端也更新 - 使用 Pinia 插件(如
pinia-plugin-persistedstate)将unreadMap和lastReadAtMap存入 localStorage,重启页面不丢未读计数


















