修正帖子列表、帖子详情的头像与名字显示问题

Change-Id: Ibcb01510f9474ea43c8739f3013c3aaa32e32640
diff --git a/Merge/back_rhj/app/user_post_graph.txt b/Merge/back_rhj/app/user_post_graph.txt
index f8ef7df..f2f2e58 100644
--- a/Merge/back_rhj/app/user_post_graph.txt
+++ b/Merge/back_rhj/app/user_post_graph.txt
@@ -1,12 +1,7 @@
-0	0 0 1 1 0 1 0 11	1749827292 1749953091 1749953091 1749953480 1749953480 1749954059 1749954059 1749955282	1 1 2 2 1 2 1 5
-1	1 4 0 12	1749827292 1749955282 1749955282 1749955282	5 5 2 1
-2	6 5 6 5 13 1 0 0 1 1 2	1749953091 1749953091 1749953480 1749953480 1749955282 1749955282 1750372189 1750372215 1750372231 1750372241 1750372258	2 1 2 1 2 5 3 2 3 2 2
-3	2 2 0	1749953091 1749953480 1749954059	2 2 2
-4	1 5	1749954059 1749955282	5 5
-5	2 6	1749955282 1749955282	5 1
-6	7	1749955282	2
-7	3 8	1749955282 1749955282	2 5
-8	9	1749955282	1
-9	10	1749955282	2
-10	12	1749894174	5
-11	1 4 7 0 2 13 4 11	1750372862 1750372873 1750373008 1750373592 1750373596 1750374164 1750374867 1750374871	3 3 3 2 2 2 2 2
+0	0 0 1 0 1 0 1	1749827292 1749953091 1749953091 1749953480 1749953480 1749954059 1749954059	1 1 2 1 2 1 2
+1	1 0 3	1749827292 1749955282 1749955282	5 2 5
+2	1 0 0 1 1	1749955282 1750372189 1750372215 1750372231 1750372241	5 3 2 3 2
+3	0	1749954059	2
+4	1	1749954059	5
+5	2	1749955282	2
+6	1 3 0 3 0	1750372862 1750372873 1750373592 1750374867 1750392753	3 3 2 2 3
diff --git a/Merge/front/src/api/api_ljc.js b/Merge/front/src/api/api_ljc.js
index b8130ca..1adea99 100644
--- a/Merge/front/src/api/api_ljc.js
+++ b/Merge/front/src/api/api_ljc.js
@@ -1,4 +1,5 @@
 import axios from 'axios';
