/** * 用户主页 UserScreen(响应式适配) * 胡萝卜BBS - 查看其他用户资料 * 支持桌面端双栏布局 */ import React, { useState, useEffect, useCallback } from 'react'; import { View, FlatList, StyleSheet, RefreshControl, ScrollView, Alert, } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { useNavigation, useRoute, RouteProp } from '@react-navigation/native'; import { NativeStackNavigationProp } from '@react-navigation/native-stack'; import { colors, spacing } from '../../theme'; import { Post, User } from '../../types'; import { useUserStore } from '../../stores'; import { useCurrentUser } from '../../stores/authStore'; import { authService, postService, messageService } from '../../services'; import { userManager } from '../../stores/userManager'; import { UserProfileHeader, PostCard, TabBar } from '../../components/business'; import { Loading, EmptyState, ResponsiveContainer } from '../../components/common'; import { useResponsive } from '../../hooks'; import { HomeStackParamList, RootStackParamList } from '../../navigation/types'; type NavigationProp = NativeStackNavigationProp; type UserRouteProp = RouteProp; const TABS = ['帖子', '收藏']; const TAB_ICONS = ['file-document-outline', 'bookmark-outline']; export const UserScreen: React.FC = () => { const navigation = useNavigation(); const route = useRoute(); const userId = route.params?.userId || ''; // 使用 any 类型来访问根导航 const rootNavigation = useNavigation>(); const { followUser, unfollowUser, likePost, unlikePost, favoritePost, unfavoritePost, posts: storePosts } = useUserStore(); const currentUser = useCurrentUser(); // 响应式布局 const { isDesktop, isTablet } = useResponsive(); const [user, setUser] = useState(null); const [posts, setPosts] = useState([]); const [favorites, setFavorites] = useState([]); const [loading, setLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); const [activeTab, setActiveTab] = useState(0); const [isBlocked, setIsBlocked] = useState(false); // 加载用户信息 const loadUserData = useCallback(async (forceRefresh = false) => { if (!userId) { setLoading(false); return; } try { // 强制从服务器获取最新数据,确保关注状态是最新的 const userData = await userManager.getUserById(userId, forceRefresh); setUser(userData || null); const blockStatus = await authService.getBlockStatus(userId); setIsBlocked(blockStatus); const response = await postService.getUserPosts(userId); setPosts(response.list); } catch (error) { console.error('加载用户数据失败:', error); } setLoading(false); }, [userId]); // 加载用户收藏 const loadUserFavorites = useCallback(async () => { if (!userId) return; try { console.log('[UserScreen] getUserFavorites called, userId:', userId); const response = await postService.getUserFavorites(userId); console.log('[UserScreen] getUserFavorites response:', response); setFavorites(response.list); } catch (error) { console.error('获取用户收藏失败:', error); } }, [userId]); // 监听 tab 切换 useEffect(() => { if (activeTab === 1) { loadUserFavorites(); } }, [activeTab, loadUserFavorites]); useEffect(() => { // 首次加载时强制刷新,确保关注状态是最新的 loadUserData(true); }, [loadUserData]); // 同步 store 中的帖子状态到本地(用于点赞、收藏等状态更新) useEffect(() => { // 同步帖子列表状态 if (posts.length > 0) { let hasChanges = false; const updatedPosts = posts.map(localPost => { const storePost = storePosts.find(sp => sp.id === localPost.id); if (storePost && ( storePost.is_liked !== localPost.is_liked || storePost.is_favorited !== localPost.is_favorited || storePost.likes_count !== localPost.likes_count || storePost.favorites_count !== localPost.favorites_count )) { hasChanges = true; return { ...localPost, is_liked: storePost.is_liked, is_favorited: storePost.is_favorited, likes_count: storePost.likes_count, favorites_count: storePost.favorites_count, }; } return localPost; }); if (hasChanges) { setPosts(updatedPosts); } } // 同步收藏列表状态 if (favorites.length > 0) { let hasChanges = false; const updatedFavorites = favorites.map(localPost => { const storePost = storePosts.find(sp => sp.id === localPost.id); if (storePost && ( storePost.is_liked !== localPost.is_liked || storePost.is_favorited !== localPost.is_favorited || storePost.likes_count !== localPost.likes_count || storePost.favorites_count !== localPost.favorites_count )) { hasChanges = true; return { ...localPost, is_liked: storePost.is_liked, is_favorited: storePost.is_favorited, likes_count: storePost.likes_count, favorites_count: storePost.favorites_count, }; } return localPost; }); if (hasChanges) { setFavorites(updatedFavorites); } } }, [storePosts]); // 下拉刷新 const onRefresh = useCallback(() => { setRefreshing(true); loadUserData(true); setRefreshing(false); }, [loadUserData]); // 关注/取消关注 const handleFollow = () => { if (!user) return; if (user.is_following) { unfollowUser(user.id); setUser({ ...user, is_following: false, followers_count: user.followers_count - 1 }); } else { followUser(user.id); setUser({ ...user, is_following: true, followers_count: user.followers_count + 1 }); } }; // 跳转到关注列表 const handleFollowingPress = () => { (rootNavigation as any).navigate('FollowList', { userId, type: 'following' }); }; // 跳转到粉丝列表 const handleFollowersPress = () => { (rootNavigation as any).navigate('FollowList', { userId, type: 'followers' }); }; // 跳转到帖子详情 const handlePostPress = (postId: string, scrollToComments: boolean = false) => { navigation.navigate('PostDetail', { postId, scrollToComments }); }; // 跳转到用户主页(这里不做处理) const handleUserPress = (postUserId: string) => { if (postUserId !== userId) { navigation.push('UserProfile', { userId: postUserId }); } }; // 删除帖子 const handleDeletePost = async (postId: string) => { try { const success = await postService.deletePost(postId); if (success) { // 从帖子列表中移除 setPosts(prev => prev.filter(p => p.id !== postId)); // 也从收藏列表中移除(如果存在) setFavorites(prev => prev.filter(p => p.id !== postId)); } else { console.error('删除帖子失败'); } } catch (error) { console.error('删除帖子失败:', error); throw error; } }; // 跳转到聊天界面 const handleMessage = async () => { if (!user) return; try { // 前端只提供对方的用户ID,会话ID由后端生成 const conversation = await messageService.createConversation(user.id); if (conversation) { // 跳转到聊天界面 - 使用 rootNavigation 确保在正确的导航栈中 (rootNavigation as any).navigate('Chat', { conversationId: conversation.id.toString(), userId: user.id }); } } catch (error) { console.error('创建会话失败:', error); } }; // 处理更多按钮点击 const handleMore = () => { if (!user) return; Alert.alert( '更多操作', undefined, [ { text: '取消', style: 'cancel' }, { text: isBlocked ? '取消拉黑' : '拉黑用户', style: 'destructive', onPress: () => { Alert.alert( isBlocked ? '确认取消拉黑' : '确认拉黑', isBlocked ? '取消拉黑后,对方可以重新与你建立关系。' : '拉黑后,对方将无法给你发送私聊消息,且会互相移除关注关系。', [ { text: '取消', style: 'cancel' }, { text: '确定', style: 'destructive', onPress: async () => { const ok = isBlocked ? await authService.unblockUser(user.id) : await authService.blockUser(user.id); if (!ok) { Alert.alert('失败', isBlocked ? '取消拉黑失败,请稍后重试' : '拉黑失败,请稍后重试'); return; } setUser(prev => prev ? { ...prev, is_following: false, is_following_me: false, } : prev ); setIsBlocked(!isBlocked); Alert.alert('成功', isBlocked ? '已取消拉黑' : '已拉黑该用户'); }, }, ] ); }, }, ] ); }; // 渲染内容 const renderContent = () => { if (loading) return ; if (activeTab === 0) { // 帖子 if (posts.length === 0) { return ( ); } return ( {posts.map((post, index) => { const isPostAuthor = currentUser?.id === post.author?.id; return ( handlePostPress(post.id)} onUserPress={() => post.author ? handleUserPress(post.author.id) : () => {}} onLike={() => post.is_liked ? unlikePost(post.id) : likePost(post.id)} onComment={() => handlePostPress(post.id, true)} onBookmark={() => post.is_favorited ? unfavoritePost(post.id) : favoritePost(post.id)} onShare={() => {}} onDelete={() => handleDeletePost(post.id)} isPostAuthor={isPostAuthor} /> ); })} ); } if (activeTab === 1) { // 收藏 if (favorites.length === 0) { return ( ); } return ( {favorites.map((post, index) => { const isPostAuthor = currentUser?.id === post.author?.id; return ( handlePostPress(post.id)} onUserPress={() => post.author ? handleUserPress(post.author.id) : () => {}} onLike={() => post.is_liked ? unlikePost(post.id) : likePost(post.id)} onComment={() => handlePostPress(post.id, true)} onBookmark={() => post.is_favorited ? unfavoritePost(post.id) : favoritePost(post.id)} onShare={() => {}} onDelete={() => handleDeletePost(post.id)} isPostAuthor={isPostAuthor} /> ); })} ); } return null; }; // 渲染用户信息头部 const renderUserHeader = () => { if (!user) return null; return ( ); }; // 渲染 TabBar 和内容 const renderTabBarAndContent = () => ( <> {renderContent()} ); if (loading) { return ; } if (!user) { return ( ); } // 桌面端使用双栏布局 if (isDesktop || isTablet) { return ( {/* 左侧:用户信息 */} } > {renderUserHeader()} {/* 右侧:帖子列表 */} {renderTabBarAndContent()} ); } // 移动端使用单栏布局 return ( ( {renderUserHeader()} {renderContent()} )} keyExtractor={item => item.key} showsVerticalScrollIndicator={false} refreshControl={ } /> ); }; const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: colors.background.default, }, // 桌面端双栏布局 desktopContainer: { flex: 1, flexDirection: 'row', gap: spacing.lg, padding: spacing.lg, }, desktopSidebar: { width: 380, flexShrink: 0, }, desktopContent: { flex: 1, minWidth: 0, }, desktopScrollContent: { flexGrow: 1, }, tabBarContainer: { marginTop: spacing.sm, marginBottom: spacing.xs, }, contentContainer: { flex: 1, minHeight: 350, paddingTop: spacing.sm, }, postsContainer: { paddingHorizontal: spacing.md, paddingTop: spacing.sm, }, postWrapper: { marginBottom: spacing.md, backgroundColor: colors.background.paper, borderRadius: 16, overflow: 'hidden', shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.06, shadowRadius: 8, elevation: 2, }, lastPost: { marginBottom: spacing['2xl'], }, }); export default UserScreen;