fix(im):同步已读补上报字段与群通话竞态修复
- web-antd、web-antdv-next、web-ele 同步 reportedReadMessageId 字段 - 避免旧 readMessageId 本地缓存污染 read API 跳过判断 - RTC_CALL_END 按 room 移除群通话胶囊,避免旧房间结束事件误删新房间通话 - participantsLoaded 仅在同 room 下继承,避免新房间误跳过参与者补齐pull/367/head
parent
09b97f1e04
commit
010da63c7c
|
|
@ -87,7 +87,7 @@ function toConversationDO(conversation: Conversation): ConversationDO {
|
|||
lastReceiptStatus: conversation.lastReceiptStatus,
|
||||
lastSelfSend: conversation.lastSelfSend,
|
||||
lastSenderDisplayName: conversation.lastSenderDisplayName,
|
||||
readMessageId: conversation.readMessageId,
|
||||
reportedReadMessageId: conversation.reportedReadMessageId,
|
||||
deleted: conversation.deleted,
|
||||
top: conversation.top,
|
||||
silent: conversation.silent,
|
||||
|
|
@ -338,7 +338,7 @@ export const useConversationStore = defineStore('imConversationStore', {
|
|||
return false
|
||||
}
|
||||
const conversation = this.getConversation(type, targetId)
|
||||
return (conversation?.readMessageId || 0) >= messageId
|
||||
return (conversation?.reportedReadMessageId || 0) >= messageId
|
||||
},
|
||||
|
||||
/** 应用读位置到会话 */
|
||||
|
|
@ -395,8 +395,8 @@ export const useConversationStore = defineStore('imConversationStore', {
|
|||
const current = this.conversationReads[clientConversationId]
|
||||
const messageId = Math.max(record.messageId, current?.messageId || 0)
|
||||
const conversation = this.getConversation(record.conversationType, record.targetId)
|
||||
if (conversation && record.messageId > (conversation.readMessageId || 0)) {
|
||||
conversation.readMessageId = record.messageId
|
||||
if (conversation && record.messageId > (conversation.reportedReadMessageId || 0)) {
|
||||
conversation.reportedReadMessageId = record.messageId
|
||||
changedConversations.set(clientConversationId, conversation)
|
||||
}
|
||||
if (!current || messageId > current.messageId) {
|
||||
|
|
@ -741,10 +741,10 @@ export const useConversationStore = defineStore('imConversationStore', {
|
|||
return
|
||||
}
|
||||
const conversation = this.getConversation(type, targetId)
|
||||
if (!conversation || messageId <= (conversation.readMessageId || 0)) {
|
||||
if (!conversation || messageId <= (conversation.reportedReadMessageId || 0)) {
|
||||
return
|
||||
}
|
||||
conversation.readMessageId = messageId
|
||||
conversation.reportedReadMessageId = messageId
|
||||
this.saveConversation(conversation)
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -263,7 +263,8 @@ export const useRtcStore = defineStore('imRtc', () => {
|
|||
useGroupStore().markGroupActiveCallLoaded(payload.groupId)
|
||||
// 浅比较:room / mediaType / joinedUserIds / inviteeIds 都没变就跳过,避免下游 watcher 无意义重算
|
||||
const existing = groupActiveCalls.value.get(payload.groupId)
|
||||
const nextParticipantsLoaded = participantsLoaded ?? !!existing?.participantsLoaded
|
||||
const nextParticipantsLoaded =
|
||||
participantsLoaded ?? (existing?.room === payload.room && !!existing.participantsLoaded)
|
||||
if (
|
||||
existing &&
|
||||
isSameGroupCall(existing, payload) &&
|
||||
|
|
@ -320,10 +321,14 @@ export const useRtcStore = defineStore('imRtc', () => {
|
|||
}
|
||||
|
||||
/** 群通话结束:从 groupActiveCalls 移除;胶囊条消失 */
|
||||
function removeGroupCall(groupId: number) {
|
||||
function removeGroupCall(groupId: number, room?: string) {
|
||||
if (!groupId) {
|
||||
return
|
||||
}
|
||||
const existing = groupActiveCalls.value.get(groupId)
|
||||
if (room && existing?.room !== room) {
|
||||
return
|
||||
}
|
||||
clearGroupCallCache(groupId)
|
||||
useGroupStore().markGroupActiveCallLoaded(groupId)
|
||||
}
|
||||
|
|
@ -407,7 +412,7 @@ export const useRtcStore = defineStore('imRtc', () => {
|
|||
return
|
||||
}
|
||||
if (nextJoined.length === 0 && nextInvitee.length === 0) {
|
||||
removeGroupCall(groupId)
|
||||
removeGroupCall(groupId, room)
|
||||
return
|
||||
}
|
||||
setGroupCall({
|
||||
|
|
|
|||
|
|
@ -1230,10 +1230,10 @@ export const useImWebSocketStore = defineStore('imWebSocketStore', {
|
|||
}
|
||||
const rtcStore = useRtcStore()
|
||||
const isGroup = payload.conversationType === ImConversationType.GROUP
|
||||
// 群通话:移除胶囊条(按外层 groupId 取,不依赖 payload)
|
||||
// 群通话:移除对应房间的胶囊条
|
||||
const groupId = (websocketMessage as ImGroupMessageNotification).groupId
|
||||
if (isGroup && groupId) {
|
||||
rtcStore.removeGroupCall(groupId)
|
||||
rtcStore.removeGroupCall(groupId, payload.room)
|
||||
}
|
||||
// 通话窗 / 来电窗指向同一 room 时关闭:
|
||||
// RUNNING / INVITING 阶段对比 call.room;INCOMING 阶段对比 incomingPayload.room
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ export interface Conversation {
|
|||
silent?: boolean // 是否免打扰(不展示未读徽标 + 不响提示音)
|
||||
atMe?: boolean // 群聊:是否有人 @我
|
||||
atAll?: boolean // 群聊:是否有人 @全体成员
|
||||
readMessageId?: number // 已上报到服务端的最大已读消息编号
|
||||
reportedReadMessageId?: number // 已上报到服务端的最大已读消息编号
|
||||
draft?: {
|
||||
html: string // 输入框 HTML
|
||||
plain: string // 输入框纯文本
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ function toConversationDO(conversation: Conversation): ConversationDO {
|
|||
lastReceiptStatus: conversation.lastReceiptStatus,
|
||||
lastSelfSend: conversation.lastSelfSend,
|
||||
lastSenderDisplayName: conversation.lastSenderDisplayName,
|
||||
readMessageId: conversation.readMessageId,
|
||||
reportedReadMessageId: conversation.reportedReadMessageId,
|
||||
deleted: conversation.deleted,
|
||||
top: conversation.top,
|
||||
silent: conversation.silent,
|
||||
|
|
@ -338,7 +338,7 @@ export const useConversationStore = defineStore('imConversationStore', {
|
|||
return false
|
||||
}
|
||||
const conversation = this.getConversation(type, targetId)
|
||||
return (conversation?.readMessageId || 0) >= messageId
|
||||
return (conversation?.reportedReadMessageId || 0) >= messageId
|
||||
},
|
||||
|
||||
/** 应用读位置到会话 */
|
||||
|
|
@ -395,8 +395,8 @@ export const useConversationStore = defineStore('imConversationStore', {
|
|||
const current = this.conversationReads[clientConversationId]
|
||||
const messageId = Math.max(record.messageId, current?.messageId || 0)
|
||||
const conversation = this.getConversation(record.conversationType, record.targetId)
|
||||
if (conversation && record.messageId > (conversation.readMessageId || 0)) {
|
||||
conversation.readMessageId = record.messageId
|
||||
if (conversation && record.messageId > (conversation.reportedReadMessageId || 0)) {
|
||||
conversation.reportedReadMessageId = record.messageId
|
||||
changedConversations.set(clientConversationId, conversation)
|
||||
}
|
||||
if (!current || messageId > current.messageId) {
|
||||
|
|
@ -741,10 +741,10 @@ export const useConversationStore = defineStore('imConversationStore', {
|
|||
return
|
||||
}
|
||||
const conversation = this.getConversation(type, targetId)
|
||||
if (!conversation || messageId <= (conversation.readMessageId || 0)) {
|
||||
if (!conversation || messageId <= (conversation.reportedReadMessageId || 0)) {
|
||||
return
|
||||
}
|
||||
conversation.readMessageId = messageId
|
||||
conversation.reportedReadMessageId = messageId
|
||||
this.saveConversation(conversation)
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -263,7 +263,8 @@ export const useRtcStore = defineStore('imRtc', () => {
|
|||
useGroupStore().markGroupActiveCallLoaded(payload.groupId)
|
||||
// 浅比较:room / mediaType / joinedUserIds / inviteeIds 都没变就跳过,避免下游 watcher 无意义重算
|
||||
const existing = groupActiveCalls.value.get(payload.groupId)
|
||||
const nextParticipantsLoaded = participantsLoaded ?? !!existing?.participantsLoaded
|
||||
const nextParticipantsLoaded =
|
||||
participantsLoaded ?? (existing?.room === payload.room && !!existing.participantsLoaded)
|
||||
if (
|
||||
existing &&
|
||||
isSameGroupCall(existing, payload) &&
|
||||
|
|
@ -320,10 +321,14 @@ export const useRtcStore = defineStore('imRtc', () => {
|
|||
}
|
||||
|
||||
/** 群通话结束:从 groupActiveCalls 移除;胶囊条消失 */
|
||||
function removeGroupCall(groupId: number) {
|
||||
function removeGroupCall(groupId: number, room?: string) {
|
||||
if (!groupId) {
|
||||
return
|
||||
}
|
||||
const existing = groupActiveCalls.value.get(groupId)
|
||||
if (room && existing?.room !== room) {
|
||||
return
|
||||
}
|
||||
clearGroupCallCache(groupId)
|
||||
useGroupStore().markGroupActiveCallLoaded(groupId)
|
||||
}
|
||||
|
|
@ -407,7 +412,7 @@ export const useRtcStore = defineStore('imRtc', () => {
|
|||
return
|
||||
}
|
||||
if (nextJoined.length === 0 && nextInvitee.length === 0) {
|
||||
removeGroupCall(groupId)
|
||||
removeGroupCall(groupId, room)
|
||||
return
|
||||
}
|
||||
setGroupCall({
|
||||
|
|
|
|||
|
|
@ -1230,10 +1230,10 @@ export const useImWebSocketStore = defineStore('imWebSocketStore', {
|
|||
}
|
||||
const rtcStore = useRtcStore()
|
||||
const isGroup = payload.conversationType === ImConversationType.GROUP
|
||||
// 群通话:移除胶囊条(按外层 groupId 取,不依赖 payload)
|
||||
// 群通话:移除对应房间的胶囊条
|
||||
const groupId = (websocketMessage as ImGroupMessageNotification).groupId
|
||||
if (isGroup && groupId) {
|
||||
rtcStore.removeGroupCall(groupId)
|
||||
rtcStore.removeGroupCall(groupId, payload.room)
|
||||
}
|
||||
// 通话窗 / 来电窗指向同一 room 时关闭:
|
||||
// RUNNING / INVITING 阶段对比 call.room;INCOMING 阶段对比 incomingPayload.room
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ export interface Conversation {
|
|||
silent?: boolean // 是否免打扰(不展示未读徽标 + 不响提示音)
|
||||
atMe?: boolean // 群聊:是否有人 @我
|
||||
atAll?: boolean // 群聊:是否有人 @全体成员
|
||||
readMessageId?: number // 已上报到服务端的最大已读消息编号
|
||||
reportedReadMessageId?: number // 已上报到服务端的最大已读消息编号
|
||||
draft?: {
|
||||
html: string // 输入框 HTML
|
||||
plain: string // 输入框纯文本
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ function toConversationDO(conversation: Conversation): ConversationDO {
|
|||
lastReceiptStatus: conversation.lastReceiptStatus,
|
||||
lastSelfSend: conversation.lastSelfSend,
|
||||
lastSenderDisplayName: conversation.lastSenderDisplayName,
|
||||
readMessageId: conversation.readMessageId,
|
||||
reportedReadMessageId: conversation.reportedReadMessageId,
|
||||
deleted: conversation.deleted,
|
||||
top: conversation.top,
|
||||
silent: conversation.silent,
|
||||
|
|
@ -338,7 +338,7 @@ export const useConversationStore = defineStore('imConversationStore', {
|
|||
return false
|
||||
}
|
||||
const conversation = this.getConversation(type, targetId)
|
||||
return (conversation?.readMessageId || 0) >= messageId
|
||||
return (conversation?.reportedReadMessageId || 0) >= messageId
|
||||
},
|
||||
|
||||
/** 应用读位置到会话 */
|
||||
|
|
@ -395,8 +395,8 @@ export const useConversationStore = defineStore('imConversationStore', {
|
|||
const current = this.conversationReads[clientConversationId]
|
||||
const messageId = Math.max(record.messageId, current?.messageId || 0)
|
||||
const conversation = this.getConversation(record.conversationType, record.targetId)
|
||||
if (conversation && record.messageId > (conversation.readMessageId || 0)) {
|
||||
conversation.readMessageId = record.messageId
|
||||
if (conversation && record.messageId > (conversation.reportedReadMessageId || 0)) {
|
||||
conversation.reportedReadMessageId = record.messageId
|
||||
changedConversations.set(clientConversationId, conversation)
|
||||
}
|
||||
if (!current || messageId > current.messageId) {
|
||||
|
|
@ -741,10 +741,10 @@ export const useConversationStore = defineStore('imConversationStore', {
|
|||
return
|
||||
}
|
||||
const conversation = this.getConversation(type, targetId)
|
||||
if (!conversation || messageId <= (conversation.readMessageId || 0)) {
|
||||
if (!conversation || messageId <= (conversation.reportedReadMessageId || 0)) {
|
||||
return
|
||||
}
|
||||
conversation.readMessageId = messageId
|
||||
conversation.reportedReadMessageId = messageId
|
||||
this.saveConversation(conversation)
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -263,7 +263,8 @@ export const useRtcStore = defineStore('imRtc', () => {
|
|||
useGroupStore().markGroupActiveCallLoaded(payload.groupId)
|
||||
// 浅比较:room / mediaType / joinedUserIds / inviteeIds 都没变就跳过,避免下游 watcher 无意义重算
|
||||
const existing = groupActiveCalls.value.get(payload.groupId)
|
||||
const nextParticipantsLoaded = participantsLoaded ?? !!existing?.participantsLoaded
|
||||
const nextParticipantsLoaded =
|
||||
participantsLoaded ?? (existing?.room === payload.room && !!existing.participantsLoaded)
|
||||
if (
|
||||
existing &&
|
||||
isSameGroupCall(existing, payload) &&
|
||||
|
|
@ -320,10 +321,14 @@ export const useRtcStore = defineStore('imRtc', () => {
|
|||
}
|
||||
|
||||
/** 群通话结束:从 groupActiveCalls 移除;胶囊条消失 */
|
||||
function removeGroupCall(groupId: number) {
|
||||
function removeGroupCall(groupId: number, room?: string) {
|
||||
if (!groupId) {
|
||||
return
|
||||
}
|
||||
const existing = groupActiveCalls.value.get(groupId)
|
||||
if (room && existing?.room !== room) {
|
||||
return
|
||||
}
|
||||
clearGroupCallCache(groupId)
|
||||
useGroupStore().markGroupActiveCallLoaded(groupId)
|
||||
}
|
||||
|
|
@ -407,7 +412,7 @@ export const useRtcStore = defineStore('imRtc', () => {
|
|||
return
|
||||
}
|
||||
if (nextJoined.length === 0 && nextInvitee.length === 0) {
|
||||
removeGroupCall(groupId)
|
||||
removeGroupCall(groupId, room)
|
||||
return
|
||||
}
|
||||
setGroupCall({
|
||||
|
|
|
|||
|
|
@ -1230,10 +1230,10 @@ export const useImWebSocketStore = defineStore('imWebSocketStore', {
|
|||
}
|
||||
const rtcStore = useRtcStore()
|
||||
const isGroup = payload.conversationType === ImConversationType.GROUP
|
||||
// 群通话:移除胶囊条(按外层 groupId 取,不依赖 payload)
|
||||
// 群通话:移除对应房间的胶囊条
|
||||
const groupId = (websocketMessage as ImGroupMessageNotification).groupId
|
||||
if (isGroup && groupId) {
|
||||
rtcStore.removeGroupCall(groupId)
|
||||
rtcStore.removeGroupCall(groupId, payload.room)
|
||||
}
|
||||
// 通话窗 / 来电窗指向同一 room 时关闭:
|
||||
// RUNNING / INVITING 阶段对比 call.room;INCOMING 阶段对比 incomingPayload.room
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ export interface Conversation {
|
|||
silent?: boolean // 是否免打扰(不展示未读徽标 + 不响提示音)
|
||||
atMe?: boolean // 群聊:是否有人 @我
|
||||
atAll?: boolean // 群聊:是否有人 @全体成员
|
||||
readMessageId?: number // 已上报到服务端的最大已读消息编号
|
||||
reportedReadMessageId?: number // 已上报到服务端的最大已读消息编号
|
||||
draft?: {
|
||||
html: string // 输入框 HTML
|
||||
plain: string // 输入框纯文本
|
||||
|
|
|
|||
Loading…
Reference in New Issue