修改好友动态、发布动态、促销模块、创建帖子,Resolve review.
Change-Id: I84a2460dd1208bc703b0527d98225204d03e5efc
diff --git a/src/pages/FriendMoments/FriendMoments.jsx b/src/pages/FriendMoments/FriendMoments.jsx
index 4e1a704..fdf101c 100644
--- a/src/pages/FriendMoments/FriendMoments.jsx
+++ b/src/pages/FriendMoments/FriendMoments.jsx
@@ -1,55 +1,210 @@
-// import React from 'react';
-// import './FriendMoments.css';
-// import { Link } from 'wouter';
-// import logo from '../../assets/logo.png';
+import React, { useState, useEffect } from 'react';
+import axios from 'axios';
+import './FriendMoments.css';
+import Header from '../../components/Header';
+import { Edit } from '@icon-park/react';
-// const FriendMoments = () => {
-// return (
-// <div className="friend-moments">
-// {/* 顶部栏 */}
-// <header className="header">
-// {/* 左侧 logo 和网站名称 */}
-// <div className="logo-and-name">
-// {/* 确保此处没有语法错误 */}
-// <img src={logo} alt="网站 logo" className="logo" />
-// <span className="site-name">Echo</span>
-// </div>
-// {/* 右侧用户头像和消息中心 */}
-// <div className="user-and-message">
-// <img src="user-avatar.png" alt="用户头像" className="user-avatar" />
-// <span className="message-center">消息</span>
-// </div>
-// </header>
-// {/* 导航栏 */}
-// <nav className="nav">
-// <Link to="/friend-moments" className="nav-item active">好友动态</Link>
-// <Link to="/forum" className="nav-item">论坛</Link>
-// <Link to="/interest-groups" className="nav-item">兴趣小组</Link>
-// <Link to="/seed-list" className="nav-item">种子列表</Link>
-// <Link to="/publish-seed" className="nav-item">发布种子</Link>
-// </nav>
-// {/* 好友动态内容区域 */}
-// <div className="content">
-// {/* 用户动态示例,可从后端获取数据循环展示 */}
-// <div className="user-post">
-// <div className="user-info">
-// <img src="user1-avatar.png" alt="用户头像" className="user-avatar-small" />
-// <span className="username">user1</span>
-// </div>
-// <div className="post-content">
-// <p>动态内容...</p>
-// </div>
-// <div className="post-actions">
-// {/* <GoodTwo theme="outline" size="24" fill="#fff" /> */}
-// <span className="like-count">21</span>
-// {/* <Comment theme="outline" size="24" fill="#fff"/> */}
-// <span className="comment-count">2</span>
-// </div>
-// <img src="image1.png" alt="动态图片" className="post-image" />
-// </div>
-// </div>
-// </div>
-// );
-// };
+const API_BASE = process.env.REACT_APP_API_BASE;
+const USER_ID = 456;
-// export default FriendMoments;
\ No newline at end of file
+const FriendMoments = () => {
+ const [feeds, setFeeds] = useState([]);
+ const [filteredFeeds, setFilteredFeeds] = useState([]);
+ const [query, setQuery] = useState('');
+
+ // 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 fetchFeeds = async () => {
+ try {
+ const res = await axios.get(`${API_BASE}/echo/users/${USER_ID}/feeds`);
+ setFeeds(res.data.feeds);
+ setFilteredFeeds(res.data.feeds);
+ } catch (err) {
+ console.error('获取动态列表失败:', err);
+ }
+ };
+
+ useEffect(() => {
+ fetchFeeds();
+ }, []);
+
+ // 搜索处理
+ const handleSearch = () => {
+ const q = query.trim().toLowerCase();
+ if (!q) return;
+ setFilteredFeeds(
+ feeds.filter(f => (f.title || '').toLowerCase().includes(q))
+ );
+ };
+ const handleReset = () => {
+ setQuery('');
+ setFilteredFeeds(feeds);
+ };
+
+ // 对话框内:本地预览 & 上传
+ const handleImageChange = async (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(`${API_BASE}/upload`, fd, {
+ headers: {'Content-Type':'multipart/form-data'}
+ });
+ return res.data.url;
+ };
+
+ // 对话框内:提交新动态
+ const handleSubmit = async () => {
+ if (!content.trim()) {
+ alert('内容不能为空');
+ return;
+ }
+ try {
+ await axios.post(
+ `${API_BASE}/echo/users/${USER_ID}/createFeed`,
+ { title: title.trim() || undefined, friend_content: content.trim(), images }
+ );
+ // 重置表单
+ setTitle('');
+ setContent('');
+ setImages([]);
+ setPreviewUrls([]);
+ setShowModal(false);
+ fetchFeeds();
+ } catch (err) {
+ console.error('发布失败', err);
+ alert('发布失败,请稍后重试');
+ }
+ };
+
+ // 删除动态
+ const handleDelete = async (feedId) => {
+ if (!window.confirm('确定要删除这条动态吗?')) return;
+ try {
+ await axios.delete(`${API_BASE}/echo/users/me/feed/${feedId}`);
+ fetchFeeds();
+ } catch (err) {
+ console.error('删除失败', err);
+ alert('删除失败');
+ }
+ };
+
+ 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 className="f-search-bar">
+ <input
+ className="search-input"
+ type="text"
+ value={query}
+ onChange={e => setQuery(e.target.value)}
+ placeholder="输入要搜索的动态"
+ />
+ <button className="search-btn" onClick={handleSearch}>搜索</button>
+ <button className="search-btn" onClick={handleReset}>重置</button>
+ </div>
+ </div>
+
+ <div className="feed-list">
+ {filteredFeeds.map(feed => (
+ <div className="feed-item" key={feed.feed_id}>
+ {feed.title && <h4>{feed.title}</h4>}
+ <p>{feed.friend_content}</p>
+
+ {feed.images?.length > 0 && (
+ <div className="feed-images">
+ {feed.images.map((url, i) => (
+ <img key={i} src={url} alt={`动态图${i}`} />
+ ))}
+ </div>
+ )}
+
+ <div className="feed-footer">
+ <span className="feed-date">
+ {new Date(feed.created_at).toLocaleString()}
+ </span>
+ {feed.is_mine && (
+ <button className="delete-btn" onClick={() => handleDelete(feed.feed_id)}>
+ 删除
+ </button>
+ )}
+ </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)}
+ />
+ {/* <input
+ type="file"
+ accept="image/*"
+ multiple
+ onChange={handleImageChange}
+ /> */}
+ <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;
+