+import { getUserInfo } from '../utils/auth';
 
 const api = axios.create({
   baseURL: 'http://10.126.59.25:5715/api/',
@@ -14,8 +15,12 @@
 export const getFavorites = (userId) => api.get(`/user/${userId}/favorites`);
 
 // 关注相关API
-export const followUser = (followeeId) => api.post(`/follow/${followeeId}`);
-export const unfollowUser = (followeeId) => api.delete(`/follow/${followeeId}`);
+export const followUser = (followeeId) => {
+  return api.post(`/follow/${followeeId}`);
+};
+export const unfollowUser = (followeeId) => {
+  return api.delete(`/follow/${followeeId}`);
+};
 
 // 帖子相关API
 export const getUserPosts = (userId) => api.get(`/user/${userId}/posts`);
diff --git a/Merge/front/src/api/posts_api.js b/Merge/front/src/api/posts_api.js
index a336da0..06cf2c7 100644
--- a/Merge/front/src/api/posts_api.js
+++ b/Merge/front/src/api/posts_api.js
@@ -2,7 +2,7 @@
 // 整合不同后端服务的帖子功能
 
 // WZY 后端服务 - 帖子CRUD、点赞、评论
-const WZY_BASE_URL = 'http://10.126.59.25:5714'
+const WZY_BASE_URL = 'http://192.168.5.235:5714'
 // LJC 后端服务 - 用户相关功能
 const LJC_BASE_URL = 'http://10.126.59.25:5715'
 
diff --git a/Merge/front/src/api/search_jwlll.js b/Merge/front/src/api/search_jwlll.js
index 085507b..01b743f 100644
--- a/Merge/front/src/api/search_jwlll.js
+++ b/Merge/front/src/api/search_jwlll.js
@@ -5,7 +5,7 @@
 // JWLLL 后端服务 - 仅用于推荐和搜索
 const JWLLL_BASE_URL = 'http://10.126.59.25:5717'
 // WZY 后端服务 - 用于帖子详情、点赞、评论等
-const WZY_BASE_URL = 'http://10.126.59.25:5714'
+const WZY_BASE_URL = 'http://192.168.5.235:5714'
 
 // 通用请求函数
 const request = async (url, options = {}) => {
diff --git a/Merge/front/src/components/FollowButton.jsx b/Merge/front/src/components/FollowButton.jsx
index 0776191..3e94161 100644
--- a/Merge/front/src/components/FollowButton.jsx
+++ b/Merge/front/src/components/FollowButton.jsx
@@ -1,31 +1,50 @@
-import React from 'react';
+import React, { useState } from 'react';
 import { followUser, unfollowUser } from '../api/api_ljc';
 
-const FollowButton = ({ userId, isFollowing, onFollowChange }) => {
+const FollowButton = ({ userId, isFollowing, onFollowChange, style }) => {
+  const [loading, setLoading] = useState(false);
   const handleFollow = async () => {
+    if (loading) return;
+    setLoading(true);
     try {
+      console.log('FollowButton clicked, isFollowing:', isFollowing, 'userId:', userId);
       if (isFollowing) {
-        await unfollowUser(userId);
+        const res = await unfollowUser(userId);
+        console.log('unfollowUser response:', res);
         onFollowChange(false);
       } else {
-        await followUser(userId);
+        const res = await followUser(userId);
+        console.log('followUser response:', res);
         onFollowChange(true);
       }
     } catch (error) {
+      alert('关注操作失败,请重试!');
       console.error('关注操作失败:', error);
+    } finally {
+      setLoading(false);
     }
   };
 
   return (
-    <button 
+    <button
       onClick={handleFollow}
-      className={`px-6 py-2 rounded-full text-sm font-medium transition-all ${
-        isFollowing 
-          ? 'bg-gray-100 text-gray-800 hover:bg-gray-200' 
-          : 'bg-red-500 text-white hover:bg-red-600'
-      }`}
+      disabled={loading}
+      style={{
+        border: 'none',
+        outline: 'none',
+        borderRadius: 20,
+        padding: '6px 22px',
+        fontSize: 15,
+        fontWeight: 600,
+        cursor: loading ? 'not-allowed' : 'pointer',
+        background: isFollowing ? '#f5f5f5' : 'linear-gradient(90deg,#ff4b2b,#ff416c)',
+        color: isFollowing ? '#888' : '#fff',
+        boxShadow: isFollowing ? 'none' : '0 2px 8px #ff416c22',
+        transition: 'all 0.2s',
+        ...style
+      }}
     >
-      {isFollowing ? '已关注' : '关注'}
+      {loading ? '处理中...' : isFollowing ? '已关注' : '+ 关注'}
     </button>
   );
 };
diff --git a/Merge/front/src/components/HomeFeed.jsx b/Merge/front/src/components/HomeFeed.jsx
index 1fb12a5..2e42621 100644
--- a/Merge/front/src/components/HomeFeed.jsx
+++ b/Merge/front/src/components/HomeFeed.jsx
@@ -7,6 +7,7 @@
 import { searchAPI } from '../api/search_jwlll'
 import { getUserInfo } from '../utils/auth'
 import { deepRecommend } from '../api/recommend_rhj'
+import postsAPI from '../api/posts_api'
 import '../style/HomeFeed.css'
 
 const categories = [
@@ -40,6 +41,7 @@
   const [recMode, setRecMode] = useState('tag')
   const [recCFNum, setRecCFNum] = useState(20)
   const [useSearchRecommend, setUseSearchRecommend] = useState(false) // 是否使用搜索推荐模式  // JWLLL 搜索推荐功能函数
+  const [userMap, setUserMap] = useState({}) // user_id: {username, nickname}
   
   // JWLLL搜索推荐内容
   const fetchSearchContent = useCallback(async (keyword = '') => {
@@ -47,16 +49,34 @@
     setError(null)
     try {
       const data = await searchAPI.search(keyword || activeCat, activeCat === '推荐' ? undefined : activeCat)
-      const formattedItems = (data.results || []).map(item => ({
-        id: item.id,
-        title: item.title,
-        author: item.author || '佚名',
-        avatar: `https://i.pravatar.cc/40?img=${item.id}`,
-        img: item.img || '', 
-        likes: item.heat || 0,
-        content: item.content
-      }))
-      setItems(formattedItems)
+      // 新增:拉取详情,保证和推荐一致
+      const detailed = await Promise.all(
+        (data.results || []).map(async item => {
+          try {
+            const d = await fetchPost(item.id)
+            return {
+              id:     d.id,
+              title:  d.title,
+              author: `作者 ${d.user_id}`,
+              avatar: `https://i.pravatar.cc/40?img=${d.user_id}`,
+              img:    d.media_urls?.[0] || '',
+              likes:  d.heat,
+              content: d.content || ''
+            }
+          } catch {
+            return {
+              id: item.id,
+              title: item.title,
+              author: item.author || '佚名',
+              avatar: `https://i.pravatar.cc/40?img=${item.id}`,
+              img: item.img || '',
+              likes: item.heat || 0,
+              content: item.content || ''
+            }
+          }
+        })
+      )
+      setItems(detailed)
     } catch (e) {
       console.error('搜索失败:', e)
       setError('搜索失败')
@@ -213,6 +233,20 @@
     setLoading(false)
   }, [recMode, fetchTagRecommend, fetchCFRecommend, fetchDeepRecommend])
 
+  // 拉取所有涉及用户的昵称
+  const fetchUserNames = async (userIds) => {
+    const map = {}
+    await Promise.all(userIds.map(async uid => {
+      try {
+        const user = await postsAPI.getUser(uid)
+        map[uid] = user.username || user.nickname || `用户${uid}`
+      } catch {
+        map[uid] = `用户${uid}`
+      }
+    }))
+    setUserMap(map)
+  }
+
   useEffect(() => {
     // 原始数据加载函数
     const loadPosts = async () => {
@@ -225,7 +259,7 @@
             return {
               id:     d.id,
               title:  d.title,
-              author: `作者 ${d.user_id}`,
+              authorId: d.user_id,
               avatar: `https://i.pravatar.cc/40?img=${d.user_id}`,
               img:    d.media_urls?.[0] || '', // 用第一张媒体作为封面
               likes:  d.heat
@@ -233,6 +267,9 @@
           })
         )
         setItems(detailed)
+        // 拉取所有涉及用户的昵称
+        const userIds = [...new Set(detailed.map(i => i.authorId))]
+        fetchUserNames(userIds)
       } catch (e) {
         setError(e.message)
       } finally {
@@ -399,8 +436,8 @@
                 {item.content && <div className="card-content">{item.content.slice(0, 60) || ''}</div>}
                 <div className="card-footer">
                   <div className="card-author">
-                    <img className="avatar" src={item.avatar} alt={item.author} />
-                    <span className="username">{item.author}</span>
+                    <img className="avatar" src={item.avatar} alt={userMap[item.authorId] || item.authorId} />
+                    <span className="username">{userMap[item.authorId] || item.authorId}</span>
                   </div>
                   <div className="card-likes">
                     <ThumbsUp size={16} />
diff --git a/Merge/front/src/components/PostDetailJWLLL.jsx b/Merge/front/src/components/PostDetailJWLLL.jsx
index 009ba6c..cc5eb96 100644
--- a/Merge/front/src/components/PostDetailJWLLL.jsx
+++ b/Merge/front/src/components/PostDetailJWLLL.jsx
@@ -3,6 +3,8 @@
 import { ArrowLeft, ThumbsUp, MessageCircle, Share2, BookmarkPlus, Heart, Eye } from 'lucide-react'
 import { searchAPI } from '../api/search_jwlll'
 import { getUserInfo } from '../utils/auth'
+import FollowButton from './FollowButton'
+import postsAPI from '../api/posts_api'
 import '../style/PostDetail.css'
 
 export default function PostDetail() {
@@ -17,6 +19,8 @@
   const [comments, setComments] = useState([])
   const [newComment, setNewComment] = useState('')
   const [showComments, setShowComments] = useState(false)
+  const [isFollowing, setIsFollowing] = useState(false)
+  const [authorInfo, setAuthorInfo] = useState(null)
   // 获取当前用户ID
   const getCurrentUserId = () => {
     const userInfo = getUserInfo()
@@ -47,6 +51,33 @@
     }
   }, [id])
 
+  // 检查当前用户是否已关注发帖人
+  useEffect(() => {
+    if (post && post.user_id) {
+      // 这里假设有API postsAPI.getUserFollowing
+      const checkFollow = async () => {
+        try {
+          const userInfo = getUserInfo()
+          if (!userInfo?.id) return
+          const res = await postsAPI.getUserFollowing(userInfo.id)
+          if (Array.isArray(res)) {
+            setIsFollowing(res.some(u => u.id === post.user_id))
+          } else if (Array.isArray(res.following)) {
+            setIsFollowing(res.following.some(u => u.id === post.user_id))
+          }
+        } catch {}
+      }
+      checkFollow()
+    }
+  }, [post])
+
+  // 拉取发帖人信息
+  useEffect(() => {
+    if (post && post.user_id) {
+      postsAPI.getUser(post.user_id).then(res => setAuthorInfo(res || {})).catch(() => setAuthorInfo({}))
+    }
+  }, [post])
+
   useEffect(() => {
     fetchPostDetail()
     fetchComments()
@@ -108,6 +139,24 @@
     }
   }
 
+  // 关注后刷新关注状态
+  const handleFollowChange = async (followed) => {
+    setIsFollowing(followed)
+    // 关注/取关后重新拉取一次关注状态,保证和数据库同步
+    if (post && post.user_id) {
+      try {
+        const userInfo = getUserInfo()
+        if (!userInfo?.id) return
+        const res = await postsAPI.getUserFollowing(userInfo.id)
+        if (Array.isArray(res)) {
+          setIsFollowing(res.some(u => u.id === post.user_id))
+        } else if (Array.isArray(res.following)) {
+          setIsFollowing(res.following.some(u => u.id === post.user_id))
+        }
+      } catch {}
+    }
+  }
+
   if (loading) {
     return (
       <div className="post-detail">
@@ -119,6 +168,7 @@
     )
   }
 
+  // 优化错误和不存在的判断逻辑
   if (error) {
     return (
       <div className="post-detail">
@@ -134,11 +184,12 @@
     )
   }
 
-  if (!post) {
+  // 只有明确为 null 或 undefined 时才显示不存在
+  if (post === null || post === undefined) {
     return (
       <div className="post-detail">
         <div className="error-container">
-          <h2>😔 帖子不存在</h2>
+          <h2>😔 帖子不存在或已被删除</h2>
           <p>该帖子可能已被删除或不存在</p>
           <button onClick={handleBack} className="back-btn">
             <ArrowLeft size={20} />
@@ -179,13 +230,26 @@
         <div className="post-meta">
           <div className="author-info">
             <div className="avatar">
-              {post.author ? post.author.charAt(0).toUpperCase() : 'U'}
+              {authorInfo && authorInfo.avatar && authorInfo.avatar.startsWith('http') ? (
+                <img className="avatar" src={authorInfo.avatar} alt={authorInfo.username || authorInfo.nickname || post.author || '用户'} />
+              ) : (
+                <img className="avatar" src={`https://i.pravatar.cc/40?img=${post.user_id}`} alt={authorInfo?.username || authorInfo?.nickname || post.author || '用户'} />
+              )}
             </div>
             <div className="author-details">
-              <span className="author-name">{post.author || '匿名用户'}</span>
+              <span className="author-name">{authorInfo?.username || authorInfo?.nickname || post.author || '匿名用户'}</span>
               <span className="post-date">
                 {post.create_time ? new Date(post.create_time).toLocaleDateString('zh-CN') : '未知时间'}
               </span>
+              {/* 关注按钮 */}
+              {post.user_id && (
+                <FollowButton
+                  userId={post.user_id}
+                  isFollowing={isFollowing}
+                  onFollowChange={handleFollowChange}
+                  style={{marginLeft: 12}}
+                />
+              )}
             </div>
           </div>
           <div className="post-stats">
diff --git a/Merge/front/src/components/UserProfile.jsx b/Merge/front/src/components/UserProfile.jsx
index 53618db..6cddcbd 100644
--- a/Merge/front/src/components/UserProfile.jsx
+++ b/Merge/front/src/components/UserProfile.jsx
@@ -279,7 +279,6 @@
 
   const handleFollowToggle = async () => {
     if (!currentUser || !profileUser) return;
-    
     try {
       if (profileUser.is_following) {
         await unfollowUserApi(profileUser.id);
@@ -288,11 +287,18 @@
         await followUserApi(profileUser.id);
         showSnackbar('关注成功');
       }
-      
       // 更新用户信息
       const updatedUser = await getUser(userId);
       setProfileUser(updatedUser.data);
-      
+      // 关注/取关后强制刷新关注和粉丝列表,保证页面和数据库同步
+      if (activeTab === 2) {
+        const followingRes = await getUserFollowing(userId);
+        setFollowing(followingRes.data);
+      }
+      if (activeTab === 3) {
+        const followersRes = await getUserFollowers(userId);
+        setFollowers(followersRes.data.data);
+      }
     } catch (error) {
       console.error('关注操作失败:', error);
       showSnackbar('操作失败,请重试', 'error');