修改好友动态、发布动态、促销模块、创建帖子,Resolve review.

Change-Id: I84a2460dd1208bc703b0527d98225204d03e5efc
diff --git a/src/pages/FriendMoments/CreateMoment.css b/src/pages/FriendMoments/CreateMoment.css
new file mode 100644
index 0000000..ddbaf7b
--- /dev/null
+++ b/src/pages/FriendMoments/CreateMoment.css
@@ -0,0 +1,63 @@
+  /* .create-feed-page {
+    margin: 0 auto;
+    padding-bottom: 40px;
+  }
+  
+  .cf-header {
+    display: flex;
+    align-items: center;
+    gap: 10px;
+    margin-top: 20px;
+
+  }
+  
+  .cf-header h3 {
+    margin: 0;
+  }
+  
+  .cf-form {
+    display: flex;
+    flex-direction: column;
+    gap: 12px;
+  }
+  
+  .cf-form input[type="text"],
+  .cf-form textarea {
+    width: 100%;
+    padding: 8px;
+    font-size: 14px;
+    border: 1px solid #ccc;
+    border-radius: 4px;
+  }
+  
+  .cf-form textarea {
+    min-height: 100px;
+    resize: vertical;
+  }
+  
+  .cf-form input[type="file"] {
+    font-size: 14px;
+  }
+  
+  .cf-preview {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 8px;
+  }
+  
+  .cf-preview img {
+    width: 80px;
+    height: 80px;
+    object-fit: cover;
+    border-radius: 4px;
+    border: 1px solid #bbb;
+  }
+  
+  .cf-submit-btn {
+    align-self: flex-end;
+    padding: 8px 16px;
+    font-size: 14px;
+    cursor: pointer;
+    background: #BA929A;
+  }
+   */
\ No newline at end of file
diff --git a/src/pages/FriendMoments/CreateMoment.jsx b/src/pages/FriendMoments/CreateMoment.jsx
new file mode 100644
index 0000000..4aca455
--- /dev/null
+++ b/src/pages/FriendMoments/CreateMoment.jsx
@@ -0,0 +1,206 @@
+// // import React, { useState } from 'react';
+// // import axios from 'axios';
+// // import { useNavigate } from 'react-router-dom';
+// // import './CreateMoment.css';
+// // import Header from '../../components/Header';
+
+// // const API_BASE = process.env.REACT_APP_API_BASE;
+// // const USER_ID = 456;
+
+// // const CreateMoment = () => {
+// //   const [title, setTitle] = useState('');
+// //   const [content, setContent] = useState('');
+// //   const [previewUrls, setPreviewUrls] = useState([]);
+// //   const [images, setImages] = useState([]);
+// //   const navigate = useNavigate();
+
+// //   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(file => uploadImageToServer(file))
+// //       );
+// //       setImages(uploaded);
+// //     } catch (err) {
+// //       console.error('图片上传失败:', err);
+// //       alert('有图片上传失败,请重试');
+// //     }
+// //   };
+
+// //   const uploadImageToServer = async (file) => {
+// //     const formData = new FormData();
+// //     formData.append('file', file);
+// //     const res = await axios.post(`${API_BASE}/upload`, formData, {
+// //       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}/CreateMoment`,
+// //         {
+// //           title: title.trim() || undefined,
+// //           friend_content: content.trim(),
+// //           images
+// //         }
+// //       );
+// //       navigate('/friend-moments');
+// //     } catch (err) {
+// //       console.error('发布失败:', err);
+// //       alert('发布失败,请稍后重试');
+// //     }
+// //   };
+
+// //   return (
+// //     <div className="create-feed-page">
+// //       <Header/>
+// //       <div className="cf-header">
+// //         <button onClick={() => navigate(-1)} style={{padding : '5px 10px', backgroundColor: '#BA929A', color: 'white'}}>返回</button>
+// //         <h3>发布新动态</h3>
+// //       </div>
+
+// //       <div className="cf-form">
+// //         <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}
+// //         />
+// //         <div className="cf-preview">
+// //           {previewUrls.map((url, i) => (
+// //             <img key={i} src={url} alt={`预览 ${i}`} />
+// //           ))}
+// //         </div>
+// //         <button className="cf-submit-btn" onClick={handleSubmit}>
+// //           发布
+// //         </button>
+// //       </div>
+// //     </div>
+// //   );
+// // };
+
+// // export default CreateMoment;
+// import React, { useState } from 'react';
+// import axios from 'axios';
+// import { useNavigate } from 'react-router-dom';
+// import './CreateMoment.css';
+// import Header from '../../components/Header';
+
+// const API_BASE = process.env.REACT_APP_API_BASE;
+// const USER_ID = 456;
+
+// const CreateMoment = ({ onClose, fetchFeeds }) => {
+//     const [title, setTitle] = useState('');
+//     const [content, setContent] = useState('');
+//     const [previewUrls, setPreviewUrls] = useState([]);
+//     const [images, setImages] = useState([]);
+//     const navigate = useNavigate();
+
+//     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(file => uploadImageToServer(file))
+//             );
+//             setImages(uploaded);
+//         } catch (err) {
+//             console.error('图片上传失败:', err);
+//             alert('有图片上传失败,请重试');
+//         }
+//     };
+
+//     const uploadImageToServer = async (file) => {
+//         const formData = new FormData();
+//         formData.append('file', file);
+//         const res = await axios.post(`${API_BASE}/upload`, formData, {
+//             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}/CreateMoment`,
+//                 {
+//                     title: title.trim() || undefined,
+//                     friend_content: content.trim(),
+//                     images
+//                 }
+//             );
+//             onClose();
+//             fetchFeeds();
+//         } catch (err) {
+//             console.error('发布失败:', err);
+//             alert('发布失败,请稍后重试');
+//         }
+//     };
+
+//     return (
+//         <div className="create-feed-page">
+//             <div className="cf-header">
+//                 <button onClick={onClose} style={{ padding: '5px 10px', backgroundColor: '#BA929A', color: 'white' }}>
+//                     返回
+//                 </button>
+//                 <h3>发布新动态</h3>
+//             </div>
+//             <div className="cf-form">
+//                 <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}
+//                 />
+//                 <div className="cf-preview">
+//                     {previewUrls.map((url, i) => (
+//                         <img key={i} src={url} alt={`预览 ${i}`} />
+//                     ))}
+//                 </div>
+//                 <button className="cf-submit-btn" onClick={handleSubmit}>
+//                     发布
+//                 </button>
+//             </div>
+//         </div>
+//     );
+// };
+
+// export default CreateMoment;
+    
diff --git a/src/pages/FriendMoments/FriendMoments.css b/src/pages/FriendMoments/FriendMoments.css
index c95bdcf..a69d919 100644
--- a/src/pages/FriendMoments/FriendMoments.css
+++ b/src/pages/FriendMoments/FriendMoments.css
@@ -1,88 +1,171 @@
-/* .friend-moments {
-    background-color: #5F4437;
-    color: white;
-  }
-  .header {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    padding: 10px;
-  }
-  .logo-and-name {
-    display: flex;
-    align-items: center;
-  }
-  .logo {
-    height: 30px;
-    margin-right: 10px;
-  }
-  .site-name {
-    font-size: 24px;
-  }
-  .user-and-message {
-    display: flex;
-    align-items: center;
-  }
-  .user-avatar {
-    height: 40px;
-    margin-right: 10px;
-  }
-  .message-center {
-    font-size: 16px;
-  }
-  .nav {
-    background-color: #dab8c2;
-    display: flex;
-    justify-content: center;
-  }
-  .nav-item {
-    color: white;
-    text-decoration: none;
-    padding: 10px 20px;
-  }
-  .active {
-    background-color: #996633;
-  }
-  .content {
-    padding: 20px;
-  }
-  .user-post {
-    border-bottom: 1px solid white;
-    margin-bottom: 20px;
-    padding-bottom: 20px;
-  }
-  .user-info {
-    display: flex;
-    align-items: center;
-    margin-bottom: 10px;
-  }
-  .user-avatar-small {
-    height: 30px;
-    margin-right: 10px;
-  }
-  .username {
-    font-size: 16px;
-  }
-  .post-content {
-    margin-bottom: 10px;
-  }
-  .post-actions {
-    display: flex;
-    align-items: center;
-    margin-bottom: 10px;
-  }
-  .like-icon,
-  .comment-icon {
-    margin-right: 5px;
-  }
-  .like-count,
-  .comment-count {
-    margin-left: 5px;
-  }
-  .post-image {
-    float: right;
-    width: 150px;
-    height: 150px;
-    background-color: #ddd;
-    margin-left: 10px;
-  } */
\ No newline at end of file
+.friend-moments-container {
+  margin: 0 auto;
+  background: linear-gradient(180deg, #5F4437, #823c3c);
+  padding-bottom: 40px;
+}
+
+.fm-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 2%;
+}
+
+
+.f-search-bar {
+  display: flex;
+  align-items: center;
+  gap: 5px;
+}
+
+.search-input {
+  padding: 6px 8px;
+  font-size: 14px;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+}
+
+.search-btn {
+  padding: 6px 12px;
+  font-size: 14px;
+  cursor: pointer;
+  background: #fff;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+}
+
+.feed-list .feed-item {
+  padding: 1% 1.5%;
+  margin: 1% 2%;
+  border-radius: 6px;
+  /*设置item之间的间隔*/
+  margin-bottom: 2%;
+  background-color: #e9ded2;
+}
+
+.feed-item h4 {
+  margin: 0 0 5px;
+}
+
+.feed-item p {
+  margin: 0 0 10px;
+  line-height: 1.4;
+}
+
+.feed-images {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 6px;
+  margin-bottom: 10px;
+}
+
+.feed-images img {
+  width: 100px;
+  height: 100px;
+  object-fit: cover;
+  border-radius: 4px;
+  border: 1px solid #ddd;
+}
+
+.feed-footer {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  font-size: 12px;
+  color: #666;
+}
+
+.delete-btn {
+  background: none;
+  border: none;
+  color: #f44;
+  cursor: pointer;
+  font-size: 12px;
+}
+
+/* Modal 样式 */
+.modal-overlay {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background: rgba(0,0,0,0.5);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 1000;
+}
+
+.modal-dialog {
+  background: #e9ded2;
+  padding: 20px;
+  width: 35%;
+  border-radius: 8px;
+  display: flex;
+  flex-direction: column;
+  gap: 20px;
+}
+
+/* 标题 */
+.modal-dialog h3 {
+  margin: 0;
+  color : #4A3B34;
+}
+
+.modal-dialog input[type="text"],
+.modal-dialog textarea {
+  width: 97%;
+  padding: 8px;
+  font-size: 14px;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+}
+
+.modal-dialog input[type="file"] {
+  width: 97%;
+  font-size: 14px;
+  border-radius: 4px;
+}
+
+.modal-dialog textarea {
+  resize: vertical;
+  min-height: 80px;
+}
+
+.cf-preview {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px;
+}
+
+.cf-preview img {
+  width: 80px;
+  height: 80px;
+  object-fit: cover;
+  border-radius: 4px;
+  border: 1px solid #bbb;
+}
+
+.modal-actions {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 10px;
+}
+
+.modal-actions .btn {
+  padding: 6px 12px;
+  font-size: 14px;
+  cursor: pointer;
+  border: none;
+  border-radius: 4px;
+}
+
+.modal-actions .btn.cancel {
+  background: #5F4437;
+}
+
+.modal-actions .btn.submit {
+  background: #BA929A;
+  color: #fff;
+}
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;
+