🐛 fix(im):codex 评审修复 FRIEND_ADD / FRIEND_DELETE 接收方 peer 与 clear 气泡
- FRIEND_ADD 接收方 peer 改按帧 sender / receiver 反推:becomeFriends 单条入库后双方收到同一份 payload,payload.friendUserId 固定是 toUserId,本端真正的对端要看自己是 sender 还是 receiver;新增 websocketStore.computeFriendPeerId 算好后传给 friendStore.applyFriendAdd/DeleteNotification - FRIEND_DELETE clear=true 跳过气泡插入:clear 语义是清会话本身,气泡分支按 isFriendDeleteWithClear 校验,避免在已清会话里写虚拟消息 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>im
parent
c653c2fa2b
commit
5bd99c53c2
|
|
@ -437,14 +437,21 @@ export const useFriendStore = defineStore('imFriendStore', {
|
|||
)
|
||||
},
|
||||
|
||||
/** FRIEND_ADD(1204):新增好友;本端拉取好友详情并入库 */
|
||||
applyFriendAddNotification(payload: FriendNotificationPayload) {
|
||||
void this.loadFriendInfo(payload.friendUserId)
|
||||
/**
|
||||
* FRIEND_ADD(1204):新增好友;本端拉取好友详情并入库
|
||||
* peerUserId 由 websocketStore 按帧 sender / receiver 算好传入:becomeFriends 单条入库后双方收到同一份 payload,
|
||||
* 本端真正的「对端」是帧上的另一个用户,不是 payload.friendUserId(payload 里固定是 toUserId)。
|
||||
*/
|
||||
applyFriendAddNotification(_payload: FriendNotificationPayload, peerUserId: number) {
|
||||
void this.loadFriendInfo(peerUserId)
|
||||
},
|
||||
|
||||
/** FRIEND_DELETE(1205):好友被删除;本端清理 + 按 payload.clear 决定是否级联清会话(多端跟主操作端一致) */
|
||||
applyFriendDeleteNotification(payload: FriendNotificationPayload) {
|
||||
this.removeFriend(payload.friendUserId, payload.clear !== false)
|
||||
/**
|
||||
* FRIEND_DELETE(1205):好友被删除;本端清理 + 按 payload.clear 决定是否级联清会话(多端跟主操作端一致)
|
||||
* peerUserId 由 websocketStore 按帧 sender / receiver 算好传入;与 FRIEND_ADD 保持一致的 peer 推断
|
||||
*/
|
||||
applyFriendDeleteNotification(payload: FriendNotificationPayload, peerUserId: number) {
|
||||
this.removeFriend(peerUserId, payload.clear !== false)
|
||||
},
|
||||
|
||||
/** FRIEND_BLOCK(1207):拉黑;多端同步 */
|
||||
|
|
|
|||
|
|
@ -26,6 +26,19 @@ import type {
|
|||
Group
|
||||
} from '../types'
|
||||
|
||||
/** FRIEND_DELETE 帧 payload 是否带 clear=true:clear 语义是清会话本身,跳过气泡渲染 */
|
||||
const isFriendDeleteWithClear = (frame: ImPrivateMessageDTO): boolean => {
|
||||
if (frame.type !== ImMessageType.FRIEND_DELETE) {
|
||||
return false
|
||||
}
|
||||
try {
|
||||
const payload = JSON.parse(frame.content || '{}') as { clear?: boolean }
|
||||
return payload.clear === true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* WebSocket 私聊 DTO -> 前端 Message
|
||||
* 不写发送人名字段:渲染层走 utils/user 实时算(备注 / 群昵称变更后历史消息自动刷新)
|
||||
|
|
@ -225,9 +238,13 @@ export const useImWebSocketStore = defineStore('imWebSocketStore', {
|
|||
default:
|
||||
if (isFriendNotification(websocketMessage.type)) {
|
||||
this.handleFriendNotification(websocketMessage)
|
||||
// FRIEND_ADD / FRIEND_DELETE 同时作为会话事件气泡插入消息列表(becomeFriends 入库
|
||||
// 帧 + silent / delete 单边推送帧统一走入库去重路径,前端按 type 渲染灰色提示)
|
||||
if (isFriendChatTip(websocketMessage.type)) {
|
||||
// FRIEND_ADD / FRIEND_DELETE:同时作为会话事件气泡插入消息列表
|
||||
// (becomeFriends 入库帧 + silent / delete 单边推送帧统一走入库去重路径,前端按 type 渲染灰色提示);
|
||||
// FRIEND_DELETE 的 clear=true 语义是清会话本身,跳过气泡避免在已清会话里写入虚拟消息
|
||||
if (
|
||||
isFriendChatTip(websocketMessage.type) &&
|
||||
!isFriendDeleteWithClear(websocketMessage)
|
||||
) {
|
||||
this.handlePrivateMessage(websocketMessage)
|
||||
}
|
||||
} else {
|
||||
|
|
@ -481,11 +498,21 @@ export const useImWebSocketStore = defineStore('imWebSocketStore', {
|
|||
|
||||
// ==================== 好友通知(1201-1210 段位,承载于私聊通道) ====================
|
||||
|
||||
/**
|
||||
* 算 FRIEND_ADD / FRIEND_DELETE 帧的「对端 userId」:
|
||||
* becomeFriends 单条入库后双方收到同一份 payload,payload.friendUserId 固定是 toUserId,本端真正的对端要从帧 sender / receiver 反推
|
||||
*/
|
||||
computeFriendPeerId(frame: ImPrivateMessageDTO): number {
|
||||
const userStore = useUserStore()
|
||||
const currentUserId = Number(userStore.getUser?.id) || 0
|
||||
return frame.senderId === currentUserId ? frame.receiverId : frame.senderId
|
||||
},
|
||||
|
||||
/**
|
||||
* 好友通知统一入口:解析 content 里的 payload,按 type 分发到 friendStore 内部 dispatcher
|
||||
*
|
||||
* 对应后端 ImPrivateMessageDTO.ofFriendNotification 系列;payload 实际类型见
|
||||
* BaseFriendNotification 子类(FriendRequestNotification / FriendAddNotification 等)
|
||||
* 对应后端 ImPrivateMessageDTO.ofFriendNotification 系列;
|
||||
* payload 实际类型见 BaseFriendNotification 子类(FriendRequestNotification / FriendAddNotification 等)
|
||||
*/
|
||||
handleFriendNotification(websocketMessage: ImPrivateMessageDTO) {
|
||||
// content 解析失败由外层 dispatchPrivateFrame 的 try-catch 兜底(含 websocketMessage 打印),不重复 catch
|
||||
|
|
@ -502,10 +529,10 @@ export const useImWebSocketStore = defineStore('imWebSocketStore', {
|
|||
friendStore.applyFriendRequestRejectedNotification(payload)
|
||||
break
|
||||
case ImMessageType.FRIEND_ADD:
|
||||
friendStore.applyFriendAddNotification(payload)
|
||||
friendStore.applyFriendAddNotification(payload, this.computeFriendPeerId(websocketMessage))
|
||||
break
|
||||
case ImMessageType.FRIEND_DELETE:
|
||||
friendStore.applyFriendDeleteNotification(payload)
|
||||
friendStore.applyFriendDeleteNotification(payload, this.computeFriendPeerId(websocketMessage))
|
||||
break
|
||||
case ImMessageType.FRIEND_BLOCK:
|
||||
friendStore.applyFriendBlockNotification(payload)
|
||||
|
|
|
|||
Loading…
Reference in New Issue