新增消息已读状态

复用 chat_participants.last_read_at 推导已读,无需新表/迁移。

- 后端:MessageDTO 增加 is_read,toMessageDTOs 按「全部已读」语义计算
  (所有其他参与者均已读才算已读,1对1 即对方已读);MarkRead 成功后
  推送 conversation_read 事件(含 reader 与 read_at),NotifyConversation
  与 NotifyAllAdmins 双通道通知,使发送方/客服实时刷新已读
- 前端:ChatMessage 增加 is_read,ChatView/AdminChatsView/MobileChatView
  在自己的消息下渲染「已读/未读」;收到 conversation_read 且本端仍有
  未获回执的自己消息时才重载,避免无谓请求

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
yml2213
2026-06-16 22:22:05 +08:00
co-authored by Claude Opus 4.8
parent cc1c0d33de
commit e75a39b03a
9 changed files with 174 additions and 6 deletions
+5 -1
View File
@@ -9,9 +9,13 @@ import (
// ChatEvent 是通过 SSE 推送给客户端的事件。
type ChatEvent struct {
Type string `json:"type"` // "new_message" | "conversation_updated"
Type string `json:"type"` // "new_message" | "conversation_updated" | "conversation_read"
ConversationID uint64 `json:"conversation_id"`
Message *MessageData `json:"message,omitempty"`
// 以下字段仅在 conversation_read 事件中使用,标识谁在何时读取了会话。
ReaderType string `json:"reader_type,omitempty"`
ReaderID uint64 `json:"reader_id,omitempty"`
ReadAt string `json:"read_at,omitempty"`
}
// MessageData 是事件中携带的消息数据,与 chat.MessageDTO 对齐。