fix(im): 修复群备注首屏展示和聊天列表名称覆盖
- 后端群 VO 返回当前用户维度的 groupRemark 和 silent - 群列表构建时通过成员关系回填个人群设置,并继续仅对有效成员回填置顶消息 - Vue3 群列表同步时以接口返回的个人群设置为准,只保留成员缓存 - 会话名写入入口统一使用 getGroupDisplayName,避免群备注被原群名覆盖 - 空群头像且成员未加载时异步预拉群成员,用于合成群头像 - 启用 IM Maven 模块和 yudao-server 对 IM 模块的依赖im
parent
ab2fa4e6b8
commit
61c9e1acf2
|
|
@ -17,6 +17,8 @@ export interface ImGroupRespVO {
|
|||
createTime?: string // 创建时间
|
||||
pinnedMessages?: ImGroupMessageRespVO[] // 群置顶消息列表(后端关联回填,仅当登录用户是群成员时非空)
|
||||
joinStatus?: number // 当前登录用户在该群的成员状态(参见 CommonStatusEnum:0 在群 / 1 已退群);历史退群群仍返回,供展示离线消息的群名 / 头像
|
||||
groupRemark?: string // 当前登录用户对该群的备注
|
||||
silent?: boolean // 当前登录用户是否免打扰
|
||||
}
|
||||
|
||||
// 群消息置顶 / 取消置顶 Request VO
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ import { ImConversationType, ImContentType, isGroupConversation } from '../../..
|
|||
import { getConversationKey } from '../../../utils/conversation'
|
||||
import { buildDefaultGroupName } from '../../../utils/group'
|
||||
import { serializeMessage, type CardTarget } from '../../../utils/message'
|
||||
import { isGroupQuit } from '../../../utils/user'
|
||||
import { getGroupDisplayName, isGroupQuit } from '../../../utils/user'
|
||||
import type { Conversation, FriendLite } from '../../types'
|
||||
|
||||
defineOptions({ name: 'ImRecommendCardDialog' })
|
||||
|
|
@ -283,7 +283,7 @@ async function handleCreateGroupAndSend() {
|
|||
const newConversation: Conversation = {
|
||||
type: ImConversationType.GROUP,
|
||||
targetId: group.id,
|
||||
name: group.name || name,
|
||||
name: getGroupDisplayName(group) || name,
|
||||
avatar: group.avatar || '',
|
||||
unreadCount: 0,
|
||||
lastContent: '',
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { useConversationStore } from '../store/conversationStore'
|
|||
import { useMessageStore, type PulledMessage } from '../store/messageStore'
|
||||
import { useImWebSocketStore } from '../store/websocketStore'
|
||||
import { useFriendStore } from '../store/friendStore'
|
||||
import { getFriendDisplayName } from '../../utils/user'
|
||||
import { getFriendDisplayName, getGroupDisplayName } from '../../utils/user'
|
||||
import { useGroupStore } from '../store/groupStore'
|
||||
import { useGroupRequestStore } from '../store/groupRequestStore'
|
||||
import {
|
||||
|
|
@ -149,7 +149,7 @@ export const useMessagePuller = () => {
|
|||
return {
|
||||
type: ImConversationType.GROUP,
|
||||
targetId: message.groupId,
|
||||
name: group?.name || String(message.groupId),
|
||||
name: group ? getGroupDisplayName(group) : String(message.groupId),
|
||||
avatar: group?.avatar || '',
|
||||
silent: group?.silent
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,9 +85,9 @@
|
|||
/>
|
||||
<div class="flex justify-end gap-2">
|
||||
<el-button size="small" @click="displayNamePopoverVisible = false">取消</el-button>
|
||||
<el-button size="small" type="primary" @click="handleSaveDisplayName"
|
||||
>保存</el-button
|
||||
>
|
||||
<el-button size="small" type="primary" @click="handleSaveDisplayName">
|
||||
保存
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-popover>
|
||||
|
|
@ -141,7 +141,7 @@ import { useMessage } from '@/hooks/web/useMessage'
|
|||
import { useConversationStore } from '@/views/im/home/store/conversationStore'
|
||||
import { useFriendStore } from '@/views/im/home/store/friendStore'
|
||||
import { useGroupStore } from '@/views/im/home/store/groupStore'
|
||||
import { getFriendDisplayName } from '@/views/im/utils/user'
|
||||
import { getFriendDisplayName, getGroupDisplayName } from '@/views/im/utils/user'
|
||||
import { ImConversationType } from '@/views/im/utils/constants'
|
||||
import type { Conversation, Friend } from '../../../../types'
|
||||
|
||||
|
|
@ -248,7 +248,7 @@ function handleGroupCreated(groupId: number) {
|
|||
conversationStore.openConversation(
|
||||
groupId,
|
||||
ImConversationType.GROUP,
|
||||
group.name,
|
||||
getGroupDisplayName(group),
|
||||
group.avatar || '',
|
||||
{ silent: !!group.silent }
|
||||
)
|
||||
|
|
|
|||
|
|
@ -260,6 +260,7 @@ import { ImRtcCallMediaType, ImRtcCallStatus, ImConversationType } from '@/views
|
|||
import { resolveCallEndReasonText } from '@/views/im/utils/message'
|
||||
import { getClientConversationId } from '@/views/im/utils/db'
|
||||
import { getCurrentUserId } from '@/utils/auth'
|
||||
import { getGroupDisplayName } from '@/views/im/utils/user'
|
||||
import { useRtcStore } from '../../../../store/rtcStore'
|
||||
import { useMessageStore } from '../../../../store/messageStore'
|
||||
|
||||
|
|
@ -405,10 +406,11 @@ const groupInfo = computed<
|
|||
}
|
||||
const group = groupStore.getGroup(conversation.targetId)
|
||||
const selfMember = group?.members?.find((member) => member.userId === getCurrentUserId())
|
||||
const showGroupName = group ? getGroupDisplayName(group) : conversation.name
|
||||
return {
|
||||
id: conversation.targetId,
|
||||
name: group?.name || conversation.name,
|
||||
showGroupName: group?.name || conversation.name,
|
||||
showGroupName,
|
||||
showImage: group?.avatar || conversation.avatar,
|
||||
notice: group?.notice,
|
||||
remarkNickName: selfMember?.displayUserName,
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ import FacePicker from '../../input/FacePicker.vue'
|
|||
import { useConversationStore } from '@/views/im/home/store/conversationStore'
|
||||
import { useFriendStore } from '@/views/im/home/store/friendStore'
|
||||
import { useGroupStore } from '@/views/im/home/store/groupStore'
|
||||
import { isGroupQuit } from '@/views/im/utils/user'
|
||||
import { getGroupDisplayName, isGroupQuit } from '@/views/im/utils/user'
|
||||
import { useMessageSender } from '@/views/im/home/composables/useMessageSender'
|
||||
import { useMessageMultiSelect } from '@/views/im/home/composables/useMessageMultiSelect'
|
||||
import {
|
||||
|
|
@ -406,7 +406,7 @@ async function handleCreateGroupAndSend() {
|
|||
const newConversation: Conversation = {
|
||||
type: ImConversationType.GROUP,
|
||||
targetId: group.id,
|
||||
name: group.name || name,
|
||||
name: getGroupDisplayName(group) || name,
|
||||
avatar: group.avatar || '',
|
||||
unreadCount: 0,
|
||||
lastContent: '',
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ import { useImUiStore } from '../../store/uiStore'
|
|||
import { ImConversationType } from '../../../utils/constants'
|
||||
import { StorageKeys } from '../../../utils/db'
|
||||
import { filterConversationsByKeyword, getConversationKey } from '../../../utils/conversation'
|
||||
import { getGroupDisplayName } from '../../../utils/user'
|
||||
import type { Conversation } from '../../types'
|
||||
import ResizableAside from '../../components/ResizableAside.vue'
|
||||
import ConversationItem from './components/conversation/ConversationItem.vue'
|
||||
|
|
@ -220,7 +221,7 @@ function handleGroupCreated(groupId: number) {
|
|||
conversationStore.openConversation(
|
||||
groupId,
|
||||
ImConversationType.GROUP,
|
||||
group.name,
|
||||
getGroupDisplayName(group),
|
||||
group.avatar || '',
|
||||
{ silent: !!group.silent }
|
||||
)
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ export const useGroupStore = defineStore('imGroupStore', {
|
|||
return
|
||||
}
|
||||
const fresh = (list || []).map((group) => convertGroup(group))
|
||||
// 合并而非全量替换:silent / groupRemark / 成员缓存这些字段不在 ImGroupRespVO 里,得从旧 group 保留
|
||||
// 合并而非全量替换:成员缓存只在成员列表接口维护,群个人设置以群列表接口为准
|
||||
const groupMap = new Map(this.groups.map((group) => [group.id, group]))
|
||||
this.groups = fresh.map((group) => {
|
||||
const existing = groupMap.get(group.id)
|
||||
|
|
@ -238,8 +238,6 @@ export const useGroupStore = defineStore('imGroupStore', {
|
|||
...group,
|
||||
members: existing.members,
|
||||
memberCount: existing.memberCount ?? group.memberCount,
|
||||
silent: existing.silent ?? group.silent,
|
||||
groupRemark: existing.groupRemark,
|
||||
membersLoaded: existing.membersLoaded,
|
||||
membersExpired: existing.membersExpired
|
||||
}
|
||||
|
|
@ -254,6 +252,24 @@ export const useGroupStore = defineStore('imGroupStore', {
|
|||
})
|
||||
}
|
||||
this.saveGroupList()
|
||||
this.preloadMembersForEmptyAvatarGroups()
|
||||
},
|
||||
|
||||
/** 预加载空群头像的成员列表,供 GroupAvatar 异步合成群头像 */
|
||||
preloadMembersForEmptyAvatarGroups() {
|
||||
for (const group of this.groups) {
|
||||
if (
|
||||
group.avatar ||
|
||||
group.joinStatus === CommonStatusEnum.DISABLE ||
|
||||
(group.membersLoaded && !group.membersExpired && group.members?.length)
|
||||
) {
|
||||
continue
|
||||
}
|
||||
const force = !!group.membersLoaded && !group.membersExpired && !group.members?.length
|
||||
this.fetchGroupMemberList(group.id, force).catch((error) => {
|
||||
console.warn('[IM groupStore] 预加载群头像成员失败', { groupId: group.id }, error)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
/** 失效全部群成员缓存 */
|
||||
|
|
@ -892,7 +908,9 @@ function convertGroup(group: ImGroupRespVO): Group {
|
|||
mutedAll: group.mutedAll,
|
||||
banned: group.banned,
|
||||
joinApproval: group.joinApproval,
|
||||
joinStatus: group.joinStatus
|
||||
joinStatus: group.joinStatus,
|
||||
groupRemark: group.groupRemark,
|
||||
silent: group.silent
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import {
|
|||
import { useConversationStore } from './conversationStore'
|
||||
import { useMessageStore } from './messageStore'
|
||||
import { useFriendStore, type FriendNotificationPayload } from './friendStore'
|
||||
import { getFriendDisplayName } from '../../utils/user'
|
||||
import { getFriendDisplayName, getGroupDisplayName } from '../../utils/user'
|
||||
import { useGroupStore } from './groupStore'
|
||||
import { useGroupRequestStore } from './groupRequestStore'
|
||||
import {
|
||||
|
|
@ -732,7 +732,7 @@ export const useImWebSocketStore = defineStore('imWebSocketStore', {
|
|||
{
|
||||
type: ImConversationType.GROUP,
|
||||
targetId: websocketMessage.groupId,
|
||||
name: group?.name || String(websocketMessage.groupId),
|
||||
name: group ? getGroupDisplayName(group) : String(websocketMessage.groupId),
|
||||
avatar: group?.avatar || '',
|
||||
silent: group?.silent
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue