diff --git a/app/_layout.tsx b/app/_layout.tsx index e854b2b..6c01cda 100644 --- a/app/_layout.tsx +++ b/app/_layout.tsx @@ -161,6 +161,7 @@ function NotificationBootstrap() { const conversationType = extras.conversation_type || extras.conversationType; const groupId = extras.group_id || extras.groupId; const groupName = extras.group_name || extras.groupName; + const groupAvatar = extras.group_avatar || extras.groupAvatar; if (conversationId) { const isGroup = conversationType === 'group'; @@ -169,6 +170,7 @@ function NotificationBootstrap() { q.set('isGroupChat', '1'); if (groupId) q.set('groupId', groupId); if (groupName) q.set('groupName', groupName); + if (groupAvatar) q.set('groupAvatar', groupAvatar); } else if (senderId) { q.set('userId', senderId); } diff --git a/src/navigation/hrefs.ts b/src/navigation/hrefs.ts index c960498..dae9ef8 100644 --- a/src/navigation/hrefs.ts +++ b/src/navigation/hrefs.ts @@ -86,13 +86,15 @@ export function hrefChat(params: { isGroupChat?: boolean; groupId?: string; groupName?: string; + groupAvatar?: string; }): string { - const { conversationId, userId, isGroupChat, groupId, groupName } = params; + const { conversationId, userId, isGroupChat, groupId, groupName, groupAvatar } = params; const q = new URLSearchParams(); if (userId) q.set('userId', userId); if (isGroupChat) q.set('isGroupChat', '1'); if (groupId != null && groupId !== '') q.set('groupId', String(groupId)); if (groupName) q.set('groupName', groupName); + if (groupAvatar) q.set('groupAvatar', groupAvatar); const qs = q.toString(); return `/chat/${encodeURIComponent(conversationId)}${qs ? `?${qs}` : ''}`; } diff --git a/src/screens/message/ChatScreen.tsx b/src/screens/message/ChatScreen.tsx index a6b1cec..ca0f92d 100644 --- a/src/screens/message/ChatScreen.tsx +++ b/src/screens/message/ChatScreen.tsx @@ -165,8 +165,8 @@ export const ChatScreen: React.FC = (props) => { muteAll, followRestrictionHint, canSendPrivateImage, - routeGroupId, - routeGroupName, + effectiveGroupId, + effectiveGroupName, otherUserLastReadSeq, messageMap, loadingMore, @@ -458,7 +458,7 @@ export const ChatScreen: React.FC = (props) => { isGroupChat={isGroupChat} groupInfo={groupInfo} otherUser={otherUser} - routeGroupName={routeGroupName ?? undefined} + routeGroupName={effectiveGroupName ?? undefined} typingHint={typingHint} onBack={props.onEmbeddedBack ? props.onEmbeddedBack : () => router.back()} onTitlePress={navigateToInfo} @@ -669,7 +669,7 @@ export const ChatScreen: React.FC = (props) => { {/* 群信息侧边栏面板 - 仅大屏幕显示 */} { conversationId: String(conversation.id), groupId: String(conversation.group.id), groupName: conversation.group.name, + groupAvatar: conversation.group.avatar, isGroupChat: true, }) ); diff --git a/src/screens/message/components/ChatScreen/useChatScreen.ts b/src/screens/message/components/ChatScreen/useChatScreen.ts index 5ebbc81..3266caf 100644 --- a/src/screens/message/components/ChatScreen/useChatScreen.ts +++ b/src/screens/message/components/ChatScreen/useChatScreen.ts @@ -96,6 +96,7 @@ export const useChatScreen = (props?: ChatScreenProps) => { isGroupChat?: string | string[]; groupId?: string | string[]; groupName?: string | string[]; + groupAvatar?: string | string[]; }>(); // 路由参数(动态段 + query);群 ID 勿用 Number(),避免超过 2^53-1 时精度丢失 // 嵌入式模式下优先使用 props,否则从路由参数获取 @@ -107,6 +108,7 @@ export const useChatScreen = (props?: ChatScreenProps) => { isGroupChat: props.embeddedIsGroupChat ?? false, groupId: props.embeddedGroupId ?? null, groupName: props.embeddedGroupName ?? null, + groupAvatar: null as string | null, }; } const isGroupFlag = firstRouteParam(rawParams.isGroupChat); @@ -116,6 +118,7 @@ export const useChatScreen = (props?: ChatScreenProps) => { isGroupChat: isGroupFlag === '1' || isGroupFlag === 'true', groupId: firstRouteParam(rawParams.groupId), groupName: firstRouteParam(rawParams.groupName), + groupAvatar: firstRouteParam(rawParams.groupAvatar), }; }, [ props?.embeddedConversationId, @@ -127,9 +130,10 @@ export const useChatScreen = (props?: ChatScreenProps) => { rawParams.isGroupChat, rawParams.groupId, rawParams.groupName, + rawParams.groupAvatar, ]); - const { conversationId: routeConversationId, userId: routeUserId, isGroupChat, groupId: routeGroupId, groupName: routeGroupName } = routeParams; + const { conversationId: routeConversationId, userId: routeUserId, isGroupChat, groupId: routeGroupId, groupName: routeGroupName, groupAvatar: routeGroupAvatar } = routeParams; // 当前会话ID(可能在新建私聊会话后动态更新) const [conversationId, setConversationId] = useState(routeConversationId); @@ -147,13 +151,18 @@ export const useChatScreen = (props?: ChatScreenProps) => { conversation, } = useChat(conversationId); + // 统一入口:优先路由参数,其次从 conversation 对象提取(JPUSH 进入时 conversation 异步加载) + const effectiveGroupId = routeGroupId || (isGroupChat && conversation?.group?.id) || null; + const effectiveGroupName = routeGroupName || (isGroupChat && conversation?.group?.name) || null; + const effectiveGroupAvatar = routeGroupAvatar || (isGroupChat && conversation?.group?.avatar) || null; + // 本地状态 const [currentUserId, setCurrentUserId] = useState(''); // 【新架构】使用 MessageManager 获取群聊输入状态和禁言状态 - const { typingUsers: groupTypingUsers } = useGroupTyping(routeGroupId ? String(routeGroupId) : null); + const { typingUsers: groupTypingUsers } = useGroupTyping(effectiveGroupId ? String(effectiveGroupId) : null); const { isMuted: isMutedFromManager, setMuted: setMutedStatus } = useGroupMuted( - routeGroupId ? String(routeGroupId) : null, + effectiveGroupId ? String(effectiveGroupId) : null, currentUserId ); @@ -202,8 +211,18 @@ export const useChatScreen = (props?: ChatScreenProps) => { const [selectedMessageId, setSelectedMessageId] = useState(null); // 群聊相关状态 - const [groupInfo, setGroupInfo] = useState<{ name?: string; member_count?: number } | null>(null); + const [groupInfo, setGroupInfo] = useState<{ name?: string; member_count?: number; avatar?: string | null } | null>(null); const [groupMembers, setGroupMembers] = useState([]); + + // 群名/头像:优先使用路由参数(JPUSH extras),其次从 conversation 对象获取 + useEffect(() => { + if (!isGroupChat) return; + const name = effectiveGroupName; + const avatar = effectiveGroupAvatar; + if (name || avatar) { + setGroupInfo(prev => prev ? prev : { name: name || undefined, avatar: avatar || null }); + } + }, [isGroupChat, effectiveGroupName, effectiveGroupAvatar]); const [currentUserRole, setCurrentUserRole] = useState('member'); const [mentionQuery, setMentionQuery] = useState(''); const [selectedMentions, setSelectedMentions] = useState([]); @@ -453,14 +472,14 @@ export const useChatScreen = (props?: ChatScreenProps) => { // 群聊模式:获取群组信息和成员列表 useEffect(() => { - if (!isGroupChat || !routeGroupId) return; + if (!isGroupChat || !effectiveGroupId) return; const fetchGroupInfo = async () => { try { - const group = await groupManager.getGroup(routeGroupId); + const group = await groupManager.getGroup(effectiveGroupId); setGroupInfo(group); - const membersResponse = await groupManager.getMembers(routeGroupId, 1, MEMBERS_PAGE_SIZE); + const membersResponse = await groupManager.getMembers(effectiveGroupId, 1, MEMBERS_PAGE_SIZE); const members = membersResponse.list || []; setGroupMembers(members); @@ -470,7 +489,7 @@ export const useChatScreen = (props?: ChatScreenProps) => { } try { - const myInfo = await groupService.getMyMemberInfo(routeGroupId); + const myInfo = await groupService.getMyMemberInfo(effectiveGroupId); setIsMuted(myInfo.is_muted); setMutedStatus(myInfo.is_muted); setMuteAll(myInfo.mute_all); @@ -508,7 +527,7 @@ export const useChatScreen = (props?: ChatScreenProps) => { if (currentUserId) { fetchGroupInfo(); } - }, [isGroupChat, routeGroupId, currentUserId, setMutedStatus]); + }, [isGroupChat, effectiveGroupId, currentUserId, setMutedStatus]); // 私聊模式:创建或获取会话 useEffect(() => { @@ -1066,7 +1085,7 @@ export const useChatScreen = (props?: ChatScreenProps) => { return; } - if (isGroupChat && routeGroupId) { + if (isGroupChat && effectiveGroupId) { await messageService.sendMessageByAction('group', conversationId, segments); setInputText(''); @@ -1097,7 +1116,7 @@ export const useChatScreen = (props?: ChatScreenProps) => { pendingAttachments, conversationId, isGroupChat, - routeGroupId, + effectiveGroupId, sendMessageViaManager, isMuted, muteAll, @@ -1264,7 +1283,7 @@ export const useChatScreen = (props?: ChatScreenProps) => { try { const segments = buildImageSegments(stickerUrl, stickerUrl, undefined, undefined, replyingTo); - if (isGroupChat && routeGroupId) { + if (isGroupChat && effectiveGroupId) { await messageService.sendMessageByAction('group', conversationId, segments); setReplyingTo(null); } else { @@ -1282,7 +1301,7 @@ export const useChatScreen = (props?: ChatScreenProps) => { } finally { setSendingImage(false); } - }, [conversationId, isGroupChat, routeGroupId, sendMessageViaManager, isMuted, muteAll, buildImageSegments, replyingTo, canSendPrivateImage, scrollToLatest]); + }, [conversationId, isGroupChat, effectiveGroupId, sendMessageViaManager, isMuted, muteAll, buildImageSegments, replyingTo, canSendPrivateImage, scrollToLatest]); // 切换表情面板 const toggleEmojiPanel = useCallback(() => { @@ -1310,7 +1329,7 @@ export const useChatScreen = (props?: ChatScreenProps) => { // 撤回消息 - 现在通过 MessageManager 处理 const handleRecall = useCallback(async (messageId: string) => { try { - if (isGroupChat && routeGroupId) { + if (isGroupChat && effectiveGroupId) { await messageService.recallMessage(messageId); } else { await messageService.recallMessage(messageId); @@ -1320,7 +1339,7 @@ export const useChatScreen = (props?: ChatScreenProps) => { console.error('撤回消息失败:', error); Alert.alert('撤回失败', '无法撤回消息'); } - }, [isGroupChat, routeGroupId, conversationId]); + }, [isGroupChat, effectiveGroupId, conversationId]); // 长按消息显示操作菜单 const handleLongPressMessage = useCallback((message: GroupMessage, position?: MenuPosition) => { @@ -1455,17 +1474,17 @@ export const useChatScreen = (props?: ChatScreenProps) => { // 导航到群组信息或用户资料 const navigateToInfo = useCallback(() => { - if (isGroupChat && routeGroupId) { - router.push(hrefs.hrefGroupInfo(routeGroupId, conversationId || undefined)); + if (isGroupChat && effectiveGroupId) { + router.push(hrefs.hrefGroupInfo(effectiveGroupId, conversationId || undefined)); } else if (otherUser?.id) { router.push(hrefs.hrefUserProfile(String(otherUser.id))); } - }, [isGroupChat, routeGroupId, otherUser, conversationId]); + }, [isGroupChat, effectiveGroupId, otherUser, conversationId]); // 导航到聊天管理页面 const navigateToChatSettings = useCallback(() => { - if (isGroupChat && routeGroupId) { - router.push(hrefs.hrefGroupInfo(routeGroupId, conversationId || undefined)); + if (isGroupChat && effectiveGroupId) { + router.push(hrefs.hrefGroupInfo(effectiveGroupId, conversationId || undefined)); } else if (otherUser?.id && conversationId) { router.push( hrefs.hrefPrivateChatInfo({ @@ -1476,7 +1495,7 @@ export const useChatScreen = (props?: ChatScreenProps) => { }) ); } - }, [isGroupChat, routeGroupId, otherUser, conversationId]); + }, [isGroupChat, effectiveGroupId, otherUser, conversationId]); return { // 状态 @@ -1512,8 +1531,8 @@ export const useChatScreen = (props?: ChatScreenProps) => { muteAll, followRestrictionHint, canSendPrivateImage, - routeGroupId, - routeGroupName, + effectiveGroupId, + effectiveGroupName, otherUserLastReadSeq, messageMap, loadingMore, diff --git a/src/stores/message/MessageManager.ts b/src/stores/message/MessageManager.ts index 86806ca..c95666b 100644 --- a/src/stores/message/MessageManager.ts +++ b/src/stores/message/MessageManager.ts @@ -344,6 +344,11 @@ class MessageManager { } const task = (async () => { + // 确保会话数据在 store 中(JPUSH 通知进入时 store 可能还没有此会话) + const store = useMessageStore.getState(); + if (!store.getConversation(normalizedId)) { + await this.fetchConversationDetail(normalizedId); + } await this.fetchMessages(normalizedId); })(); this.activatingConversationTasks.set(normalizedId, task);