修复消息未读数字

This commit is contained in:
619dev
2026-07-26 13:15:59 +08:00
parent 1393cf750d
commit 54beaaa6b3
3 changed files with 34 additions and 17 deletions

View File

@@ -159,13 +159,13 @@ export function useSocket() {
}
}
useStore.getState().addMessage(chatId, msgToAdd)
const isNewMessage = useStore.getState().addMessage(chatId, msgToAdd)
// If not on that chat page AND message is not from me, trigger notification
const isFromMe = data.from === myId
const isOnChat = window.location.pathname.includes(chatId)
if (!isFromMe && !isOnChat) {
if (isNewMessage && !isFromMe && !isOnChat) {
useStore.getState().incrementUnread(chatId)
// Skip all notifications for offline catch-up messages
@@ -221,7 +221,7 @@ export function useSocket() {
: `/chat/${chatId}`
}
)
} else if (!isFromMe && isOnChat) {
} else if (isNewMessage && !isFromMe && isOnChat) {
// On the chat page but still play a subtle sound for new messages
// (skip if it's a self message)
}

View File

@@ -310,6 +310,7 @@ export default function Chat() {
const user = useStore(s => s.user)
const messages = useStore(s => s.messages[id!] ?? EMPTY_MSGS)
const setMessages = useStore(s => s.setMessages)
const clearUnread = useStore(s => s.clearUnread)
const friends = useStore(s => s.friends)
const groups = useStore(s => s.groups)
const wsConnected = useStore(s => s.wsConnected)
@@ -385,6 +386,12 @@ export default function Chat() {
}
// ── Load history + decrypt + merge with cache ──
useEffect(() => {
// A chat can be opened from a push/toast or a deep link, bypassing the
// conversation-list click handler that also clears this counter.
if (id) clearUnread(id)
}, [id, clearUnread])
useEffect(() => {
if (!id) return
const path = isGroup ? `/api/messages/group/${id}?limit=50000` : `/api/messages/private/${id}?limit=50000`

View File

@@ -163,7 +163,11 @@ interface AppStore {
// Chat Messages (keyed by chatId)
messages: Record<string, ChatMessage[]>
addMessage: (chatId: string, msg: ChatMessage) => void
/**
* Adds a message if its server ID is not already cached.
* Returns true only when the message was actually inserted.
*/
addMessage: (chatId: string, msg: ChatMessage) => boolean
updateMessage: (chatId: string, msgId: string, patch: Partial<ChatMessage>) => void
setMessages: (chatId: string, msgs: ChatMessage[]) => void
prependMessages: (chatId: string, msgs: ChatMessage[]) => void
@@ -305,19 +309,25 @@ export const useStore = create<AppStore>((set, get) => ({
// Messages (initialized from localStorage cache)
messages: loadCachedMessages(),
addMessage: (chatId, msg) => set(s => {
const existing = s.messages[chatId] || []
// Deduplicate by message ID
if (msg.id && existing.some(m => m.id === msg.id)) {
return s // skip duplicate
}
const updated = {
...s.messages,
[chatId]: [...existing, msg],
}
persistMessages(updated)
return { messages: updated }
}),
addMessage: (chatId, msg) => {
let inserted = false
set(s => {
const existing = s.messages[chatId] || []
// Offline messages are replayed after every reconnect. Keep insertion
// and its return value atomic so callers do not count a replay as new.
if (msg.id && existing.some(m => m.id === msg.id)) {
return s
}
const updated = {
...s.messages,
[chatId]: [...existing, msg],
}
inserted = true
persistMessages(updated)
return { messages: updated }
})
return inserted
},
updateMessage: (chatId, msgId, patch) => set(s => {
const msgs = s.messages[chatId]
if (!msgs) return s