blob: 704636ea861bc638eab68b3830f9bf77a26f2321 [file] [log] [blame]
ym923ed3de702025-06-09 20:10:16 +08001import React, { useState, useEffect } from 'react';
2import {
3 getCommentsByPostId,
4 createComment,
5 deleteComment,
6 likeComment,
7 unlikeComment,
8} from '../api/comment';
9
10import {
11 Card,
12 Button,
13 Input,
14 List,
15 Avatar,
16 Popconfirm,
17 message,
18 Space,
19 Tooltip
20} from 'antd';
21
22import {
23 LikeOutlined,
24 LikeFilled,
25 DeleteOutlined
26} from '@ant-design/icons';
27
28import axios from 'axios';
29import './Comment.css';
30
31const { TextArea } = Input;
32
33const Comment = ({ postId, currentUser }) => {
34 const [comments, setComments] = useState([]);
35 const [newContent, setNewContent] = useState('');
36 const [loading, setLoading] = useState(false);
37 const [userInfoMap, setUserInfoMap] = useState({});
38 const [isCommenting, setIsCommenting] = useState(false);
39
40 useEffect(() => {
41 loadComments();
42 }, [postId, currentUser]);
43
44 const loadComments = async () => {
45 try {
46 if (!postId) return;
47
48 const commentList = await getCommentsByPostId(postId);
49 setComments(commentList);
50
51 // 修复1: 统一使用 userid 而不是 id
52 const userIds = [
53 ...new Set(commentList.map(c => c.userid))
54 ];
55
56 // 如果当前用户存在,添加其 userid
57 if (currentUser && currentUser.userid) {
58 userIds.push(currentUser.userid);
59 }
60
61 // 批量获取用户信息
62 const userInfoPromises = userIds.map(async (id) => {
63 try {
64 const res = await axios.get(`http://localhost:8080/user/getDecoration?userid=${id}`);
65 if (res.data?.success) {
66 return { id, data: res.data.data };
67 }
68 return { id, data: { username: `用户${id}`, image: '' } };
69 } catch (error) {
70 return { id, data: { username: `用户${id}`, image: '' } };
71 }
72 });
73
74 const userInfoResults = await Promise.all(userInfoPromises);
75
76 // 构建用户信息映射
77 const newUserInfoMap = {};
78 userInfoResults.forEach(({ id, data }) => {
79 newUserInfoMap[id] = data;
80 });
81
82 setUserInfoMap(newUserInfoMap);
83
84 } catch (error) {
85 console.error('加载评论失败:', error);
86 message.error('加载评论失败');
87 }
88 };
89
90 const handleCreate = async () => {
91 // 检查用户是否登录
92 if (!currentUser) {
93 message.error('请先登录后再评论');
94 return;
95 }
96
97 // 修复2: 确保当前用户有 userid 属性
98 if (!currentUser.userid) {
99 message.error('用户信息异常,请重新登录');
100 return;
101 }
102
103 if (!newContent.trim()) {
104 message.warning('评论内容不能为空');
105 return;
106 }
107
108 setIsCommenting(true);
109 setLoading(true);
110
111 // 修复3: 使用 currentUser.userid 而非 currentUser.id
112 const commentData = {
113 postid: postId,
114 userid: Number(currentUser.userid),
115 postCommentcontent: newContent,
116 commenttime: new Date().toISOString()
117 };
118
119 try {
120 await createComment(commentData);
121 setNewContent('');
122 await loadComments(); // 重新加载评论,确保新评论显示
123 message.success('评论发布成功');
124 } catch (error) {
125 console.error('发布评论失败:', error);
126 message.error('发布评论失败');
127 } finally {
128 setLoading(false);
129 setIsCommenting(false);
130 }
131 };
132
133 const handleDelete = async (commentid) => {
134 try {
135 await deleteComment(commentid);
136 message.success('删除成功');
137 loadComments();
138 } catch (error) {
139 console.error('删除评论失败:', error);
140 message.error('删除失败');
141 }
142 };
143
144 const handleLike = async (commentid) => {
145 try {
146 await likeComment(commentid);
147 loadComments();
148 } catch (error) {
149 console.error('点赞失败:', error);
150 message.error('操作失败');
151 }
152 };
153
154 const handleUnlike = async (commentid) => {
155 try {
156 await unlikeComment(commentid);
157 loadComments();
158 } catch (error) {
159 console.error('取消点赞失败:', error);
160 message.error('操作失败');
161 }
162 };
163
164 // 获取用户信息(包括当前登录用户)
165 const getUserInfo = (userId) => {
166 // 修复4: 使用 currentUser.userid 而非 currentUser.id
167 if (currentUser && currentUser.userid && userId === currentUser.userid) {
168 return {
169 username: currentUser.username || `用户${userId}`,
170 image: currentUser.image || '',
171 decoration: currentUser.decoration || ''
172 };
173 }
174
175 // 对于其他用户,从userInfoMap中获取
176 return userInfoMap[userId] || {
177 username: `用户${userId}`,
178 image: '',
179 decoration: ''
180 };
181 };
182
183 return (
184 <Card title="评论区" bordered={false} className="comment-card">
185 {/* 评论输入框 - 根据用户登录状态调整 */}
186 {currentUser ? (
187 <>
188 <TextArea
189 rows={3}
190 placeholder={`${currentUser.username},留下你的评论...`}
191 value={newContent}
192 onChange={(e) => setNewContent(e.target.value)}
193 className="comment-textarea"
194 disabled={loading}
195 />
196 <div className="text-right mt-2">
197 <Button
198 type="primary"
199 onClick={handleCreate}
200 loading={loading || isCommenting}
201 disabled={isCommenting}
202 >
203 {isCommenting ? '发布中...' : '发布评论'}
204 </Button>
205 </div>
206 </>
207 ) : (
208 <div className="login-prompt">
209 请<a href="/login" className="login-link">登录</a>后发表评论
210 </div>
211 )}
212
213 {/* 评论列表 */}
214 <List
215 itemLayout="vertical"
216 dataSource={comments}
217 locale={{ emptyText: '暂无评论' }}
218 className="mt-6"
219 renderItem={(item) => {
220 const user = getUserInfo(item.userid);
221 // 修复5: 使用 userid 而非 id 比较当前用户
222 const isCurrentUser = currentUser && currentUser.userid === item.userid;
223
224 return (
225 <List.Item
226 key={item.commentid}
227 className={isCurrentUser ? "current-user-comment" : ""}
228 actions={[
229 <Tooltip title="点赞" key="like">
230 <Space>
231 <Button
232 icon={<LikeOutlined />}
233 size="small"
234 onClick={() => handleLike(item.commentid)}
235 />
236 {item.likes}
237 </Space>
238 </Tooltip>,
239 <Tooltip title="取消点赞" key="unlike">
240 <Button
241 icon={<LikeFilled style={{ color: '#fadb14' }} />}
242 size="small"
243 onClick={() => handleUnlike(item.commentid)}
244 />
245 </Tooltip>,
246 isCurrentUser && (
247 <Popconfirm
248 title="确定要删除这条评论吗?"
249 onConfirm={() => handleDelete(item.commentid)}
250 okText="删除"
251 cancelText="取消"
252 key="delete"
253 >
254 <Button icon={<DeleteOutlined />} size="small" danger />
255 </Popconfirm>
256 )
257 ]}
258 extra={
259 <div className="comment-time">
260 {new Date(item.commenttime).toLocaleString()}
261 </div>
262 }
263 >
264 <List.Item.Meta
265 avatar={
266 <Avatar
267 src={user.image || undefined}
268 alt={user.username}
269 className="comment-avatar"
270 >
271 {!user.image && user.username ? user.username.charAt(0).toUpperCase() : ''}
272 </Avatar>
273 }
274 title={
275 <span className="comment-username">
276 {user.username || `用户${item.userid}`}
277 {isCurrentUser && <span className="current-user-tag">(我)</span>}
278 </span>
279 }
280 description={<div className="comment-content">{item.postCommentcontent}</div>}
281 />
282 </List.Item>
283 );
284 }}
285 />
286 </Card>
287 );
288};
289
290export default Comment;