修改促销、优化页面布局
Change-Id: Iae813b5b6557efa7059fe6d94bc32e96c984e4ea
diff --git a/src/pages/FriendMoments/FriendMoments.jsx b/src/pages/FriendMoments/FriendMoments.jsx
index ab1aef2..0d92303 100644
--- a/src/pages/FriendMoments/FriendMoments.jsx
+++ b/src/pages/FriendMoments/FriendMoments.jsx
@@ -1,1341 +1,3 @@
-// // FriendMoments.js
-// import React, { useContext, useState, useEffect } from 'react';
-// import axios from 'axios';
-// import './FriendMoments.css';
-// import Header from '../../components/Header';
-// import { Edit, GoodTwo, Comment } from '@icon-park/react';
-// import { UserContext } from '../../context/UserContext'; // 引入用户上下文
-
-// // 修改后的封面图 URL 拼接函数
-// const formatImageUrl = (url) => {
-// if (!url) return '';
-// const filename = url.split('/').pop(); // 提取文件名部分
-// return `http://localhost:5011/uploads/dynamic/${filename}`;
-// };
-
-// const FriendMoments = () => {
-// const [feeds, setFeeds] = useState([]);
-// const [filteredFeeds, setFilteredFeeds] = useState([]);
-// const [query, setQuery] = useState('');
-// const [loading, setLoading] = useState(true);
-// const [error, setError] = useState(null);
-
-// // 从上下文中获取用户信息
-// const { user } = useContext(UserContext);
-// const userId = user?.userId || null; // 从用户上下文中获取userId
-// const username = user?.username || '未知用户'; // 获取用户名
-
-// // Modal state & form fields
-// const [showModal, setShowModal] = useState(false);
-// const [title, setTitle] = useState('');
-// const [content, setContent] = useState('');
-// const [selectedImages, setSelectedImages] = useState([]);
-// const [previewUrls, setPreviewUrls] = useState([]);
-
-// // 检查用户是否已登录
-// const isLoggedIn = !!userId;
-
-// // 拉取好友动态列表
-// const fetchFeeds = async () => {
-// if (!isLoggedIn) {
-// setLoading(false);
-// setError('请先登录');
-// return;
-// }
-
-// setLoading(true);
-// setError(null);
-// try {
-// // 注意这里修改了API路径,使用getAllDynamics接口
-// const res = await axios.get(`/echo/dynamic/${userId}/getAllDynamics`);
-
-// // 检查API返回的数据结构
-// console.log('API响应数据:', res.data);
-
-// // 从响应中提取dynamic数组
-// const dynamicList = res.data.dynamic || [];
-
-// // 将API返回的数据结构转换为前端期望的格式
-// const formattedFeeds = dynamicList.map(item => ({
-// postNo: item.dynamic_id, // 使用API返回的dynamic_id作为帖子ID
-// title: item.title,
-// postContent: item.content,
-// imageUrl: item.images, // 使用API返回的images字段
-// postTime: item.time, // 使用API返回的time字段
-// postLikeNum: item.likes?.length || 0, // 点赞数
-// liked: item.likes?.some(like => like.user_id === userId), // 当前用户是否已点赞
-// user_id: item.user_id, // 发布者ID
-// username: item.username, // 发布者昵称
-// avatar_url: item.avatar_url, // 发布者头像
-// comments: item.comments || [] // 评论列表
-// }));
-
-// setFeeds(formattedFeeds);
-// setFilteredFeeds(formattedFeeds);
-// } catch (err) {
-// console.error('获取动态列表失败:', err);
-// setError('获取动态列表失败,请稍后重试');
-// } finally {
-// setLoading(false);
-// }
-// };
-
-// useEffect(() => {
-// fetchFeeds();
-// }, [userId]);
-
-// // 搜索处理
-// const handleSearch = () => {
-// const q = query.trim().toLowerCase();
-// if (!q) {
-// setFilteredFeeds(feeds);
-// return;
-// }
-// setFilteredFeeds(
-// feeds.filter(f =>
-// (f.title || '').toLowerCase().includes(q) ||
-// (f.postContent || '').toLowerCase().includes(q)
-// )
-// );
-// };
-
-// const handleReset = () => {
-// setQuery('');
-// setFilteredFeeds(feeds);
-// };
-
-// // 对话框内:处理图片选择
-// const handleImageChange = (e) => {
-// const files = Array.from(e.target.files);
-// if (!files.length) return;
-
-// const previewUrls = files.map(file => URL.createObjectURL(file));
-
-// setSelectedImages(files);
-// setPreviewUrls(previewUrls);
-// };
-
-// // 对话框内:提交新动态
-// const handleSubmit = async () => {
-// if (!isLoggedIn) {
-// alert('请先登录');
-// return;
-// }
-
-// if (!content.trim()) {
-// alert('内容不能为空');
-// return;
-// }
-
-// try {
-// // 使用formData格式提交
-// const formData = new FormData();
-// formData.append('title', title.trim() || '');
-// formData.append('content', content.trim());
-
-// // 添加图片文件
-// selectedImages.forEach((file, index) => {
-// formData.append('image_url', file);
-// });
-
-// // 调用创建动态API
-// await axios.post(`/echo/dynamic/${userId}/createDynamic`, formData, {
-// headers: {
-// 'Content-Type': 'multipart/form-data'
-// }
-// });
-
-// // 重置表单
-// setTitle('');
-// setContent('');
-// setSelectedImages([]);
-// setPreviewUrls([]);
-// setShowModal(false);
-// fetchFeeds();
-// alert('发布成功');
-// } catch (err) {
-// console.error('发布失败', err);
-// alert('发布失败,请稍后重试');
-// }
-// };
-
-// // 删除动态 - 注意:API文档中未提供删除接口,这里保留原代码
-// const handleDelete = async (dynamicId) => {
-
-// if (!isLoggedIn) {
-// alert('请先登录');
-// return;
-// }
-
-// if (!window.confirm('确定要删除这条动态吗?')) return;
-// try {
-// // 注意:API文档中未提供删除接口,这里使用原代码中的路径
-// await axios.delete(`/echo/dynamic/me/deleteDynamic/${dynamicId}`);
-// fetchFeeds();
-// alert('删除成功');
-// } catch (err) {
-// console.error('删除失败', err);
-// alert('删除失败,请稍后重试');
-// }
-// };
-
-// // 点赞动态
-// const handleLike = async (dynamicId, islike) => {
-// if (islike) {
-// handleUnlike(dynamicId);
-// return
-// }
-// if (!isLoggedIn) {
-// alert('请先登录');
-// return;
-// }
-
-// // 验证dynamicId是否有效
-// if (!dynamicId) {
-// console.error('无效的dynamicId:', dynamicId);
-// alert('点赞失败:动态ID无效');
-// return;
-// }
-
-// console.log('当前用户ID:', userId);
-// console.log('即将点赞的动态ID:', dynamicId);
-
-// try {
-// // 确保参数是整数类型
-// const requestData = {
-// userId: parseInt(userId),
-// dynamicId: parseInt(dynamicId)
-// };
-
-// // 验证参数是否为有效数字
-// if (isNaN(requestData.userId) || isNaN(requestData.dynamicId)) {
-// console.error('无效的参数:', requestData);
-// alert('点赞失败:参数格式错误');
-// return;
-// }
-
-// console.log('点赞请求数据:', requestData);
-
-// const res = await axios.post(`/echo/dynamic/like`, requestData, {
-// headers: {
-// 'Content-Type': 'application/json' // 明确指定JSON格式
-// }
-// });
-
-// console.log('点赞API响应:', res.data);
-
-// if (res.status === 200) {
-// // 更新本地状态
-// setFeeds(prevFeeds => {
-// return prevFeeds.map(feed => {
-// if (feed.postNo === dynamicId) {
-// return {
-// ...feed,
-// postLikeNum: (feed.postLikeNum || 0) + 1,
-// liked: true
-// };
-// }
-// return feed;
-// });
-// });
-// } else {
-// alert(res.data.message || '点赞失败');
-// }
-// } catch (err) {
-// console.error('点赞失败', err);
-
-// // 检查错误响应,获取更详细的错误信息
-// if (err.response) {
-// console.error('错误响应数据:', err.response.data);
-// console.error('错误响应状态:', err.response.status);
-// console.error('错误响应头:', err.response.headers);
-// }
-
-// alert('点赞失败,请稍后重试');
-// }
-// };
-
-// // 取消点赞
-// const handleUnlike = async (dynamicId) => {
-// if (!isLoggedIn) {
-// alert('请先登录');
-// return;
-// }
-
-// // 验证dynamicId是否有效
-// if (!dynamicId) {
-// console.error('无效的dynamicId:', dynamicId);
-// alert('取消点赞失败:动态ID无效');
-// return;
-// }
-
-// // 检查是否已经取消点赞,防止重复请求
-// const currentFeed = feeds.find(feed => feed.postNo === dynamicId);
-// if (currentFeed && !currentFeed.liked) {
-// console.warn('尝试重复取消点赞,已忽略');
-// return;
-// }
-
-// try {
-// // 确保参数是整数类型
-// const requestData = {
-// userId: parseInt(userId),
-// dynamicId: parseInt(dynamicId)
-// };
-
-// // 验证参数是否为有效数字
-// if (isNaN(requestData.userId) || isNaN(requestData.dynamicId)) {
-// console.error('无效的参数:', requestData);
-// alert('取消点赞失败:参数格式错误');
-// return;
-// }
-
-// console.log('取消点赞请求数据:', requestData);
-
-// const res = await axios.delete(`/echo/dynamic/unlike`, {
-// headers: {
-// 'Content-Type': 'application/json' // 明确指定JSON格式
-// },
-// data: requestData // 将参数放在data属性中
-// });
-
-// console.log('取消点赞API响应:', res.data);
-
-// if (res.status === 200) {
-// // 更新本地状态
-// setFeeds(prevFeeds => {
-// return prevFeeds.map(feed => {
-// if (feed.postNo === dynamicId) {
-// return {
-// ...feed,
-// postLikeNum: Math.max(0, (feed.postLikeNum || 0) - 1),
-// liked: false
-// };
-// }
-// return feed;
-// });
-// });
-// } else {
-// alert(res.data.message || '取消点赞失败');
-// }
-// } catch (err) {
-// console.error('取消点赞失败', err);
-
-// // 检查错误响应,获取更详细的错误信息
-// if (err.response) {
-// console.error('错误响应数据:', err.response.data);
-// console.error('错误响应状态:', err.response.status);
-// console.error('错误响应头:', err.response.headers);
-// }
-
-// alert('取消点赞失败,请稍后重试');
-// }
-// };
-
-// // 评论好友动态
-// const handleComment = async (dynamicId, parentCommentId = null, replyToUsername = '') => {
-// if (!isLoggedIn) {
-// alert('请先登录');
-// return;
-// }
-
-// const commentInputId = `comment-input-${dynamicId}-${parentCommentId}`;
-// const commentInput = document.getElementById(commentInputId);
-
-// if (!commentInput || !commentInput.value.trim()) {
-// alert('评论内容不能为空');
-// return;
-// }
-
-// const commentContent = commentInput.value.trim();
-
-// try {
-// // 准备请求数据
-// const requestData = {
-// content: commentContent
-// };
-
-// // 如果是回复,添加parent_comment_id
-// if (parentCommentId) {
-// requestData.parent_comment_id = parentCommentId;
-// }
-
-// const res = await axios.post(`/echo/dynamic/${userId}/feeds/${dynamicId}/comments`, requestData);
-
-// if (res.status === 200 || res.status === 201) {
-// // 创建新评论对象
-// const newComment = {
-// // 使用API返回的评论ID,如果没有则生成临时ID
-// id: res.data.comment_id || `temp-${Date.now()}`,
-// user_id: userId,
-// username: username,
-// content: commentContent,
-// time: new Date().toISOString(),
-// // 如果是回复,添加reply_to_username
-// ...(replyToUsername && { reply_to_username: replyToUsername })
-// };
-
-// // 更新本地状态
-// setFeeds(prevFeeds => {
-// return prevFeeds.map(feed => {
-// if (feed.postNo === dynamicId) {
-// if (parentCommentId) {
-// // 这是一个回复,找到父评论并添加到其replies数组
-// return {
-// ...feed,
-// comments: feed.comments.map(comment => {
-// if (comment.id === parentCommentId || comment.postNo === parentCommentId) {
-// // 确保replies数组存在
-// if (!comment.replies) {
-// return {
-// ...comment,
-// replies: [newComment]
-// };
-// }
-// return {
-// ...comment,
-// replies: [...comment.replies, newComment]
-// };
-// }
-// return comment;
-// })
-// };
-// } else {
-// // 这是一个新评论,添加到评论列表
-// return {
-// ...feed,
-// comments: [...feed.comments, newComment]
-// };
-// }
-// }
-// return feed;
-// });
-// });
-
-// // 清空输入框并隐藏回复框
-// if (commentInput) {
-// commentInput.value = '';
-// }
-// toggleReplyBox(dynamicId, parentCommentId);
-// } else {
-// alert(res.data.error || '评论失败');
-// }
-// } catch (err) {
-// console.error('评论失败', err);
-// alert('评论失败,请稍后重试');
-// }
-// };
-
-// // 切换回复框显示状态
-// const toggleReplyBox = (dynamicId, parentCommentId = null) => {
-// const replyBoxId = `reply-box-${dynamicId}-${parentCommentId}`;
-// const replyBox = document.getElementById(replyBoxId);
-
-// if (replyBox) {
-// replyBox.style.display = replyBox.style.display === 'none' ? 'block' : 'none';
-
-// // 如果显示,聚焦到输入框
-// if (replyBox.style.display === 'block') {
-// const commentInput = document.getElementById(`comment-input-${dynamicId}-${parentCommentId}`);
-// if (commentInput) commentInput.focus();
-// }
-// }
-// };
-
-// return (
-// <div className="friend-moments-container">
-// <Header />
-// <div className="fm-header">
-// <button className="create-btn" onClick={() => setShowModal(true)}>
-// <Edit theme="outline" size="18" style={{ marginRight: '6px' }} />
-// 创建动态
-// </button>
-// </div>
-
-// <div className="feed-list">
-// {loading ? (
-// <div className="loading-message">加载中...</div>
-// ) : error ? (
-// <div className="error-message">{error}</div>
-// ) : !isLoggedIn ? (
-// <div className="login-prompt">
-// <p>请先登录查看好友动态</p>
-// </div>
-// ) : filteredFeeds.length === 0 ? (
-// <div className="empty-message">暂无动态</div>
-// ) : (
-// filteredFeeds.map(feed => (
-// <div className="feed-item" key={feed.postNo || `feed-${Math.random()}`}>
-// {/* 显示发布者信息 */}
-// <div className="feed-author">
-// <img
-// className="user-avatar"
-// src={feed.avatar_url || 'https://example.com/default-avatar.jpg'}
-// alt={feed.username || '用户头像'}
-// />
-// <div>
-// <h4>{feed.username || '未知用户'}</h4>
-// <span className="feed-date">{new Date(feed.postTime || Date.now()).toLocaleString()}</span>
-// </div>
-// </div>
-
-// {feed.title && <h4 className="feed-title">{feed.title}</h4>}
-// <p className="feed-content">{feed.postContent || '无内容'}</p>
-
-// {feed.imageUrl && (
-// <div className="feed-images">
-// {typeof feed.imageUrl === 'string' ? (
-// <img src={formatImageUrl(feed.imageUrl)} alt="动态图片" />
-// ) : (
-// feed.imageUrl.map((url, i) => (
-// <img key={i} src={formatImageUrl(url)} alt={`动态图${i}`} />
-// ))
-// )}
-// </div>
-// )}
-
-// <div className="feed-footer">
-// <div className="like-container">
-// <button className="icon-btn" onClick={() => handleLike(feed.postNo, feed.liked, feed.user_id)}>
-// <GoodTwo theme="outline" size="24" fill={feed.liked ? '#f00' : '#fff'} />
-// <span>{feed.postLikeNum || 0}</span>
-// </button>
-
-// <button
-// className="icon-btn"
-// onClick={() => toggleReplyBox(feed.postNo)}
-// >
-// <Comment theme="outline" size="24" fill="#333" />
-// <span>评论</span>
-// </button>
-// </div>
-
-// {feed.user_id === userId && (
-// <button className="delete-btn" onClick={() => handleDelete(feed.postNo)}>
-// 删除
-// </button>
-// )}
-// </div>
-
-// {/* 动态的评论输入框 */}
-// <div id={`reply-box-${feed.postNo}-null`} className="comment-box" style={{display: 'none'}}>
-// <textarea
-// id={`comment-input-${feed.postNo}-null`}
-// className="comment-input"
-// placeholder="请输入评论内容..."
-// />
-// <button
-// className="submit-comment-btn"
-// onClick={() => handleComment(feed.postNo)}
-// >
-// 发布评论
-// </button>
-// </div>
-
-// {/* 评论列表 */}
-// {Array.isArray(feed.comments) && feed.comments.length > 0 && (
-// <div className="comments-container">
-// <h5>评论 ({feed.comments.length})</h5>
-// <div className="comments-list">
-// {feed.comments.map((comment, index) => (
-// <div className="comment-item" key={comment.id || index}>
-// <div className="comment-header">
-// <span className="comment-user">{comment.username || '用户'}</span>
-// <span className="comment-time">
-// {new Date(comment.time || Date.now()).toLocaleString()}
-// </span>
-// </div>
-// <p className="comment-content">
-// {/* 显示回复格式 */}
-// {comment.reply_to_username ?
-// <span className="reply-prefix">{comment.username} 回复 {comment.reply_to_username}:</span> :
-// <span>{comment.username}:</span>
-// }
-// {comment.content}
-// </p>
-// <button
-// className="reply-btn"
-// onClick={() => toggleReplyBox(feed.postNo, comment.id || index, comment.username)}
-// >
-// 回复
-// </button>
-
-// {/* 该评论的回复框 */}
-// <div id={`reply-box-${feed.postNo}-${comment.id || index}`} className="comment-box nested-reply-box" style={{display: 'none'}}>
-// <textarea
-// id={`comment-input-${feed.postNo}-${comment.id || index}`}
-// className="comment-input"
-// placeholder={`回复 ${comment.username}...`}
-// />
-// <button
-// className="submit-comment-btn"
-// onClick={() => handleComment(feed.postNo, comment.id || index, comment.username)}
-// >
-// 发布回复
-// </button>
-// </div>
-
-// {/* 嵌套回复 */}
-// {Array.isArray(comment.replies) && comment.replies.length > 0 && (
-// <div className="nested-replies">
-// {comment.replies.map((reply, replyIndex) => (
-// <div className="reply-item" key={reply.id || `${comment.id || index}-${replyIndex}`}>
-// <p className="reply-content">
-// {reply.reply_to_username ?
-// <span className="reply-prefix">{reply.username} 回复 {reply.reply_to_username}:</span> :
-// <span>{reply.username}:</span>
-// }
-// {reply.content}
-// </p>
-// <button
-// className="reply-btn"
-// onClick={() => toggleReplyBox(feed.postNo, reply.id || `${comment.id || index}-${replyIndex}`, reply.username)}
-// >
-// 回复
-// </button>
-
-// {/* 该回复的回复框 */}
-// <div id={`reply-box-${feed.postNo}-${reply.id || `${comment.id || index}-${replyIndex}`}`} className="comment-box nested-reply-box" style={{display: 'none'}}>
-// <textarea
-// id={`comment-input-${feed.postNo}-${reply.id || `${comment.id || index}-${replyIndex}`}`}
-// className="comment-input"
-// placeholder={`回复 ${reply.username}...`}
-// />
-// <button
-// className="submit-comment-btn"
-// onClick={() => handleComment(feed.postNo, reply.id || `${comment.id || index}-${replyIndex}`, reply.username)}
-// >
-// 发布回复
-// </button>
-// </div>
-// </div>
-// ))}
-// </div>
-// )}
-// </div>
-// ))}
-// </div>
-// </div>
-// )}
-// </div>
-// ))
-// )}
-// </div>
-
-// {/* Modal 对话框 */}
-// {showModal && (
-// <div className="modal-overlay" onClick={() => setShowModal(false)}>
-// <div className="modal-dialog" onClick={e => e.stopPropagation()}>
-// <h3>发布新动态</h3>
-// <input
-// type="text"
-// placeholder="标题"
-// value={title}
-// onChange={e => setTitle(e.target.value)}
-// />
-// <textarea
-// placeholder="写下你的内容..."
-// value={content}
-// onChange={e => setContent(e.target.value)}
-// />
-// <label className="file-label">
-// 选择图片
-// <input
-// type="file"
-// accept="image/*"
-// multiple
-// onChange={handleImageChange}
-// style={{ display: 'none' }}
-// />
-// </label>
-// <div className="cf-preview">
-// {previewUrls.map((url, i) => (
-// <img key={i} src={url} alt={`预览${i}`} />
-// ))}
-// </div>
-// <div className="modal-actions">
-// <button className="btn cancel" onClick={() => setShowModal(false)}>
-// 取消
-// </button>
-// <button className="btn submit" onClick={handleSubmit}>
-// 发布
-// </button>
-// </div>
-// </div>
-// </div>
-// )}
-// </div>
-// );
-// };
-
-// export default FriendMoments;
-// // FriendMoments.js
-// import React, { useContext, useState, useEffect } from 'react';
-// import axios from 'axios';
-// import './FriendMoments.css';
-// import Header from '../../components/Header';
-// import { Edit, GoodTwo, Comment } from '@icon-park/react';
-// import { UserContext } from '../../context/UserContext'; // 引入用户上下文
-
-// // 修改后的封面图 URL 拼接函数
-// const formatImageUrl = (url) => {
-// if (!url) return '';
-// const filename = url.split('/').pop(); // 提取文件名部分
-// return `http://localhost:5011/uploads/dynamic/${filename}`;
-// };
-
-// const FriendMoments = () => {
-// const [feeds, setFeeds] = useState([]);
-// const [filteredFeeds, setFilteredFeeds] = useState([]);
-// const [query, setQuery] = useState('');
-// const [loading, setLoading] = useState(true);
-// const [error, setError] = useState(null);
-
-// // 从上下文中获取用户信息
-// const { user } = useContext(UserContext);
-// const userId = user?.userId || null; // 从用户上下文中获取userId
-// const username = user?.username || '未知用户'; // 获取用户名
-
-// // Modal state & form fields
-// const [showModal, setShowModal] = useState(false);
-// const [title, setTitle] = useState('');
-// const [content, setContent] = useState('');
-// const [selectedImages, setSelectedImages] = useState([]);
-// const [previewUrls, setPreviewUrls] = useState([]);
-
-// // 检查用户是否已登录
-// const isLoggedIn = !!userId;
-
-// // 拉取好友动态列表
-// const fetchFeeds = async () => {
-// if (!isLoggedIn) {
-// setLoading(false);
-// setError('请先登录');
-// return;
-// }
-
-// setLoading(true);
-// setError(null);
-// try {
-// // 注意这里修改了API路径,使用getAllDynamics接口
-// const res = await axios.get(`/echo/dynamic/${userId}/getAllDynamics`);
-
-// // 检查API返回的数据结构
-// console.log('API响应数据:', res.data);
-
-// // 从响应中提取dynamic数组
-// const dynamicList = res.data.dynamic || [];
-
-// // 将API返回的数据结构转换为前端期望的格式
-// const formattedFeeds = dynamicList.map(item => ({
-// postNo: item.dynamic_id, // 使用API返回的dynamic_id作为帖子ID
-// title: item.title,
-// postContent: item.content,
-// imageUrl: item.images, // 使用API返回的images字段
-// postTime: item.time, // 使用API返回的time字段
-// postLikeNum: item.likes?.length || 0, // 点赞数
-// liked: item.likes?.some(like => like.user_id === userId), // 当前用户是否已点赞
-// user_id: item.user_id, // 发布者ID
-// username: item.username, // 发布者昵称
-// avatar_url: item.avatar_url, // 发布者头像
-// comments: item.comments || [] // 评论列表
-// }));
-
-// setFeeds(formattedFeeds);
-// setFilteredFeeds(formattedFeeds);
-// } catch (err) {
-// console.error('获取动态列表失败:', err);
-// setError('获取动态列表失败,请稍后重试');
-// } finally {
-// setLoading(false);
-// }
-// };
-
-// useEffect(() => {
-// fetchFeeds();
-// }, [userId]);
-
-// // 搜索处理
-// const handleSearch = () => {
-// const q = query.trim().toLowerCase();
-// if (!q) {
-// setFilteredFeeds(feeds);
-// return;
-// }
-// setFilteredFeeds(
-// feeds.filter(f =>
-// (f.title || '').toLowerCase().includes(q) ||
-// (f.postContent || '').toLowerCase().includes(q)
-// )
-// );
-// };
-
-// const handleReset = () => {
-// setQuery('');
-// setFilteredFeeds(feeds);
-// };
-
-// // 对话框内:处理图片选择
-// const handleImageChange = (e) => {
-// const files = Array.from(e.target.files);
-// if (!files.length) return;
-
-// const previewUrls = files.map(file => URL.createObjectURL(file));
-
-// setSelectedImages(files);
-// setPreviewUrls(previewUrls);
-// };
-
-// // 对话框内:提交新动态
-// const handleSubmit = async () => {
-// if (!isLoggedIn) {
-// alert('请先登录');
-// return;
-// }
-
-// if (!content.trim()) {
-// alert('内容不能为空');
-// return;
-// }
-
-// try {
-// // 使用formData格式提交
-// const formData = new FormData();
-// formData.append('title', title.trim() || '');
-// formData.append('content', content.trim());
-
-// // 添加图片文件
-// selectedImages.forEach((file, index) => {
-// formData.append('image_url', file);
-// });
-
-// // 调用创建动态API
-// await axios.post(`/echo/dynamic/${userId}/createDynamic`, formData, {
-// headers: {
-// 'Content-Type': 'multipart/form-data'
-// }
-// });
-
-// // 重置表单
-// setTitle('');
-// setContent('');
-// setSelectedImages([]);
-// setPreviewUrls([]);
-// setShowModal(false);
-// fetchFeeds();
-// alert('发布成功');
-// } catch (err) {
-// console.error('发布失败', err);
-// alert('发布失败,请稍后重试');
-// }
-// };
-
-// // 删除动态 - 注意:API文档中未提供删除接口,这里保留原代码
-// const handleDelete = async (dynamicId) => {
-
-// if (!isLoggedIn) {
-// alert('请先登录');
-// return;
-// }
-
-// if (!window.confirm('确定要删除这条动态吗?')) return;
-// try {
-// // 注意:API文档中未提供删除接口,这里使用原代码中的路径
-// await axios.delete(`/echo/dynamic/me/deleteDynamic/${dynamicId}`);
-// fetchFeeds();
-// alert('删除成功');
-// } catch (err) {
-// console.error('删除失败', err);
-// alert('删除失败,请稍后重试');
-// }
-// };
-
-// // 点赞动态
-// const handleLike = async (dynamicId, islike) => {
-// if (islike) {
-// handleUnlike(dynamicId);
-// return
-// }
-// if (!isLoggedIn) {
-// alert('请先登录');
-// return;
-// }
-
-// // 验证dynamicId是否有效
-// if (!dynamicId) {
-// console.error('无效的dynamicId:', dynamicId);
-// alert('点赞失败:动态ID无效');
-// return;
-// }
-
-// console.log('当前用户ID:', userId);
-// console.log('即将点赞的动态ID:', dynamicId);
-
-// try {
-// // 确保参数是整数类型
-// const requestData = {
-// userId: parseInt(userId),
-// dynamicId: parseInt(dynamicId)
-// };
-
-// // 验证参数是否为有效数字
-// if (isNaN(requestData.userId) || isNaN(requestData.dynamicId)) {
-// console.error('无效的参数:', requestData);
-// alert('点赞失败:参数格式错误');
-// return;
-// }
-
-// console.log('点赞请求数据:', requestData);
-
-// const res = await axios.post(`/echo/dynamic/like`, requestData, {
-// headers: {
-// 'Content-Type': 'application/json' // 明确指定JSON格式
-// }
-// });
-
-// console.log('点赞API响应:', res.data);
-
-// if (res.status === 200) {
-// // 更新本地状态
-// feeds.forEach(feed => {
-// if (feed.postNo === dynamicId) {
-// feed.postLikeNum = (feed.postLikeNum || 0) + 1;
-// feed.liked = true;
-// }
-// });
-// setFeeds([...feeds]); // 更新状态以触发重新渲染
-// } else {
-// alert(res.data.message || '点赞失败');
-// }
-// } catch (err) {
-// console.error('点赞失败', err);
-
-// // 检查错误响应,获取更详细的错误信息
-// if (err.response) {
-// console.error('错误响应数据:', err.response.data);
-// console.error('错误响应状态:', err.response.status);
-// console.error('错误响应头:', err.response.headers);
-// }
-
-// alert('点赞失败,请稍后重试');
-// }
-// };
-
-// // 取消点赞
-// const handleUnlike = async (dynamicId) => {
-// if (!isLoggedIn) {
-// alert('请先登录');
-// return;
-// }
-
-// // 验证dynamicId是否有效
-// if (!dynamicId) {
-// console.error('无效的dynamicId:', dynamicId);
-// alert('取消点赞失败:动态ID无效');
-// return;
-// }
-
-// // 检查是否已经取消点赞,防止重复请求
-// const currentFeed = feeds.find(feed => feed.postNo === dynamicId);
-// if (currentFeed && !currentFeed.liked) {
-// console.warn('尝试重复取消点赞,已忽略');
-// return;
-// }
-
-// try {
-// // 确保参数是整数类型
-// const requestData = {
-// userId: parseInt(userId),
-// dynamicId: parseInt(dynamicId)
-// };
-
-// // 验证参数是否为有效数字
-// if (isNaN(requestData.userId) || isNaN(requestData.dynamicId)) {
-// console.error('无效的参数:', requestData);
-// alert('取消点赞失败:参数格式错误');
-// return;
-// }
-
-// console.log('取消点赞请求数据:', requestData);
-
-// const res = await axios.delete(`/echo/dynamic/unlike`, {
-// headers: {
-// 'Content-Type': 'application/json' // 明确指定JSON格式
-// },
-// data: requestData // 将参数放在data属性中
-// });
-
-// console.log('取消点赞API响应:', res.data);
-
-// if (res.status === 200) {
-// // 更新本地状态
-// feeds.forEach(feed => {
-// if (feed.postNo === dynamicId) {
-// feed.postLikeNum = Math.max(0, (feed.postLikeNum || 0) - 1);
-// feed.liked = false;
-// }
-// });
-// setFeeds([...feeds]); // 更新状态以触发重新渲染
-// } else {
-// alert(res.data.message || '取消点赞失败');
-// }
-// } catch (err) {
-// console.error('取消点赞失败', err);
-
-// // 检查错误响应,获取更详细的错误信息
-// if (err.response) {
-// console.error('错误响应数据:', err.response.data);
-// console.error('错误响应状态:', err.response.status);
-// console.error('错误响应头:', err.response.headers);
-// }
-
-// alert('取消点赞失败,请稍后重试');
-// }
-// };
-
-// // 评论好友动态
-// const handleComment = async (dynamicId, parentCommentId = null, replyToUsername = '') => {
-// if (!isLoggedIn) {
-// alert('请先登录');
-// return;
-// }
-
-// const commentInputRef = document.getElementById(`comment-input-${dynamicId}-${parentCommentId}`);
-// if (!commentInputRef || !commentInputRef.value.trim()) {
-// alert('评论内容不能为空');
-// return;
-// }
-
-// const commentContent = commentInputRef.value.trim();
-
-// try {
-// // 准备请求数据
-// const requestData = {
-// content: commentContent
-// };
-
-// // 如果是回复,添加parent_comment_id
-// if (parentCommentId) {
-// requestData.parent_comment_id = parentCommentId;
-// }
-
-// const res = await axios.post(`/echo/dynamic/${userId}/feeds/${dynamicId}/comments`, requestData);
-
-// if (res.status === 200 || res.status === 201) {
-// // 成功获取评论数据
-// const newComment = {
-// user_id: userId,
-// username: username,
-// content: commentContent,
-// time: new Date().toISOString(), // 使用当前时间作为评论时间
-// // 如果是回复,添加parent_comment_id和reply_to_username
-// ...(parentCommentId && { parent_comment_id: parentCommentId }),
-// ...(replyToUsername && { reply_to_username: replyToUsername })
-// };
-
-// // 更新本地状态,添加新评论
-// setFeeds(prevFeeds => {
-// return prevFeeds.map(feed => {
-// if (feed.postNo === dynamicId) {
-// // 确保comments是数组,并且正确合并新评论
-// const currentComments = Array.isArray(feed.comments) ? feed.comments : [];
-
-// if (parentCommentId) {
-// // 查找父评论并添加回复
-// return {
-// ...feed,
-// comments: currentComments.map(comment => {
-// if (comment.id === parentCommentId || comment.postNo === parentCommentId) {
-// // 如果父评论已有replies数组,添加到其中
-// if (Array.isArray(comment.replies)) {
-// return {
-// ...comment,
-// replies: [...comment.replies, newComment]
-// };
-// } else {
-// // 否则创建新的replies数组
-// return {
-// ...comment,
-// replies: [newComment]
-// };
-// }
-// }
-// return comment;
-// })
-// };
-// } else {
-// // 普通评论,添加到评论列表
-// return {
-// ...feed,
-// comments: [...currentComments, newComment]
-// };
-// }
-// }
-// return feed;
-// });
-// });
-
-// // 清空输入框
-// if (commentInputRef) {
-// commentInputRef.value = '';
-// }
-
-// // 隐藏回复框
-// toggleReplyBox(dynamicId, parentCommentId);
-// } else {
-// alert(res.data.error || '评论失败');
-// }
-// } catch (err) {
-// console.error('评论失败', err);
-// alert('评论失败,请稍后重试');
-// }
-// };
-
-// // 切换回复框显示状态
-// const toggleReplyBox = (dynamicId, parentCommentId = null) => {
-// const replyBoxId = `reply-box-${dynamicId}-${parentCommentId}`;
-// const replyBox = document.getElementById(replyBoxId);
-
-// if (replyBox) {
-// replyBox.style.display = replyBox.style.display === 'none' ? 'block' : 'none';
-
-// // 如果显示,聚焦到输入框
-// if (replyBox.style.display === 'block') {
-// const commentInput = document.getElementById(`comment-input-${dynamicId}-${parentCommentId}`);
-// if (commentInput) commentInput.focus();
-// }
-// }
-// };
-
-// return (
-// <div className="friend-moments-container">
-// <Header />
-// <div className="fm-header">
-// <button className="create-btn" onClick={() => setShowModal(true)}>
-// <Edit theme="outline" size="18" style={{ marginRight: '6px' }} />
-// 创建动态
-// </button>
-// </div>
-
-// <div className="feed-list">
-// {loading ? (
-// <div className="loading-message">加载中...</div>
-// ) : error ? (
-// <div className="error-message">{error}</div>
-// ) : !isLoggedIn ? (
-// <div className="login-prompt">
-// <p>请先登录查看好友动态</p>
-// </div>
-// ) : filteredFeeds.length === 0 ? (
-// <div className="empty-message">暂无动态</div>
-// ) : (
-// filteredFeeds.map(feed => (
-// <div className="feed-item" key={feed.postNo || `feed-${Math.random()}`}>
-// {/* 显示发布者信息 */}
-// <div className="feed-author">
-// <img
-// className="user-avatar"
-// src={feed.avatar_url || 'https://example.com/default-avatar.jpg'}
-// alt={feed.username || '用户头像'}
-// />
-// <div>
-// <h4>{feed.username || '未知用户'}</h4>
-// <span className="feed-date">{new Date(feed.postTime || Date.now()).toLocaleString()}</span>
-// </div>
-// </div>
-
-// {feed.title && <h4 className="feed-title">{feed.title}</h4>}
-// <p className="feed-content">{feed.postContent || '无内容'}</p>
-
-// {feed.imageUrl && (
-// <div className="feed-images">
-// {typeof feed.imageUrl === 'string' ? (
-// <img src={formatImageUrl(feed.imageUrl)} alt="动态图片" />
-// ) : (
-// feed.imageUrl.map((url, i) => (
-// <img key={i} src={formatImageUrl(url)} alt={`动态图${i}`} />
-// ))
-// )}
-// </div>
-// )}
-
-// <div className="feed-footer">
-// <div className="like-container">
-// <button className="icon-btn" onClick={() => handleLike(feed.postNo, feed.liked, feed.user_id)}>
-// <GoodTwo theme="outline" size="24" fill={feed.liked ? '#f00' : '#fff'} />
-// <span>{feed.postLikeNum || 0}</span>
-// </button>
-
-// <button
-// className="icon-btn"
-// onClick={() => toggleReplyBox(feed.postNo)}
-// >
-// <Comment theme="outline" size="24" fill="#333" />
-// <span>评论</span>
-// </button>
-// </div>
-
-// {feed.user_id === userId && (
-// <button className="delete-btn" onClick={() => handleDelete(feed.postNo)}>
-// 删除
-// </button>
-// )}
-// </div>
-
-// {/* 动态的评论输入框 */}
-// <div id={`reply-box-${feed.postNo}-null`} className="comment-box" style={{display: 'none'}}>
-// <textarea
-// id={`comment-input-${feed.postNo}-null`}
-// className="comment-input"
-// placeholder="请输入评论内容..."
-// />
-// <button
-// className="submit-comment-btn"
-// onClick={() => handleComment(feed.postNo)}
-// >
-// 发布评论
-// </button>
-// </div>
-
-// {/* 评论列表 */}
-// {Array.isArray(feed.comments) && feed.comments.length > 0 && (
-// <div className="comments-container">
-// <h5>评论 ({feed.comments.length})</h5>
-// <div className="comments-list">
-// {feed.comments.map((comment, index) => (
-// <div className="comment-item" key={index}>
-// <div className="comment-header">
-// <span className="comment-user">{comment.username || '用户'}</span>
-// <span className="comment-time">
-// {new Date(comment.time || Date.now()).toLocaleString()}
-// </span>
-// </div>
-// <p className="comment-content">
-// {/* 显示回复格式 */}
-// {comment.reply_to_username ?
-// <span className="reply-prefix">{comment.username} 回复 {comment.reply_to_username}:</span> :
-// <span>{comment.username}:</span>
-// }
-// {comment.content}
-// </p>
-// <button
-// className="reply-btn"
-// onClick={() => toggleReplyBox(feed.postNo, comment.id || index)}
-// >
-// 回复
-// </button>
-
-// {/* 该评论的回复框 */}
-// <div id={`reply-box-${feed.postNo}-${comment.id || index}`} className="comment-box nested-reply-box" style={{display: 'none'}}>
-// <textarea
-// id={`comment-input-${feed.postNo}-${comment.id || index}`}
-// className="comment-input"
-// placeholder={`回复 ${comment.username}...`}
-// />
-// <button
-// className="submit-comment-btn"
-// onClick={() => handleComment(feed.postNo, comment.id || index, comment.username)}
-// >
-// 发布回复
-// </button>
-// </div>
-
-// {/* 嵌套回复 */}
-// {Array.isArray(comment.replies) && comment.replies.length > 0 && (
-// <div className="nested-replies">
-// {comment.replies.map((reply, replyIndex) => (
-// <div className="reply-item" key={replyIndex}>
-// <p className="reply-content">
-// {reply.reply_to_username ?
-// <span className="reply-prefix">{reply.username} 回复 {reply.reply_to_username}:</span> :
-// <span>{reply.username}:</span>
-// }
-// {reply.content}
-// </p>
-// <button
-// className="reply-btn"
-// onClick={() => toggleReplyBox(feed.postNo, reply.id || `${index}-${replyIndex}`, reply.username)}
-// >
-// 回复
-// </button>
-
-// {/* 该回复的回复框 */}
-// <div id={`reply-box-${feed.postNo}-${reply.id || `${index}-${replyIndex}`}`} className="comment-box nested-reply-box" style={{display: 'none'}}>
-// <textarea
-// id={`comment-input-${feed.postNo}-${reply.id || `${index}-${replyIndex}`}`}
-// className="comment-input"
-// placeholder={`回复 ${reply.username}...`}
-// />
-// <button
-// className="submit-comment-btn"
-// onClick={() => handleComment(feed.postNo, reply.id || `${index}-${replyIndex}`, reply.username)}
-// >
-// 发布回复
-// </button>
-// </div>
-// </div>
-// ))}
-// </div>
-// )}
-// </div>
-// ))}
-// </div>
-// </div>
-// )}
-// </div>
-// ))
-// )}
-// </div>
-
-// {/* Modal 对话框 */}
-// {showModal && (
-// <div className="modal-overlay" onClick={() => setShowModal(false)}>
-// <div className="modal-dialog" onClick={e => e.stopPropagation()}>
-// <h3>发布新动态</h3>
-// <input
-// type="text"
-// placeholder="标题"
-// value={title}
-// onChange={e => setTitle(e.target.value)}
-// />
-// <textarea
-// placeholder="写下你的内容..."
-// value={content}
-// onChange={e => setContent(e.target.value)}
-// />
-// <label className="file-label">
-// 选择图片
-// <input
-// type="file"
-// accept="image/*"
-// multiple
-// onChange={handleImageChange}
-// style={{ display: 'none' }}
-// />
-// </label>
-// <div className="cf-preview">
-// {previewUrls.map((url, i) => (
-// <img key={i} src={url} alt={`预览${i}`} />
-// ))}
-// </div>
-// <div className="modal-actions">
-// <button className="btn cancel" onClick={() => setShowModal(false)}>
-// 取消
-// </button>
-// <button className="btn submit" onClick={handleSubmit}>
-// 发布
-// </button>
-// </div>
-// </div>
-// </div>
-// )}
-// </div>
-// );
-// };
-
-// export default FriendMoments;
-
-
// FriendMoments.js
import React, { useContext, useState, useEffect } from 'react';
import axios from 'axios';
@@ -1790,18 +452,18 @@
{/* 显示发布者信息 */}
<div className="feed-author">
<img
- className="user-avatar"
+ style={{ width: '70px', height: '70px', borderRadius: '50%' }}
src={feed.avatar_url || 'https://example.com/default-avatar.jpg'}
alt={feed.username || '用户头像'}
/>
<div>
- <h4>{feed.username || '未知用户'}</h4>
+ <div style={{ fontWeight: 'bold', fontSize: '20px', marginBottom: '5px' }}>{feed.username || '未知用户'}</div>
<span className="feed-date">{new Date(feed.postTime || Date.now()).toLocaleString()}</span>
</div>
</div>
- {feed.title && <h4 className="feed-title">{feed.title}</h4>}
- <p className="feed-content">{feed.postContent || '无内容'}</p>
+ {feed.title && <h4 style={{ fontWeight: 'bold', fontSize: '18px', margin: '15px 0' }}>{feed.title}</h4>}
+ <div style={{ margin: '20px 0' }}>{feed.postContent || '无内容'}</div>
{feed.imageUrl && (
<div className="feed-images">
@@ -1818,7 +480,7 @@
<div className="feed-footer">
<div className="like-container">
<button className="icon-btn" onClick={() => handleLike(feed.postNo, feed.liked, feed.user_id)}>
- <GoodTwo theme="outline" size="24" fill={feed.liked ? '#f00' : '#fff'} />
+ <GoodTwo theme="outline" size="24" fill={feed.liked ? '#ffa600dd' : '#000000'} />
<span>{feed.postLikeNum || 0}</span>
</button>
@@ -1828,8 +490,8 @@
toggleReplyBox(feed.postNo);
}}
>
- <Comment theme="outline" size="24" fill="#333" />
- <span>评论</span>
+ <Comment theme="outline" size="24" fill="#333" />评论
+ {/* <span style={{ fontSize: '14px', color: '#333' }}>评论</span> */}
</button>
</div>
@@ -1861,7 +523,7 @@
{/* 评论列表 */}
{Array.isArray(feed.comments) && feed.comments.length > 0 && (
<div className="comments-container">
- <h5>评论 ({feed.comments.length})</h5>
+ <h5 style={{ fontWeight: 'bold', fontSize: '18px', marginTop: '10px', marginBottom: '20px' }}>评论 ({feed.comments.length})</h5>
<div className="comments-list">
{feed.comments.map((comment, index) => (
<div className="comment-item" key={index}>
@@ -1873,10 +535,10 @@
</div>
<p className="comment-content">
{/* 显示回复格式 */}
- {comment.reply_to_username ?
+ {/* {comment.reply_to_username ?
<span className="reply-prefix">{comment.username} 回复 {comment.reply_to_username}:</span> :
<span>{comment.username}:</span>
- }
+ } */}
{comment.content}
</p>
<button