diff --git a/pages/message/hooks/use-group-avatars.js b/pages/message/hooks/use-group-avatars.js new file mode 100644 index 0000000..c5f9d14 --- /dev/null +++ b/pages/message/hooks/use-group-avatars.js @@ -0,0 +1,107 @@ +import { ref, computed } from 'vue' +import api from '@/utils/api.js' +import useTeamStore from '@/store/team.js' + +/** + * 群聊头像管理hook - 为消息列表中的每个群聊获取成员头像 + * 用于在消息列表中显示群聊的group-avatar组件 + */ +export default function useGroupAvatars() { + const groupAvatarMap = ref({}) // { groupID: [avatarUrl1, avatarUrl2, ...] } + const teamStore = useTeamStore() + const patientDefaultAvatar = '/static/default-avatar.png' + + /** + * 获取单个群聊的头像列表 + * @param {string} groupID 群组ID + * @param {string} teamId 团队ID + * @param {string} patientId 患者ID + * @returns {Promise} 头像URL数组 + */ + async function getGroupAvatarList(groupID, teamId, patientId) { + try { + if (!teamId) { + console.warn(`群聊 ${groupID} 没有 teamId,无法获取头像`) + return [patientDefaultAvatar] + } + + // 获取团队成员的头像和名称 + const memberMap = await teamStore.getTeamMemberAvatarsAndName(teamId) + + if (!memberMap || Object.keys(memberMap).length === 0) { + console.warn(`群聊 ${groupID} 的团队成员为空`) + return [patientDefaultAvatar] + } + + // 提取头像列表(过滤掉空头像,使用默认头像替代) + const avatarList = Object.values(memberMap) + .map(member => { + // 如果成员有头像且不为空,使用成员头像;否则使用默认头像 + return (member.avatar && member.avatar.trim() !== '') + ? member.avatar + : patientDefaultAvatar + }) + + // 添加患者默认头像 + avatarList.push(patientDefaultAvatar) + + console.log(`群聊 ${groupID} 的头像列表已加载,共 ${avatarList.length} 个头像`) + return avatarList + } catch (error) { + console.error(`获取群聊 ${groupID} 的头像列表失败:`, error) + return [patientDefaultAvatar] + } + } + + /** + * 批量获取多个群聊的头像列表 + * @param {Array} conversationList 会话列表 + * @returns {Promise} + */ + async function loadGroupAvatars(conversationList) { + if (!conversationList || conversationList.length === 0) { + return + } + + try { + // 并发加载所有群聊的头像 + const promises = conversationList.map(async (conversation) => { + const avatarList = await getGroupAvatarList( + conversation.groupID, + conversation.teamId, + conversation.patientId + ) + groupAvatarMap.value[conversation.groupID] = avatarList + }) + + await Promise.all(promises) + console.log('所有群聊头像加载完成') + } catch (error) { + console.error('批量加载群聊头像失败:', error) + } + } + + /** + * 获取指定群聊的头像列表 + * @param {string} groupID 群组ID + * @returns {Array} 头像URL数组 + */ + function getAvatarList(groupID) { + return groupAvatarMap.value[groupID] || [patientDefaultAvatar] + } + + /** + * 清空缓存 + */ + function clearCache() { + groupAvatarMap.value = {} + } + + return { + groupAvatarMap, + getGroupAvatarList, + loadGroupAvatars, + getAvatarList, + clearCache + } +} diff --git a/pages/message/message.vue b/pages/message/message.vue index c36d14d..61116d5 100644 --- a/pages/message/message.vue +++ b/pages/message/message.vue @@ -24,10 +24,9 @@ @click="handleClickConversation(conversation)" > - {{ @@ -81,6 +80,8 @@ import { storeToRefs } from "pinia"; import useAccountStore from "@/store/account.js"; import { globalTimChatManager } from "@/utils/tim-chat.js"; import { mergeConversationWithGroupDetails } from "@/utils/conversation-merger.js"; +import useGroupAvatars from "./hooks/use-group-avatars.js"; +import GroupAvatar from "@/components/group-avatar.vue"; // 获取登录状态 const { account, openid, isIMInitialized } = storeToRefs(useAccountStore()); @@ -93,6 +94,9 @@ const loadingMore = ref(false); const hasMore = ref(false); const refreshing = ref(false); +// 群聊头像管理 +const { loadGroupAvatars, getAvatarList } = useGroupAvatars(); + // 初始化IM const initIM = async () => { console.log("=== message.vue initIM 开始 ==="); @@ -184,7 +188,14 @@ const loadConversationList = async () => { conversationList.value = await mergeConversationWithGroupDetails( result.groupList ); - console.log("群聊列表加载成功,共", conversationList.value, "个会话"); + console.log( + "群聊列表加载成功,共", + conversationList.value.length, + "个会话" + ); + + // 加载所有群聊的头像 + await loadGroupAvatars(conversationList.value); } else { console.error("加载群聊列表失败:", result); uni.showToast({ @@ -291,7 +302,10 @@ const setupConversationListener = () => { // 保持原有头像,避免闪动 avatar: existing.avatar || conversationData.avatar, // 保留较大的未读数(避免被后端数据覆盖) - unreadCount: Math.max(existing.unreadCount || 0, conversationData.unreadCount || 0) + unreadCount: Math.max( + existing.unreadCount || 0, + conversationData.unreadCount || 0 + ), }; needSort = true; console.log( @@ -331,11 +345,11 @@ const setupConversationListener = () => { // 检查当前页面栈,判断用户是否正在查看该会话的聊天详情页 const pages = getCurrentPages(); const currentPage = pages[pages.length - 1]; - + // 获取当前页面的 groupID 参数(如果在聊天详情页) const currentGroupID = currentPage?.options?.groupID; - const isViewingThisConversation = - currentPage?.route === "pages/message/index" && + const isViewingThisConversation = + currentPage?.route === "pages/message/index" && currentGroupID === conversation.groupID; // 如果用户正在查看这个具体的会话,不增加未读数 @@ -533,6 +547,7 @@ onHide(() => { .avatar-container { position: relative; margin-right: 24rpx; + flex-shrink: 0; } .avatar { @@ -540,8 +555,6 @@ onHide(() => { height: 96rpx; border-radius: 8rpx; } - -.unread-badge { position: absolute; top: -8rpx; right: -8rpx;