修改帖子
Change-Id: I467b35242bce8b27d612eb96f2710b27aa03d1d2
diff --git a/src/App.js b/src/App.js
index 770c7f9..0499188 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,4 +1,5 @@
import { Route } from 'wouter';
+import { Redirect } from 'wouter';
import AuthPage from './pages/AuthPage/AuthPage';
import HomePage from './pages/HomePage';
import FriendMoments from './pages/FriendMoments/FriendMoments';
@@ -7,7 +8,7 @@
import PostDetailPage from './pages/Forum/posts-detail/PostDetailPage';
import { UserProvider } from './context/UserContext';
import PublishSeed from './pages/PublishSeed/PublishSeed';
-import SeedDetail from './pages/SeedList/SeedDetail/SeedDetail';
+import SeedDetail from './pages/SeedList/SeedDetail/SeedDetail';
import InterestGroup from './pages/InterestGroup/InterestGroup';
import UserProfile from './pages/UserCenter/UserProfile';
import CreatePostPage from './pages/Forum/posts-create/CreatePostPage';
@@ -17,11 +18,18 @@
import LevelPage from './pages/LevelPage/LevelPage';
import NewbieTasks from './pages/UserCenter/NewbieTasks';
+function RedirectToAuth() {
+ if (typeof window !== 'undefined') {
+ window.location.replace('/auth');
+ }
+ return null;
+}
+
function App() {
return (
<UserProvider>
<>
- <Route path="/" component={HomePage} />
+ <Route path="/" component={RedirectToAuth} />
<Route path="/auth" component={AuthPage} />
<Route path="/friend-moments" component={FriendMoments} />
<Route path="/friend-moments/create" component={CreateMoment} />
@@ -30,12 +38,12 @@
<Route path="/forum/create-post" component={CreatePostPage} />
<Route path="/seed-list" component={SeedList} />
<Route path="/publish-seed" component={PublishSeed} />
- <Route path="/seed/:seed_id" component={SeedDetail} /> {/* 新增路由 */}
- <Route path="/interest-groups" component={InterestGroup}/>
- <Route path="/user/profile" component={UserProfile}/>
- <Route path="/messages" component={MessagePage}/>
- <Route path="/promotions" component={PromotionsPage}/>
- <Route path="/level" component={LevelPage}/>
+ <Route path="/seed/:seed_id" component={SeedDetail} />
+ <Route path="/interest-groups" component={InterestGroup} />
+ <Route path="/user/profile" component={UserProfile} />
+ <Route path="/messages" component={MessagePage} />
+ <Route path="/promotions" component={PromotionsPage} />
+ <Route path="/level" component={LevelPage} />
<Route path="/user/newbie-tasks" component={NewbieTasks} />
</>
</UserProvider>
diff --git a/src/context/UserContext.js b/src/context/UserContext.js
index 69f73bd..39ab6cd 100644
--- a/src/context/UserContext.js
+++ b/src/context/UserContext.js
@@ -1,49 +1,7 @@
-// import React, { createContext, useContext, useState, useEffect } from 'react';
-
-// const UserContext = createContext();
-
-// export const UserProvider = ({ children }) => {
-// const [user, setUser] = useState(null);
-// const [loading, setLoading] = useState(true);
-
-// useEffect(() => {
-// const storedUser = localStorage.getItem('user');
-// if (storedUser) {
-// setUser(JSON.parse(storedUser));
-// } else {
-// // 设置默认用户(id: 1)
-// const defaultUser = { id: 1, name: '测试用户' };
-// localStorage.setItem('user', JSON.stringify(defaultUser));
-// setUser(defaultUser);
-// }
-// setLoading(false);
-// }, []);
-
-// const saveUser = (userData) => {
-// localStorage.setItem('user', JSON.stringify(userData));
-// setUser(userData);
-// };
-
-// const logout = () => {
-// localStorage.removeItem('user');
-// setUser(null);
-// };
-
-// return (
-// <UserContext.Provider value={{ user, loading, saveUser, logout }}>
-// {children}
-// </UserContext.Provider>
-// );
-// };
-
-// export const useUser = () => useContext(UserContext);
-
import React, { createContext, useContext, useState, useEffect } from 'react';
-// 创建上下文
-const UserContext = createContext();
+export const UserContext = createContext();
-// Provider 组件
export const UserProvider = ({ children }) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
@@ -51,19 +9,29 @@
useEffect(() => {
const storedUser = localStorage.getItem('user');
if (storedUser) {
- setUser(JSON.parse(storedUser));
- } else {
- // 设置默认用户
- const defaultUser = { id: 1, name: '测试用户' };
- localStorage.setItem('user', JSON.stringify(defaultUser));
- setUser(defaultUser);
+ try {
+ const parsedUser = JSON.parse(storedUser);
+ // 验证用户对象是否有效
+ if (parsedUser && parsedUser.userId) {
+ setUser(parsedUser);
+ } else {
+ localStorage.removeItem('user');
+ }
+ } catch (error) {
+ console.error('解析用户信息失败:', error);
+ localStorage.removeItem('user');
+ }
}
setLoading(false);
}, []);
const saveUser = (userData) => {
- localStorage.setItem('user', JSON.stringify(userData));
- setUser(userData);
+ if (userData && userData.id) {
+ localStorage.setItem('user', JSON.stringify(userData));
+ setUser(userData);
+ } else {
+ console.error('无效的用户数据:', userData);
+ }
};
const logout = () => {
@@ -71,17 +39,17 @@
setUser(null);
};
- // ✅ 加载完用户数据后再渲染子组件,避免子组件访问 null
- if (loading) {
- return <div>正在加载用户信息...</div>;
- }
-
return (
- <UserContext.Provider value={{ user, saveUser, logout }}>
+ <UserContext.Provider value={{ user, saveUser, logout, loading }}>
{children}
</UserContext.Provider>
);
};
-// 自定义 hook
-export const useUser = () => useContext(UserContext);
+export const useUser = () => {
+ const context = useContext(UserContext);
+ if (!context) {
+ throw new Error('useUser must be used within a UserProvider');
+ }
+ return context;
+};
\ No newline at end of file
diff --git a/src/pages/AuthPage/AuthPage.jsx b/src/pages/AuthPage/AuthPage.jsx
index 4c51ff9..64f3378 100644
--- a/src/pages/AuthPage/AuthPage.jsx
+++ b/src/pages/AuthPage/AuthPage.jsx
@@ -67,8 +67,9 @@
if (data.msg === "登录成功" && data.user) {
// 保存用户信息到 localStorage
localStorage.setItem("user", JSON.stringify(data.user));
- localStorage.setItem("userId", data.user.id); // 如果有 id 字段
- window.location.href = '/forum';
+ localStorage.setItem("userId", data.user.userId); // 如果有 id 字段
+ debugger
+ // window.location.href = '/forum';
} else {
throw new Error(data.msg || "登录失败");
}
diff --git a/src/pages/Forum/posts-detail/PostDetailPage.jsx b/src/pages/Forum/posts-detail/PostDetailPage.jsx
index a505d88..159bdfa 100644
--- a/src/pages/Forum/posts-detail/PostDetailPage.jsx
+++ b/src/pages/Forum/posts-detail/PostDetailPage.jsx
@@ -1,9 +1,9 @@
-import React, { useEffect, useState } from 'react';
+import React, { useContext, useEffect, useState } from 'react';
import { useParams } from 'wouter';
import { GoodTwo, Star } from '@icon-park/react';
import { getPostDetail, getPostComments, likePost, unlikePost, addCommentToPost, collectPost, uncollectPost } from './api'; // 引入你的 API 函数
import './PostDetailPage.css';
-import { useUser } from '../../../context/UserContext'; // 注意路径
+import { UserContext, useUser } from '../../../context/UserContext'; // 注意路径
import Header from '../../../components/Header';
const PostDetailPage = () => {
@@ -20,7 +20,8 @@
const [replyToUsername, setReplyToUsername] = useState(null);
// 获取当前用户ID(假设从上下文中获取)
- const { user } = useUser(); // 你需要从用户上下文获取用户 ID
+ const { user } = useContext(UserContext);
+ // const { user } = useUser(); // 你需要从用户上下文获取用户 ID
useEffect(() => {
const fetchPostDetail = async () => {
@@ -69,7 +70,7 @@
try {
if (isLiked) {
// 取消点赞
- await unlikePost(postId, user.id);
+ await unlikePost(postId, user.userId);
setIsLiked(false);
setPostDetail((prev) => ({
...prev,
@@ -77,7 +78,7 @@
}));
} else {
// 点赞
- await likePost(postId, user.id);
+ await likePost(postId, user.userId);
setIsLiked(true);
setPostDetail((prev) => ({
...prev,
@@ -100,7 +101,7 @@
try {
if (isCollected) {
// 取消收藏 - 使用原有的collectPost函数,传递action: "cancel"
- await collectPost(postId, user.id, "cancel");
+ await collectPost(postId, user.userId, "cancel");
setIsCollected(false);
setPostDetail((prev) => ({
...prev,
@@ -108,7 +109,7 @@
}));
} else {
// 收藏
- await collectPost(postId, user.id, "collect");
+ await collectPost(postId, user.userId, "collect");
setIsCollected(true);
setPostDetail((prev) => ({
...prev,
@@ -121,40 +122,57 @@
}
};
- // 添加评论
+// 添加评论
const handleAddComment = async () => {
+ // 直接使用组件顶层获取的 user
+ if (!user || !user.userId) {
+ alert('请先登录后再评论');
+ return;
+ }
+
if (!newComment.trim()) {
alert('评论内容不能为空');
return;
}
try {
+ // 构建评论数据
const commentPayload = {
content: newComment,
- userId: user.id,
+ userId: user.userId, // 使用已获取的用户ID
isAnonymous: false,
com_comment_id: replyToCommentId || null,
};
+ // 发送评论请求
const commentData = await addCommentToPost(postId, commentPayload);
- setComments((prev) => [
- ...prev,
- {
- commentId: (commentData && commentData.commentId) || Date.now(),
- post_id: postId,
- userId: user.id,
- content: newComment,
- commentTime: new Date().toISOString(),
- comCommentId: replyToCommentId,
- },
- ]);
+ // 更新评论列表
+ const newCommentItem = {
+ commentId: commentData?.commentId || Date.now(),
+ post_id: postId,
+ userId: user.userId,
+ content: newComment,
+ commentTime: new Date().toISOString(),
+ comCommentId: replyToCommentId,
+ };
+ setComments((prevComments) => [newCommentItem, ...prevComments]);
+
+ // 重置表单
setNewComment('');
setReplyToCommentId(null);
- } catch (err) {
- console.error('评论添加失败:', err);
- alert('评论失败,请稍后再试');
+
+ // alert('评论成功!');
+ } catch (error) {
+ console.error('评论失败:', error);
+
+ const errorMessage =
+ error.response?.data?.message ||
+ error.message ||
+ '评论失败,请稍后再试';
+
+ alert(errorMessage);
}
};
diff --git a/src/pages/Forum/promotion-part/Promotion.jsx b/src/pages/Forum/promotion-part/Promotion.jsx
index 36d6319..49863e3 100644
--- a/src/pages/Forum/promotion-part/Promotion.jsx
+++ b/src/pages/Forum/promotion-part/Promotion.jsx
@@ -1,16 +1,153 @@
+// import React, { useEffect, useState, useRef } from 'react';
+// import './Promotion.css';
+
+// const Promotion = () => {
+// const [promotions, setPromotions] = useState([]);
+// const [coldResources, setColdResources] = useState([]);
+// const [loading, setLoading] = useState(true);
+
+// const [promoIndex, setPromoIndex] = useState(0);
+// const [coldIndex, setColdIndex] = useState(0);
+
+// const promoTimerRef = useRef(null);
+// const coldTimerRef = useRef(null);
+
+// useEffect(() => {
+// fetchData();
+// }, []);
+
+// useEffect(() => {
+// if (promotions.length === 0) return;
+// clearInterval(promoTimerRef.current);
+// promoTimerRef.current = setInterval(() => {
+// setPromoIndex(prev => (prev + 1) % promotions.length);
+// }, 5000);
+// return () => clearInterval(promoTimerRef.current);
+// }, [promotions]);
+
+// useEffect(() => {
+// if (coldResources.length === 0) return;
+// clearInterval(coldTimerRef.current);
+// coldTimerRef.current = setInterval(() => {
+// setColdIndex(prev => (prev + 1) % coldResources.length);
+// }, 5000);
+// return () => clearInterval(coldTimerRef.current);
+// }, [coldResources]);
+
+// const fetchData = async () => {
+// try {
+// // ✅ 获取促销活动列表(新接口)
+// const promoResponse = await fetch(`seeds/promotions`);
+// const promoJson = await promoResponse.json();
+// const promoData = Array.isArray(promoJson?.result) ? promoJson.result : [];
+// setPromotions(promoData);
+
+// // 冷门资源(接口保持不变,若已更换请提供文档)
+// const coldResponse = await fetch(`/echo/resources/cold`);
+// const coldData = await coldResponse.json();
+// setColdResources(coldData);
+// } catch (error) {
+// console.error('获取数据失败:', error);
+// } finally {
+// setLoading(false);
+// }
+// };
+
+// if (loading) {
+// return <div className="promotion-container">加载中...</div>;
+// }
+
+// const prevPromo = () => setPromoIndex((promoIndex - 1 + promotions.length) % promotions.length);
+// const nextPromo = () => setPromoIndex((promoIndex + 1) % promotions.length);
+// const prevCold = () => setColdIndex((coldIndex - 1 + coldResources.length) % coldResources.length);
+// const nextCold = () => setColdIndex((coldIndex + 1) % coldResources.length);
+
+// const currentPromo = promotions[promoIndex];
+// const currentCold = coldResources[coldIndex];
+
+// return (
+// <div className="promotion-container carousel-container">
+// {/* 促销活动轮播 */}
+// <section className="carousel-section">
+// <h2>当前促销活动</h2>
+// {promotions.length === 0 || !currentPromo ? (
+// <div className="empty-state">暂无促销活动</div>
+// ) : (
+// <div
+// className="carousel"
+// onMouseEnter={() => clearInterval(promoTimerRef.current)}
+// onMouseLeave={() => {
+// promoTimerRef.current = setInterval(() => {
+// setPromoIndex(prev => (prev + 1) % promotions.length);
+// }, 3000);
+// }}
+// >
+// <button className="arrow left" onClick={prevPromo}><</button>
+// <div className="slide">
+// <div><strong>促销名称:</strong>{currentPromo?.name ?? '未知'}</div>
+// <div><strong>促销时间:</strong>
+// {currentPromo?.pStartTime && currentPromo?.pEndTime
+// ? `${new Date(currentPromo.pStartTime).toLocaleString()} ~ ${new Date(currentPromo.pEndTime).toLocaleString()}`
+// : '未知'}
+// </div>
+// <div><strong>上传奖励系数:</strong>{currentPromo?.uploadCoeff ?? '无'}</div>
+// <div><strong>下载折扣系数:</strong>{currentPromo?.downloadCoeff ?? '无'}</div>
+// {currentPromo?.description && (
+// <div><strong>描述:</strong>{currentPromo.description}</div>
+// )}
+// </div>
+// <button className="arrow right" onClick={nextPromo}>></button>
+// </div>
+// )}
+// </section>
+
+// {/* 冷门资源轮播 */}
+// <section className="carousel-section">
+// <h2>冷门资源推荐</h2>
+// {coldResources.length === 0 || !currentCold ? (
+// <div className="empty-state">暂无冷门资源推荐</div>
+// ) : (
+// <div
+// className="carousel"
+// onMouseEnter={() => clearInterval(coldTimerRef.current)}
+// onMouseLeave={() => {
+// coldTimerRef.current = setInterval(() => {
+// setColdIndex(prev => (prev + 1) % coldResources.length);
+// }, 3000);
+// }}
+// >
+// <button className="arrow left" onClick={prevCold}><</button>
+// <div className="slide cold-slide">
+// <img src={currentCold.poster} alt={currentCold.title} className="resource-poster" />
+// <div className="resource-info">
+// <div><strong>标题:</strong>{currentCold.title}</div>
+// <div><strong>下载量:</strong>{currentCold.download_count ?? 0} | <strong>种子数:</strong>{currentCold.seed_count ?? 0}</div>
+// <div><strong>激励:</strong>
+// {currentCold.incentives?.download_exempt && <span className="incentive-badge">免下载量</span>}
+// {currentCold.incentives?.extra_seed_bonus && <span className="incentive-badge">做种加成</span>}
+// {!currentCold.incentives?.download_exempt && !currentCold.incentives?.extra_seed_bonus && '无'}
+// </div>
+// </div>
+// </div>
+// <button className="arrow right" onClick={nextCold}>></button>
+// </div>
+// )}
+// </section>
+// </div>
+// );
+// };
+
+// export default Promotion;
+
import React, { useEffect, useState, useRef } from 'react';
import './Promotion.css';
const Promotion = () => {
const [promotions, setPromotions] = useState([]);
- const [coldResources, setColdResources] = useState([]);
const [loading, setLoading] = useState(true);
const [promoIndex, setPromoIndex] = useState(0);
- const [coldIndex, setColdIndex] = useState(0);
-
const promoTimerRef = useRef(null);
- const coldTimerRef = useRef(null);
useEffect(() => {
fetchData();
@@ -25,29 +162,16 @@
return () => clearInterval(promoTimerRef.current);
}, [promotions]);
- useEffect(() => {
- if (coldResources.length === 0) return;
- clearInterval(coldTimerRef.current);
- coldTimerRef.current = setInterval(() => {
- setColdIndex(prev => (prev + 1) % coldResources.length);
- }, 5000);
- return () => clearInterval(coldTimerRef.current);
- }, [coldResources]);
-
const fetchData = async () => {
try {
// ✅ 获取促销活动列表(新接口)
- const promoResponse = await fetch(`seeds/promotions`);
+ const promoResponse = await fetch(`/seeds/promotions`);
const promoJson = await promoResponse.json();
+ console.log('接口返回数据:', promoJson);
const promoData = Array.isArray(promoJson?.result) ? promoJson.result : [];
setPromotions(promoData);
-
- // 冷门资源(接口保持不变,若已更换请提供文档)
- const coldResponse = await fetch(`/echo/resources/cold`);
- const coldData = await coldResponse.json();
- setColdResources(coldData);
} catch (error) {
- console.error('获取数据失败:', error);
+ console.error('获取促销活动失败:', error);
} finally {
setLoading(false);
}
@@ -59,11 +183,7 @@
const prevPromo = () => setPromoIndex((promoIndex - 1 + promotions.length) % promotions.length);
const nextPromo = () => setPromoIndex((promoIndex + 1) % promotions.length);
- const prevCold = () => setColdIndex((coldIndex - 1 + coldResources.length) % coldResources.length);
- const nextCold = () => setColdIndex((coldIndex + 1) % coldResources.length);
-
const currentPromo = promotions[promoIndex];
- const currentCold = coldResources[coldIndex];
return (
<div className="promotion-container carousel-container">
@@ -100,39 +220,6 @@
</div>
)}
</section>
-
- {/* 冷门资源轮播 */}
- <section className="carousel-section">
- <h2>冷门资源推荐</h2>
- {coldResources.length === 0 || !currentCold ? (
- <div className="empty-state">暂无冷门资源推荐</div>
- ) : (
- <div
- className="carousel"
- onMouseEnter={() => clearInterval(coldTimerRef.current)}
- onMouseLeave={() => {
- coldTimerRef.current = setInterval(() => {
- setColdIndex(prev => (prev + 1) % coldResources.length);
- }, 3000);
- }}
- >
- <button className="arrow left" onClick={prevCold}><</button>
- <div className="slide cold-slide">
- <img src={currentCold.poster} alt={currentCold.title} className="resource-poster" />
- <div className="resource-info">
- <div><strong>标题:</strong>{currentCold.title}</div>
- <div><strong>下载量:</strong>{currentCold.download_count ?? 0} | <strong>种子数:</strong>{currentCold.seed_count ?? 0}</div>
- <div><strong>激励:</strong>
- {currentCold.incentives?.download_exempt && <span className="incentive-badge">免下载量</span>}
- {currentCold.incentives?.extra_seed_bonus && <span className="incentive-badge">做种加成</span>}
- {!currentCold.incentives?.download_exempt && !currentCold.incentives?.extra_seed_bonus && '无'}
- </div>
- </div>
- </div>
- <button className="arrow right" onClick={nextCold}>></button>
- </div>
- )}
- </section>
</div>
);
};
diff --git a/src/pages/FriendMoments/FriendMoments.jsx b/src/pages/FriendMoments/FriendMoments.jsx
index 6d9def6..fd017b2 100644
--- a/src/pages/FriendMoments/FriendMoments.jsx
+++ b/src/pages/FriendMoments/FriendMoments.jsx
@@ -4,69 +4,66 @@
import Header from '../../components/Header';
import { Edit } from '@icon-park/react';
-
-const USER_ID = 456;
-
const FriendMoments = () => {
const [feeds, setFeeds] = useState([]);
const [filteredFeeds, setFilteredFeeds] = useState([]);
const [query, setQuery] = useState('');
+ const [userId, setUserId] = useState(456); // 从状态管理或登录信息获取
// Modal state & form fields
const [showModal, setShowModal] = useState(false);
const [title, setTitle] = useState('');
const [content, setContent] = useState('');
- const [previewUrls, setPreviewUrls] = useState([]);
- const [images, setImages] = useState([]);
+ const [selectedImages, setSelectedImages] = useState([]);
+ const [previewUrls, setPreviewUrls] = useState([]); // 新增:图片预览URLs
// 拉取好友动态列表
const fetchFeeds = async () => {
try {
- const res = await axios.get(`/echo/users/${USER_ID}/feeds`);
- setFeeds(res.data.feeds);
- setFilteredFeeds(res.data.feeds);
+ // 修改为新的API路径
+ const res = await axios.get(`/echo/dynamic/${userId}/getAllDynamics`);
+ setFeeds(res.data.posts || []);
+ setFilteredFeeds(res.data.posts || []);
} catch (err) {
console.error('获取动态列表失败:', err);
+ alert('获取动态列表失败,请稍后重试');
}
};
useEffect(() => {
fetchFeeds();
- }, []);
+ }, [userId]);
// 搜索处理
const handleSearch = () => {
const q = query.trim().toLowerCase();
- if (!q) return;
+ if (!q) {
+ setFilteredFeeds(feeds);
+ return;
+ }
setFilteredFeeds(
- feeds.filter(f => (f.title || '').toLowerCase().includes(q))
+ feeds.filter(f =>
+ (f.title || '').toLowerCase().includes(q) ||
+ (f.postContent || '').toLowerCase().includes(q)
+ )
);
};
+
const handleReset = () => {
setQuery('');
setFilteredFeeds(feeds);
};
- // 对话框内:本地预览 & 上传
- const handleImageChange = async (e) => {
+ // 对话框内:处理图片选择
+ const handleImageChange = (e) => {
const files = Array.from(e.target.files);
if (!files.length) return;
- setPreviewUrls(files.map(f => URL.createObjectURL(f)));
- try {
- const uploaded = await Promise.all(files.map(f => uploadImageToServer(f)));
- setImages(uploaded);
- } catch (err) {
- console.error('图片上传失败', err);
- alert('图片上传失败,请重试');
- }
- };
- const uploadImageToServer = async (file) => {
- const fd = new FormData();
- fd.append('file', file);
- const res = await axios.post(`/upload`, fd, {
- headers: {'Content-Type':'multipart/form-data'}
- });
- return res.data.url;
+
+ // 生成预览URLs
+ const previewUrls = files.map(file => URL.createObjectURL(file));
+
+ setSelectedImages(files);
+ setPreviewUrls(previewUrls); // 更新预览URLs
};
// 对话框内:提交新动态
@@ -75,18 +72,33 @@
alert('内容不能为空');
return;
}
+
try {
- await axios.post(
- `/echo/users/${USER_ID}/createFeed`,
- { title: title.trim() || undefined, friend_content: content.trim(), images }
- );
+ const formData = new FormData();
+ formData.append('user_id', userId);
+ 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('');
- setImages([]);
- setPreviewUrls([]);
+ setSelectedImages([]);
+ setPreviewUrls([]); // 重置预览URLs
setShowModal(false);
fetchFeeds();
+ alert('发布成功');
} catch (err) {
console.error('发布失败', err);
alert('发布失败,请稍后重试');
@@ -94,14 +106,75 @@
};
// 删除动态
- const handleDelete = async (feedId) => {
+ const handleDelete = async (dynamicId) => {
if (!window.confirm('确定要删除这条动态吗?')) return;
try {
- await axios.delete(`/echo/users/me/feed/${feedId}`);
+ // 修改为新的API路径
+ await axios.delete(`/echo/dynamic/me/deleteDynamic/${dynamicId}`);
fetchFeeds();
+ alert('删除成功');
} catch (err) {
console.error('删除失败', err);
- alert('删除失败');
+ alert('删除失败,请稍后重试');
+ }
+ };
+
+ // 点赞动态
+ const handleLike = async (dynamicId) => {
+ try {
+ // 调用新的点赞API
+ const res = await axios.post(`/echo/dynamic/like`, {
+ userId,
+ dynamicId
+ });
+
+ if (res.status === 200) {
+ // 更新本地状态
+ setFeeds(feeds.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);
+ alert('点赞失败,请稍后重试');
+ }
+ };
+
+ // 取消点赞
+ const handleUnlike = async (dynamicId) => {
+ try {
+ // 调用新的取消点赞API
+ const res = await axios.delete(`/echo/dynamic/unlike`, {
+ data: { userId, dynamicId }
+ });
+
+ if (res.status === 200) {
+ // 更新本地状态
+ setFeeds(feeds.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);
+ alert('取消点赞失败,请稍后重试');
}
};
@@ -128,13 +201,13 @@
<div className="feed-list">
{filteredFeeds.map(feed => (
- <div className="feed-item" key={feed.feed_id}>
+ <div className="feed-item" key={feed.postNo}>
{feed.title && <h4>{feed.title}</h4>}
- <p>{feed.friend_content}</p>
+ <p>{feed.postContent}</p>
- {feed.images?.length > 0 && (
+ {feed.imageUrl && feed.imageUrl.split(',').length > 0 && (
<div className="feed-images">
- {feed.images.map((url, i) => (
+ {feed.imageUrl.split(',').map((url, i) => (
<img key={i} src={url} alt={`动态图${i}`} />
))}
</div>
@@ -142,10 +215,21 @@
<div className="feed-footer">
<span className="feed-date">
- {new Date(feed.created_at).toLocaleString()}
+ {new Date(feed.postTime).toLocaleString()}
</span>
- {feed.is_mine && (
- <button className="delete-btn" onClick={() => handleDelete(feed.feed_id)}>
+ <div className="like-container">
+ {feed.liked ? (
+ <button className="unlike-btn" onClick={() => handleUnlike(feed.postNo)}>
+ 已点赞 ({feed.postLikeNum || 0})
+ </button>
+ ) : (
+ <button className="like-btn" onClick={() => handleLike(feed.postNo)}>
+ 点赞 ({feed.postLikeNum || 0})
+ </button>
+ )}
+ </div>
+ {feed.user_id === userId && (
+ <button className="delete-btn" onClick={() => handleDelete(feed.postNo)}>
删除
</button>
)}
@@ -170,12 +254,6 @@
value={content}
onChange={e => setContent(e.target.value)}
/>
- {/* <input
- type="file"
- accept="image/*"
- multiple
- onChange={handleImageChange}
- /> */}
<label className="file-label">
选择图片
<input
@@ -187,7 +265,7 @@
/>
</label>
<div className="cf-preview">
- {previewUrls.map((url, i) => (
+ {previewUrls.map((url, i) => ( // 使用定义的previewUrls
<img key={i} src={url} alt={`预览${i}`} />
))}
</div>
@@ -206,5 +284,4 @@
);
};
-export default FriendMoments;
-
+export default FriendMoments;
\ No newline at end of file