blob: 3aaec44eb4106bf0ba467ccbac0a8183445beb36 [file] [log] [blame]
22301009648cb7e2025-06-04 08:54:23 +08001import React, { useEffect, useState } from 'react';
2import axios from 'axios';
3import UserNav from './UserNav';
4import Header from '../../components/Header';
5import './UserFriends.css';
6import { useUser } from '../../context/UserContext';
7
8const UserFriends = () => {
9 const { user, loading } = useUser();
10 const [friends, setFriends] = useState([]);
11 const [error, setError] = useState(null);
12
13 // 私信相关状态
14 const [chatOpen, setChatOpen] = useState(false);
15 const [chatFriend, setChatFriend] = useState(null);
16 const [messageContent, setMessageContent] = useState('');
17 const [sendingStatus, setSendingStatus] = useState(null);
18
19 // 新增:聊天记录
20 const [chatMessages, setChatMessages] = useState([]);
21 const [loadingMessages, setLoadingMessages] = useState(false);
22 const [messagesError, setMessagesError] = useState(null);
23
24 useEffect(() => {
25 if (loading) return;
26
27 const fetchFriends = async () => {
28 if (!user || !user.userId) {
29 setError('未登录或用户信息缺失');
30 return;
31 }
32
33 try {
34 const res = await axios.get(`/echo/user/${user.userId}/friends`);
35 setFriends(res.data || []);
36 setError(null);
37 } catch (err) {
38 setError('加载好友失败,请稍后再试');
39 }
40 };
41
42 fetchFriends();
43 }, [user, loading]);
44
45 // 打开聊天框时加载聊天记录
46 const openChat = async (friend) => {
47 setChatFriend(friend);
48 setMessageContent('');
49 setSendingStatus(null);
50 setChatMessages([]);
51 setMessagesError(null);
52 setChatOpen(true);
53
54 if (!user || !user.userId) return;
55
56 setLoadingMessages(true);
57 try {
58 const res = await axios.get(`/echo/message/${user.userId}/getUserMessages`);
59 if (res.data.status === 'success') {
60 // 过滤出和这个好友的聊天消息(发或收都算)
61 const allMessages = res.data.messages || [];
62 const related = allMessages.filter(m =>
63 (m.sender_id === user.userId && m.receiver_id === friend.id) ||
64 (m.sender_id === friend.id && m.receiver_id === user.userId)
65 );
66 // 按时间排序(升序)
67 related.sort((a, b) => new Date(a.timestamp) - new Date(b.timestamp));
68 setChatMessages(related);
69 } else {
70 setMessagesError('无法加载聊天记录');
71 }
72 } catch (err) {
73 setMessagesError('加载聊天记录失败,请稍后再试');
74 } finally {
75 setLoadingMessages(false);
76 }
77 };
78
79 const closeChat = () => {
80 setChatOpen(false);
81 setChatFriend(null);
82 setMessageContent('');
83 setSendingStatus(null);
84 setChatMessages([]);
85 setMessagesError(null);
86 };
87
88 const sendMessage = async () => {
89 if (!messageContent.trim()) {
90 setSendingStatus('消息不能为空');
91 return;
92 }
93 setSendingStatus('发送中...');
94 try {
95 const res = await axios.post('/echo/message/sendMessages', {
96 sender_id: user.userId,
97 receiver_id: chatFriend.id,
98 content: messageContent.trim(),
99 });
100 if (res.data.status === 'success') {
101 setSendingStatus('发送成功');
102 setMessageContent('');
103 // 发送成功后,将这条消息追加到聊天记录
104 const newMsg = {
105 message_id: res.data.message_id,
106 sender_id: user.userId,
107 sender_username: user.username || '我',
108 receiver_id: chatFriend.id,
109 receiver_username: chatFriend.nickname,
110 content: messageContent.trim(),
111 timestamp: new Date().toISOString(),
112 };
113 setChatMessages(prev => [...prev, newMsg]);
114 } else {
115 setSendingStatus(res.data.message || '发送失败');
116 }
117 } catch (err) {
118 setSendingStatus('发送失败,请稍后再试');
119 }
120 };
121
122 if (loading) return <p>正在加载...</p>;
123 if (error) return <p className="error">{error}</p>;
124
125 return (
126 <div className="user-friends-container">
127 <Header />
128 <div className="user-center">
129 <div className="user-nav-container">
130 <UserNav />
131 </div>
132 <div className="common-card">
133 <h2>我的好友</h2>
134 <div className="friends-list">
135 {friends.length === 0 && <p>暂无好友</p>}
136 {friends.map((friend) => (
137 <div key={friend.id} className="friend-card">
138 <img src={friend.avatar} alt={friend.nickname} className="friend-avatar" />
139 <div className="friend-info">
140 <p><strong>{friend.nickname}</strong></p>
141 <p>{friend.email}</p>
142 <button
143 className="send-message-btn"
144 onClick={() => openChat(friend)}
145 >
146 发送私信
147 </button>
148 </div>
149 </div>
150 ))}
151 </div>
152 </div>
153 </div>
154
155 {/* 私信弹窗 */}
156 {chatOpen && (
157 <div className="chat-modal">
158 <div className="chat-modal-content">
159 <h3> {chatFriend.nickname} 发送私信</h3>
160 <div className="chat-messages" style={{height: '250px', overflowY: 'auto', border: '1px solid #ccc', padding: '8px', marginBottom: '8px'}}>
161 {loadingMessages && <p>加载聊天记录中...</p>}
162 {messagesError && <p className="error">{messagesError}</p>}
163 {!loadingMessages && chatMessages.length === 0 && <p>暂无聊天记录</p>}
164 {chatMessages.map(msg => (
165 <div
166 key={msg.message_id}
167 style={{
168 textAlign: msg.sender_id === user.userId ? 'right' : 'left',
169 marginBottom: '8px'
170 }}
171 >
172 <div style={{
173 display: 'inline-block',
174 backgroundColor: msg.sender_id === user.userId ? '#409eff' : '#f0f0f0',
175 color: msg.sender_id === user.userId ? 'white' : 'black',
176 borderRadius: '10px',
177 padding: '6px 12px',
178 maxWidth: '70%',
179 wordBreak: 'break-word'
180 }}>
181 <p style={{margin: 0}}>{msg.content}</p>
182 <small style={{fontSize: '10px', opacity: 0.7}}>
183 {new Date(msg.timestamp).toLocaleString()}
184 </small>
185 </div>
186 </div>
187 ))}
188 </div>
189 <textarea
190 rows="3"
191 value={messageContent}
192 onChange={(e) => setMessageContent(e.target.value)}
193 placeholder="输入消息内容"
194 style={{width: '100%', marginBottom: '8px'}}
195 />
196 <div className="chat-actions">
197 <button onClick={sendMessage}>发送</button>
198 <button onClick={closeChat}>关闭</button>
199 </div>
200 {sendingStatus && <p className="status-msg">{sendingStatus}</p>}
201 </div>
202 <div className="chat-modal-backdrop" onClick={closeChat}></div>
203 </div>
204 )}
205 </div>
206 );
207};
208
209export default UserFriends;