✨ feat(im): 增加频道消息的已读状态
parent
30b963149a
commit
fc812aef26
|
|
@ -6,6 +6,7 @@ export interface ImManagerChannelMessageVO {
|
|||
channelName?: string
|
||||
materialId: number
|
||||
materialTitle?: string
|
||||
materialCoverUrl?: string
|
||||
type: number
|
||||
content?: string
|
||||
receiverUserIds?: number[]
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ export interface ImChannelMessageRespVO {
|
|||
materialId: number
|
||||
type: number
|
||||
content: string
|
||||
/** 当前用户已读态;pull 时按 Redis 游标计算填充,多端同步使用 */
|
||||
status?: number
|
||||
sendTime: string
|
||||
}
|
||||
|
||||
|
|
@ -16,3 +18,11 @@ export const pullChannelMessages = (params: { minId: number; size?: number }) =>
|
|||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 上报频道消息已读位置;切到频道会话或拉到新消息后调
|
||||
export const readChannelMessages = (channelId: number, messageId: number) => {
|
||||
return request.put({
|
||||
url: '/im/channel/message/read',
|
||||
params: { channelId, messageId }
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import {
|
|||
} from '@/api/im/message/channel'
|
||||
import {
|
||||
ImConversationType,
|
||||
ImMessageStatus,
|
||||
ImMessageType,
|
||||
isFriendChatTip,
|
||||
isFriendNotification
|
||||
|
|
@ -96,7 +97,7 @@ export const useMessagePuller = () => {
|
|||
clientMessageId: '',
|
||||
type: message.type,
|
||||
content: message.content,
|
||||
status: 0, // 频道消息无状态机;占位 UNREAD
|
||||
status: message.status ?? ImMessageStatus.UNREAD,
|
||||
sendTime: new Date(message.sendTime).getTime(),
|
||||
senderId: 0, // 系统下发,无发送人
|
||||
targetId: message.channelId, // 会话归属到频道编号
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {
|
|||
readGroupMessages as apiReadGroupMessages,
|
||||
recallGroupMessage as apiRecallGroupMessage
|
||||
} from '@/api/im/message/group'
|
||||
import { readChannelMessages as apiReadChannelMessages } from '@/api/im/message/channel'
|
||||
import {
|
||||
generateClientMessageId,
|
||||
serializeMessage,
|
||||
|
|
@ -233,19 +234,24 @@ export const useMessageSender = () => {
|
|||
// 接口调用:按会话类型分发,并按对应已读开关控制;失败仅记录日志,不回退本地已读状态
|
||||
const isPrivate = conversation.type === ImConversationType.PRIVATE
|
||||
const isGroup = conversation.type === ImConversationType.GROUP
|
||||
// 频道目前不上报已读
|
||||
// TODO @AI:频道已读,应该还是要上报的,同步到别的端。但是不用记录 status 字段。
|
||||
if (!isPrivate && !isGroup) {
|
||||
const isChannel = conversation.type === ImConversationType.CHANNEL
|
||||
if (!isPrivate && !isGroup && !isChannel) {
|
||||
return
|
||||
}
|
||||
const readEnabled = isPrivate ? MESSAGE_PRIVATE_READ_ENABLED : MESSAGE_GROUP_READ_ENABLED
|
||||
if (!readEnabled) {
|
||||
if (isPrivate && !MESSAGE_PRIVATE_READ_ENABLED) {
|
||||
return
|
||||
}
|
||||
if (isGroup && !MESSAGE_GROUP_READ_ENABLED) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
await (isPrivate
|
||||
? apiReadPrivateMessages(conversation.targetId, maxMessageId)
|
||||
: apiReadGroupMessages(conversation.targetId, maxMessageId))
|
||||
if (isPrivate) {
|
||||
await apiReadPrivateMessages(conversation.targetId, maxMessageId)
|
||||
} else if (isGroup) {
|
||||
await apiReadGroupMessages(conversation.targetId, maxMessageId)
|
||||
} else {
|
||||
await apiReadChannelMessages(conversation.targetId, maxMessageId)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(
|
||||
'[IM] 标记已读失败',
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { useUserStore } from '@/store/modules/user'
|
|||
|
||||
import {
|
||||
ImWebSocketMessageType,
|
||||
ImMessageStatus,
|
||||
ImMessageType,
|
||||
ImConversationType,
|
||||
ImRtcParticipantStatus,
|
||||
|
|
@ -213,13 +214,37 @@ export const useImWebSocketStore = defineStore('imWebSocketStore', {
|
|||
this.dispatchGroupFrame(content as ImGroupMessageDTO)
|
||||
break
|
||||
case ImWebSocketMessageType.CHANNEL_MESSAGE:
|
||||
this.handleChannelMessage(content as ImChannelMessageRespVO)
|
||||
this.dispatchChannelFrame(content as ImChannelMessageRespVO)
|
||||
break
|
||||
default:
|
||||
console.debug('[IM WS] 未识别事件', frame)
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 频道帧分发:按 payload.type 分到 READ(多端已读同步)或普通素材推送
|
||||
*/
|
||||
dispatchChannelFrame(websocketMessage: ImChannelMessageRespVO) {
|
||||
if (websocketMessage.type === ImMessageType.READ) {
|
||||
this.handleChannelRead(websocketMessage)
|
||||
return
|
||||
}
|
||||
this.handleChannelMessage(websocketMessage)
|
||||
},
|
||||
|
||||
/** 频道 READ:自己其它终端在某频道里标为已读,本端同步清零该频道未读 */
|
||||
handleChannelRead(websocketMessage: ImChannelMessageRespVO) {
|
||||
const conversationStore = useConversationStore()
|
||||
const conversation = conversationStore.getConversation(
|
||||
ImConversationType.CHANNEL,
|
||||
websocketMessage.channelId
|
||||
)
|
||||
if (conversation) {
|
||||
conversation.unreadCount = 0
|
||||
}
|
||||
conversationStore.saveConversations()
|
||||
},
|
||||
|
||||
/**
|
||||
* 频道消息实时入会话;频道消息单向 + 无状态机,直接 insertMessage 即可
|
||||
* pull 与 WS 拿到同一条 id 时,conversationStore.insertMessage 内部按 id 去重,不会重复
|
||||
|
|
@ -245,7 +270,7 @@ export const useImWebSocketStore = defineStore('imWebSocketStore', {
|
|||
clientMessageId: '',
|
||||
type: websocketMessage.type,
|
||||
content: websocketMessage.content,
|
||||
status: 0,
|
||||
status: ImMessageStatus.UNREAD,
|
||||
sendTime: sendTimeMs,
|
||||
senderId: 0,
|
||||
targetId: websocketMessage.channelId,
|
||||
|
|
|
|||
Loading…
Reference in New Issue