diff --git a/src/views/im/home/pages/conversation/components/conversation/ConversationGroupSide.vue b/src/views/im/home/pages/conversation/components/conversation/ConversationGroupSide.vue
index bb0334fe4..5a0d62f7c 100644
--- a/src/views/im/home/pages/conversation/components/conversation/ConversationGroupSide.vue
+++ b/src/views/im/home/pages/conversation/components/conversation/ConversationGroupSide.vue
@@ -626,10 +626,11 @@ async function handleRemoveComplete(members: GroupMemberFlag[]) {
// ---------- 设置群管理员 ----------
-/** 当前管理员的 userId 列表,作为 Selector 默认勾选 */
+/** 当前管理员的 userId 列表,作为 Selector 默认勾选;过滤已退群成员,避免 maxSize 名额被隐藏成员占用导致无法新增管理员 */
const adminCheckedIds = computed(() =>
props.members
- .filter((member) => member.role === ImGroupMemberRole.ADMIN)
+ .filter((member) => member.role === ImGroupMemberRole.ADMIN
+ && member.status !== CommonStatusEnum.DISABLE)
.map((member) => member.userId)
)
diff --git a/src/views/im/home/pages/conversation/components/message/MessageHistory.vue b/src/views/im/home/pages/conversation/components/message/MessageHistory.vue
index 6b8174401..e9f8569d3 100644
--- a/src/views/im/home/pages/conversation/components/message/MessageHistory.vue
+++ b/src/views/im/home/pages/conversation/components/message/MessageHistory.vue
@@ -152,7 +152,7 @@
{{ resolveTipText(message.content) }}
-
+
-
+
parseMessage(props.message.conte
/** TIP_TEXT 文案:与 conversationStore.resolveLastContent / MessageHistory.renderContent 共用 helper,避免兼容性逻辑分裂 */
const tipText = computed(() => resolveTipText(props.message.content))
-/** 群广播事件(1501-1520 / 1530) */
+/** 群广播事件 */
const isGroupNotificationMessage = computed(() => isGroupNotification(props.message.type))
const groupNotificationText = computed(() => resolveGroupNotificationText(props.message))
const imagePayload = computed(() =>
diff --git a/src/views/im/home/store/groupStore.ts b/src/views/im/home/store/groupStore.ts
index 5e8390c7c..01e4fba6e 100644
--- a/src/views/im/home/store/groupStore.ts
+++ b/src/views/im/home/store/groupStore.ts
@@ -21,7 +21,7 @@ import {
setQuietly,
StorageKeys
} from '../../utils/storage'
-import { getGroupDisplayName } from '../../utils/user'
+import { getGroupDisplayName, type GroupNotificationPayload } from '../../utils/user'
import type { Group, GroupMember } from '../types'
/**
@@ -38,9 +38,16 @@ const pendingMemberKey = (userId: number, groupId: number) => `${userId}:${group
* 跟整群表分开:单成员 fetch 跟整群 fetch 语义不同(单成员不回填 me 的 muted),不能互相代替
*/
const pendingSingleMemberFetches = new Map>()
+
const pendingSingleMemberKey = (userId: number, groupId: number, memberUserId: number) =>
`${userId}:${groupId}:${memberUserId}`
+/** 判断当前用户是否在 payload.memberUserIds 里(GROUP_CREATE / INVITE / KICK 自判用) */
+function isSelfInPayloadMembers(payload: GroupNotificationPayload): boolean {
+ const selfUserId = getCurrentUserId()
+ return !!selfUserId && (payload.memberUserIds || []).includes(selfUserId)
+}
+
/**
* IM 群 Store
*
@@ -458,12 +465,16 @@ export const useGroupStore = defineStore('imGroupStore', {
this.saveGroupMembers(groupId)
},
- /** 局部更新群字段(name / notice / avatar 等);未命中本地缓存时静默忽略,等 fetchGroups 兜底 */
+ /** 局部更新群字段(name / notice / avatar 等);未命中本地缓存时静默忽略,等 fetchGroups 兜底;新值跟旧值都相同时跳过响应式 + IDB 写 */
updateGroupFields(groupId: number, fields: Partial) {
const group = this.getGroup(groupId)
if (!group) {
return
}
+ const changed = (Object.keys(fields) as (keyof Group)[]).some((k) => group[k] !== fields[k])
+ if (!changed) {
+ return
+ }
Object.assign(group, fields)
const conversationStore = useConversationStore()
conversationStore.updateConversation(ImConversationType.GROUP, groupId, {
@@ -475,7 +486,7 @@ export const useGroupStore = defineStore('imGroupStore', {
},
/**
- * 接收 GROUP_* 群广播事件,按 type 分发到对应 mutation
+ * 接收 GROUP_* 群广播事件,按 type 分发到对应私有 action
*
* WebSocket 实时收 + useMessagePuller 离线 pull 都走 conversationStore.insertMessage 旁路调用
* store 里没缓存的群静默忽略,等 fetchGroups 兜底
@@ -484,84 +495,44 @@ export const useGroupStore = defineStore('imGroupStore', {
if (!groupId) {
return
}
- let payload: Record = {}
+ let payload: GroupNotificationPayload = {}
try {
payload = content ? JSON.parse(content) : {}
} catch (error) {
- console.warn('[IM groupStore] applyGroupNotification 解析 content 失败', { groupId, type, content }, error)
+ console.warn(
+ '[IM groupStore] applyGroupNotification 解析 content 失败',
+ { groupId, type, contentLength: content?.length ?? 0 },
+ error
+ )
return
}
switch (type) {
- case ImMessageType.GROUP_CREATE: {
- // 创建群广播:创建者多端同步 + 初始成员 bootstrap;payload.memberUserIds 含自己 → 拉群详情 / 成员
- const selfUserId = getCurrentUserId()
- const memberIds: number[] = payload.memberUserIds || []
- if (selfUserId && memberIds.includes(selfUserId)) {
- this.fetchGroupInfo(groupId).catch(() => undefined)
- this.fetchGroupMembers(groupId, true).catch(() => undefined)
- }
+ case ImMessageType.GROUP_CREATE:
+ this.applyGroupCreateNotification(groupId, payload)
break
- }
case ImMessageType.GROUP_NAME_UPDATE:
- if (payload.newName) {
- this.updateGroupFields(groupId, { name: payload.newName })
- }
+ this.applyGroupNameUpdateNotification(groupId, payload)
break
case ImMessageType.GROUP_NOTICE_UPDATE:
- this.updateGroupFields(groupId, { notice: payload.notice ?? '' })
+ this.applyGroupNoticeUpdateNotification(groupId, payload)
break
- case ImMessageType.GROUP_INFO_UPDATE: {
- // 兜底 NAME / NOTICE 之外的群字段变更(avatar 等);按非 null 字段累积更新
- const fields: Partial = {}
- if (payload.avatar) {
- fields.avatar = payload.avatar
- }
- if (Object.keys(fields).length > 0) {
- this.updateGroupFields(groupId, fields)
- }
+ case ImMessageType.GROUP_INFO_UPDATE:
+ this.applyGroupInfoUpdateNotification(groupId, payload)
break
- }
case ImMessageType.GROUP_DISSOLVE:
- // 群解散:所有成员(含群主)收到广播 → 本端自行清群
this.removeGroup(groupId)
break
- case ImMessageType.GROUP_MEMBER_INVITE: {
- // 被邀请者:本端 group 还没就位,先 fetchGroupInfo bootstrap,再拉成员
- // 已在群成员:只刷成员列表(新成员 nickname / avatar 不在 payload,必须 fetch)
- const selfUserId = getCurrentUserId()
- const memberIds: number[] = payload.memberUserIds || []
- const selfInvited = !!selfUserId && memberIds.includes(selfUserId)
- if (selfInvited && !this.getGroup(groupId)) {
- this.fetchGroupInfo(groupId).catch(() => undefined)
- }
- this.fetchGroupMembers(groupId, true).catch(() => undefined)
+ case ImMessageType.GROUP_MEMBER_INVITE:
+ this.applyGroupMemberInviteNotification(groupId, payload)
break
- }
- case ImMessageType.GROUP_MEMBER_QUIT: {
- // 退群者本人多端同步:清群;其他成员:从本地成员列表移除
- const selfUserId = getCurrentUserId()
- if (selfUserId && payload.operatorUserId === selfUserId) {
- this.removeGroup(groupId)
- } else if (payload.operatorUserId) {
- this.removeMembersLocal(groupId, [payload.operatorUserId])
- }
+ case ImMessageType.GROUP_MEMBER_QUIT:
+ this.applyGroupMemberQuitNotification(groupId, payload)
break
- }
- case ImMessageType.GROUP_MEMBER_KICK: {
- // 被踢者本人:清群;其他成员:从本地成员列表移除
- const selfUserId = getCurrentUserId()
- const memberIds: number[] = payload.memberUserIds || []
- if (selfUserId && memberIds.includes(selfUserId)) {
- this.removeGroup(groupId)
- } else if (memberIds.length) {
- this.removeMembersLocal(groupId, memberIds)
- }
+ case ImMessageType.GROUP_MEMBER_KICK:
+ this.applyGroupMemberKickNotification(groupId, payload)
break
- }
case ImMessageType.GROUP_MEMBER_NICKNAME_UPDATE:
- if (payload.operatorUserId) {
- this.updateMemberDisplayUserName(groupId, payload.operatorUserId, payload.displayUserName ?? '')
- }
+ this.applyGroupMemberNicknameUpdateNotification(groupId, payload)
break
case ImMessageType.GROUP_ADMIN_ADD:
this.updateMembersRole(groupId, payload.memberUserIds || [], ImGroupMemberRole.ADMIN)
@@ -570,13 +541,94 @@ export const useGroupStore = defineStore('imGroupStore', {
this.updateMembersRole(groupId, payload.memberUserIds || [], ImGroupMemberRole.NORMAL)
break
case ImMessageType.GROUP_OWNER_TRANSFER:
- if (payload.operatorUserId && payload.newOwnerUserId) {
- this.transferOwner(groupId, payload.operatorUserId, payload.newOwnerUserId)
- }
+ this.applyGroupOwnerTransferNotification(groupId, payload)
break
}
},
+ /** 创建群广播:创建者多端同步 + 初始成员 bootstrap;payload.memberUserIds 含自己 → 拉群详情 / 成员;本端发起者已经 upsert 过本群,跳过避免双拉 */
+ applyGroupCreateNotification(groupId: number, payload: GroupNotificationPayload) {
+ if (!isSelfInPayloadMembers(payload)) {
+ return
+ }
+ const selfUserId = getCurrentUserId()
+ const selfIsOperator = !!selfUserId && payload.operatorUserId === selfUserId
+ if (selfIsOperator && this.getGroup(groupId)) {
+ return
+ }
+ this.fetchGroupInfo(groupId).catch(() => undefined)
+ this.fetchGroupMembers(groupId, true).catch(() => undefined)
+ },
+
+ /** 群名变更:按 newName 局部更新本地群名 */
+ applyGroupNameUpdateNotification(groupId: number, payload: GroupNotificationPayload) {
+ if (payload.newName) {
+ this.updateGroupFields(groupId, { name: payload.newName })
+ }
+ },
+
+ /** 群公告变更:按 newNotice 局部更新(允许空串作为「清空公告」) */
+ applyGroupNoticeUpdateNotification(groupId: number, payload: GroupNotificationPayload) {
+ this.updateGroupFields(groupId, { notice: payload.newNotice ?? '' })
+ },
+
+ /** 群信息变更(NAME / NOTICE 之外字段,当前承载头像变更) */
+ applyGroupInfoUpdateNotification(groupId: number, payload: GroupNotificationPayload) {
+ const fields: Partial = {}
+ if (payload.newAvatar) {
+ fields.avatar = payload.newAvatar
+ }
+ if (Object.keys(fields).length > 0) {
+ this.updateGroupFields(groupId, fields)
+ }
+ },
+
+ /** 成员加入:被邀请者本端 group 未就位先 fetchGroupInfo bootstrap;所有人都刷成员列表(新成员 nickname / avatar 不在 payload) */
+ applyGroupMemberInviteNotification(groupId: number, payload: GroupNotificationPayload) {
+ if (isSelfInPayloadMembers(payload) && !this.getGroup(groupId)) {
+ this.fetchGroupInfo(groupId).catch(() => undefined)
+ }
+ this.fetchGroupMembers(groupId, true).catch(() => undefined)
+ },
+
+ /** 成员退群:退群者本人多端同步走 removeGroup;其他成员从本地列表移除 quitter */
+ applyGroupMemberQuitNotification(groupId: number, payload: GroupNotificationPayload) {
+ const selfUserId = getCurrentUserId()
+ if (selfUserId && payload.operatorUserId === selfUserId) {
+ this.removeGroup(groupId)
+ } else if (payload.operatorUserId) {
+ this.removeMembersLocal(groupId, [payload.operatorUserId])
+ }
+ },
+
+ /** 成员被移出:被踢者本人 removeGroup;其他成员从本地列表移除被踢者 */
+ applyGroupMemberKickNotification(groupId: number, payload: GroupNotificationPayload) {
+ const memberIds = payload.memberUserIds || []
+ if (isSelfInPayloadMembers(payload)) {
+ this.removeGroup(groupId)
+ } else if (memberIds.length) {
+ this.removeMembersLocal(groupId, memberIds)
+ }
+ },
+
+ /** 成员昵称变更:按 operatorUserId 局部更新对应 member.displayUserName */
+ applyGroupMemberNicknameUpdateNotification(groupId: number, payload: GroupNotificationPayload) {
+ if (payload.operatorUserId) {
+ this.updateMemberDisplayUserName(
+ groupId,
+ payload.operatorUserId,
+ payload.displayUserName ?? ''
+ )
+ }
+ },
+
+ /** 群主转让:旧群主 → NORMAL,新群主 → OWNER */
+ applyGroupOwnerTransferNotification(groupId: number, payload: GroupNotificationPayload) {
+ if (payload.operatorUserId && payload.newOwnerUserId) {
+ this.transferOwner(groupId, payload.operatorUserId, payload.newOwnerUserId)
+ }
+ },
+
/** 切账号时仅清 in-memory,IDB 按 userId 分桶天然隔离,回切秒开 */
clear() {
this.groups = []
diff --git a/src/views/im/home/store/websocketStore.ts b/src/views/im/home/store/websocketStore.ts
index 4cf98112e..3e59359a1 100644
--- a/src/views/im/home/store/websocketStore.ts
+++ b/src/views/im/home/store/websocketStore.ts
@@ -15,7 +15,8 @@ import type {
WebSocketFrame,
ImPrivateMessageDTO,
ImGroupMessageDTO,
- Message
+ Message,
+ Group
} from '../types'
/**
@@ -73,7 +74,8 @@ const convertGroupMessage = (
* - 普通消息(TEXT / IMAGE / FILE / VOICE / VIDEO / TIP_TEXT):入库 + 当前会话自动已读 / 提示音
* - 已读 / 回执(READ / RECEIPT):多端已读同步、对方读后回执
* - 好友变更(FRIEND_ADD / DELETE / UPDATE):同步 friendStore + 级联刷新私聊会话
- * - 群个人信号(1530 GROUP_MEMBER_SETTING_UPDATE):同步 groupStore + 级联刷新群聊会话;群广播事件(1501-1520 OpenIM 段位)走 handleGroupMessage + applyGroupNotification 旁路(含 DISSOLVE/QUIT/KICK 自判清群)
+ * - 群个人信号(GROUP_MEMBER_SETTING_UPDATE):同步 groupStore + 级联刷新群聊会话
+ * - 群广播事件(GROUP_*):走 handleGroupMessage + applyGroupNotification 旁路(含 DISSOLVE / QUIT / KICK 自判清群)
*/
export const useImWebSocketStore = defineStore('imWebSocketStore', {
state: () => ({
@@ -518,7 +520,7 @@ export const useImWebSocketStore = defineStore('imWebSocketStore', {
if (!group) {
return
}
- const fields: Partial = {}
+ const fields: Partial = {}
if (payload.muted != null) {
fields.muted = payload.muted
}
diff --git a/src/views/im/manager/message/MessageContentPreview.vue b/src/views/im/manager/message/MessageContentPreview.vue
index 6068634ce..ebcd650d6 100644
--- a/src/views/im/manager/message/MessageContentPreview.vue
+++ b/src/views/im/manager/message/MessageContentPreview.vue
@@ -76,7 +76,7 @@
[回执]
-
+
{
return raw
})
-/** 是否群广播事件(1501-1520 / 1530) */
+/** 是否群广播事件 */
const isGroupNotificationType = computed(() => isGroupNotification(props.type ?? -1))
-/** 群广播事件 operatorUserId:用于把 senderNickname 仅覆盖到 operator 这一个 id 上 */
-const groupOperatorUserId = computed(() => {
- try {
- return JSON.parse(props.content || '{}')?.operatorUserId
- } catch {
- return undefined
- }
-})
-
-/** 群广播事件文案:复用 utils/user.resolveGroupNotificationText,admin 端 resolveName 用 senderNickname(仅 operator)+ 用户(id) 兜底 */
+/** 群广播事件文案:复用 utils/user.resolveGroupNotificationText;admin 端 operator 用 senderNickname 直接覆盖,其它 id 退化为 用户(id) */
const groupNotificationText = computed(() =>
resolveGroupNotificationText(
- {
- type: props.type as number,
- content: props.content || '',
- targetId: 0
- } as Pick,
- (id) =>
- id === groupOperatorUserId.value && props.senderNickname
- ? props.senderNickname
- : `用户(${id})`
+ { type: props.type, content: props.content },
+ (id) => `用户(${id})`,
+ props.senderNickname
)
)
diff --git a/src/views/im/utils/constants.ts b/src/views/im/utils/constants.ts
index 72bab1133..07efad68b 100644
--- a/src/views/im/utils/constants.ts
+++ b/src/views/im/utils/constants.ts
@@ -13,51 +13,33 @@ export const ImMessageType = {
FRIEND_ADD: 100, // 好友添加
FRIEND_DELETE: 101, // 好友删除
FRIEND_UPDATE: 102, // 好友更新(客户端收到后自行拉取)
- // 群事件(1501-1520 直接复用 OpenIM 段位编号;1530+ 我们独有扩展;persistent=true 广播 + persistent=false 个人信号)
- // 1500 mirror OpenIM GroupNotificationBegin marker,不使用
+ // 群事件(1501-1520 复用 OpenIM 段位编号;1530+ 自有扩展段)
GROUP_CREATE: 1501, // 群创建
- GROUP_INFO_UPDATE: 1502, // 群信息变更,NAME / NOTICE 之外字段兜底
+ GROUP_INFO_UPDATE: 1502, // 群信息变更(NAME / NOTICE 之外字段兜底)
// 1503 GROUP_JOIN_APPLICATION TODO 未实现:入群申请
GROUP_MEMBER_QUIT: 1504, // 成员退群
- // 1505 GROUP_APPLICATION_ACCEPTED TODO 未实现
- // 1506 GROUP_APPLICATION_REJECTED TODO 未实现
+ // 1505 GROUP_APPLICATION_ACCEPTED TODO 未实现:入群申请通过
+ // 1506 GROUP_APPLICATION_REJECTED TODO 未实现:入群申请拒绝
GROUP_OWNER_TRANSFER: 1507, // 群主转让
GROUP_MEMBER_KICK: 1508, // 成员被移出
GROUP_MEMBER_INVITE: 1509, // 成员加入
// 1510 GROUP_MEMBER_ENTER TODO 未实现:自由进群
GROUP_DISSOLVE: 1511, // 群解散
// 1512 GROUP_MEMBER_MUTED TODO 未实现:单成员禁言
- // 1513 GROUP_MEMBER_CANCEL_MUTED TODO 未实现
+ // 1513 GROUP_MEMBER_CANCEL_MUTED TODO 未实现:单成员取消禁言
// 1514 GROUP_MUTED TODO 未实现:全群禁言
- // 1515 GROUP_CANCEL_MUTED TODO 未实现
+ // 1515 GROUP_CANCEL_MUTED TODO 未实现:全群取消禁言
GROUP_MEMBER_NICKNAME_UPDATE: 1516, // 成员昵称变更(窄化到 displayUserName)
GROUP_ADMIN_ADD: 1517, // 添加管理员
GROUP_ADMIN_REMOVE: 1518, // 撤销管理员
GROUP_NOTICE_UPDATE: 1519, // 群公告变更
GROUP_NAME_UPDATE: 1520, // 群名变更
- // 1530+ 我们独有扩展段
- GROUP_MEMBER_SETTING_UPDATE: 1530 // 群成员个人设置变更:muted / groupRemark 多端同步(个人)
+ GROUP_MEMBER_SETTING_UPDATE: 1530 // 群成员个人设置变更:muted / groupRemark 个人多端同步
} as const
-/** 群广播事件 type 集合:1501-1520 OpenIM 段位(除 1530 个人设置同步),前端按 type 分发到 applyGroupNotification */
-const ImGroupNotificationTypes: number[] = [
- ImMessageType.GROUP_CREATE,
- ImMessageType.GROUP_NAME_UPDATE,
- ImMessageType.GROUP_NOTICE_UPDATE,
- ImMessageType.GROUP_INFO_UPDATE,
- ImMessageType.GROUP_DISSOLVE,
- ImMessageType.GROUP_MEMBER_INVITE,
- ImMessageType.GROUP_MEMBER_QUIT,
- ImMessageType.GROUP_MEMBER_KICK,
- ImMessageType.GROUP_MEMBER_NICKNAME_UPDATE,
- ImMessageType.GROUP_ADMIN_ADD,
- ImMessageType.GROUP_ADMIN_REMOVE,
- ImMessageType.GROUP_OWNER_TRANSFER
-]
-
-/** 判断是否「群广播事件」 */
+/** 判断是否「群广播事件」:[GROUP_CREATE, GROUP_MEMBER_SETTING_UPDATE) 段位都算,GROUP_MEMBER_SETTING_UPDATE 是个人信号不算 */
export function isGroupNotification(type: number): boolean {
- return ImGroupNotificationTypes.includes(type)
+ return type >= ImMessageType.GROUP_CREATE && type < ImMessageType.GROUP_MEMBER_SETTING_UPDATE
}
/** IM 普通消息类型集合(聊天气泡中显示,并作为会话最后一条摘要) */
diff --git a/src/views/im/utils/user.ts b/src/views/im/utils/user.ts
index fcba2686f..06d63b862 100644
--- a/src/views/im/utils/user.ts
+++ b/src/views/im/utils/user.ts
@@ -14,16 +14,14 @@ import { ImConversationType, ImMessageType } from './constants'
import { getCurrentUserId } from './storage'
import { useFriendStore } from '../home/store/friendStore'
import { useGroupStore } from '../home/store/groupStore'
-import type { Friend, Group, Message } from '../home/types'
+import type { Friend, Group } from '../home/types'
/**
* 私聊好友显示名:备注 > 真实昵称
*
* displayName 是「我对这个人的私人称呼」属于我的数据,删好友(DISABLE)也保留;删了再加回来时备注自然延续,历史消息里仍以备注辨识
*/
-export function getFriendDisplayName(
- friend: Pick
-): string {
+export function getFriendDisplayName(friend: Pick): string {
return friend.displayName || friend.nickname
}
@@ -151,35 +149,42 @@ export function getSenderRealNickname(
}
/**
- * 群广播事件(GROUP_* 1501-1520 / 1530)的中文文案
+ * 群广播事件(GROUP_* 系列)的中文文案
*
* 按 message.type 取 content payload 字段,昵称默认走 getSenderDisplayName(备注 / 群昵称 / 真实昵称兜底);
* 管理后台无 store,可传入 resolveName 自定义 id → 名字(如 senderNickname + 用户(id) 兜底);
* home 端 MessageItem.vue / ConversationItem.vue / MessageHistory.vue 与 admin 端 MessageContentPreview.vue 共用
*/
+export type GroupNotificationPayload = {
+ operatorUserId?: number
+ memberUserIds?: number[]
+ newOwnerUserId?: number
+ oldName?: string
+ newName?: string
+ oldNotice?: string
+ newNotice?: string
+ oldAvatar?: string
+ newAvatar?: string
+ displayUserName?: string
+}
+
export function resolveGroupNotificationText(
- message: Pick,
- resolveName?: (userId: number) => string
+ message: { type?: number; content?: string; targetId?: number },
+ resolveName?: (userId: number) => string,
+ operatorNameOverride?: string
): string {
- const groupId = message.targetId
- let payload: {
- operatorUserId?: number
- memberUserIds?: number[]
- newOwnerUserId?: number
- oldName?: string
- newName?: string
- notice?: string
- avatar?: string
- displayUserName?: string
- } = {}
+ let payload: GroupNotificationPayload = {}
try {
payload = JSON.parse(message.content || '{}')
} catch {
return ''
}
const resolve =
- resolveName || ((id: number) => getSenderDisplayName(id, ImConversationType.GROUP, groupId))
- const operatorName = payload.operatorUserId ? resolve(payload.operatorUserId) : ''
+ resolveName ||
+ ((id: number) => getSenderDisplayName(id, ImConversationType.GROUP, message.targetId ?? 0))
+ const operatorName = payload.operatorUserId
+ ? (operatorNameOverride ?? resolve(payload.operatorUserId))
+ : ''
const memberNames = (payload.memberUserIds || []).map(resolve).join('、')
const newOwnerName = payload.newOwnerUserId ? resolve(payload.newOwnerUserId) : ''
switch (message.type) {
@@ -191,7 +196,7 @@ export function resolveGroupNotificationText(
return `${operatorName} 更新了群公告`
case ImMessageType.GROUP_INFO_UPDATE:
// 兜底事件:按非 null 字段优先匹配特化文案,全部为空时降级为 "更新了群信息" 通用文案
- if (payload.avatar) {
+ if (payload.newAvatar) {
return `${operatorName} 更换了群头像`
}
return `${operatorName} 更新了群信息`