blob: fd017b27bd84793075abae4ebfcef9e11ca79d46 [file] [log] [blame]
Krishyaf1d0ea82025-05-03 17:01:58 +08001import React, { useState, useEffect } from 'react';
2import axios from 'axios';
3import './FriendMoments.css';
4import Header from '../../components/Header';
5import { Edit } from '@icon-park/react';
Krishyae71688a2025-04-10 21:25:17 +08006
Krishyaf1d0ea82025-05-03 17:01:58 +08007const FriendMoments = () => {
8 const [feeds, setFeeds] = useState([]);
9 const [filteredFeeds, setFilteredFeeds] = useState([]);
10 const [query, setQuery] = useState('');
Krishya8f2fec82025-06-04 21:54:46 +080011 const [userId, setUserId] = useState(456); // 从状态管理或登录信息获取
Krishyaf1d0ea82025-05-03 17:01:58 +080012
13 // Modal state & form fields
14 const [showModal, setShowModal] = useState(false);
15 const [title, setTitle] = useState('');
16 const [content, setContent] = useState('');
Krishya8f2fec82025-06-04 21:54:46 +080017 const [selectedImages, setSelectedImages] = useState([]);
18 const [previewUrls, setPreviewUrls] = useState([]); // 新增:图片预览URLs
Krishyaf1d0ea82025-05-03 17:01:58 +080019
20 // 拉取好友动态列表
21 const fetchFeeds = async () => {
22 try {
Krishya8f2fec82025-06-04 21:54:46 +080023 // 修改为新的API路径
24 const res = await axios.get(`/echo/dynamic/${userId}/getAllDynamics`);
25 setFeeds(res.data.posts || []);
26 setFilteredFeeds(res.data.posts || []);
Krishyaf1d0ea82025-05-03 17:01:58 +080027 } catch (err) {
28 console.error('获取动态列表失败:', err);
Krishya8f2fec82025-06-04 21:54:46 +080029 alert('获取动态列表失败,请稍后重试');
Krishyaf1d0ea82025-05-03 17:01:58 +080030 }
31 };
32
33 useEffect(() => {
34 fetchFeeds();
Krishya8f2fec82025-06-04 21:54:46 +080035 }, [userId]);
Krishyaf1d0ea82025-05-03 17:01:58 +080036
37 // 搜索处理
38 const handleSearch = () => {
39 const q = query.trim().toLowerCase();
Krishya8f2fec82025-06-04 21:54:46 +080040 if (!q) {
41 setFilteredFeeds(feeds);
42 return;
43 }
Krishyaf1d0ea82025-05-03 17:01:58 +080044 setFilteredFeeds(
Krishya8f2fec82025-06-04 21:54:46 +080045 feeds.filter(f =>
46 (f.title || '').toLowerCase().includes(q) ||
47 (f.postContent || '').toLowerCase().includes(q)
48 )
Krishyaf1d0ea82025-05-03 17:01:58 +080049 );
50 };
Krishya8f2fec82025-06-04 21:54:46 +080051
Krishyaf1d0ea82025-05-03 17:01:58 +080052 const handleReset = () => {
53 setQuery('');
54 setFilteredFeeds(feeds);
55 };
56
Krishya8f2fec82025-06-04 21:54:46 +080057 // 对话框内:处理图片选择
58 const handleImageChange = (e) => {
Krishyaf1d0ea82025-05-03 17:01:58 +080059 const files = Array.from(e.target.files);
60 if (!files.length) return;
Krishya8f2fec82025-06-04 21:54:46 +080061
62 // 生成预览URLs
63 const previewUrls = files.map(file => URL.createObjectURL(file));
64
65 setSelectedImages(files);
66 setPreviewUrls(previewUrls); // 更新预览URLs
Krishyaf1d0ea82025-05-03 17:01:58 +080067 };
68
69 // 对话框内:提交新动态
70 const handleSubmit = async () => {
71 if (!content.trim()) {
72 alert('内容不能为空');
73 return;
74 }
Krishya8f2fec82025-06-04 21:54:46 +080075
Krishyaf1d0ea82025-05-03 17:01:58 +080076 try {
Krishya8f2fec82025-06-04 21:54:46 +080077 const formData = new FormData();
78 formData.append('user_id', userId);
79 formData.append('title', title.trim() || '');
80 formData.append('content', content.trim());
81
82 // 添加图片文件
83 selectedImages.forEach((file, index) => {
84 formData.append('image_url', file);
85 });
86
87 // 修改为新的API路径
88 await axios.post(`/echo/dynamic/${userId}/createDynamic`, formData, {
89 headers: {
90 'Content-Type': 'multipart/form-data'
91 }
92 });
93
Krishyaf1d0ea82025-05-03 17:01:58 +080094 // 重置表单
95 setTitle('');
96 setContent('');
Krishya8f2fec82025-06-04 21:54:46 +080097 setSelectedImages([]);
98 setPreviewUrls([]); // 重置预览URLs
Krishyaf1d0ea82025-05-03 17:01:58 +080099 setShowModal(false);
100 fetchFeeds();
Krishya8f2fec82025-06-04 21:54:46 +0800101 alert('发布成功');
Krishyaf1d0ea82025-05-03 17:01:58 +0800102 } catch (err) {
103 console.error('发布失败', err);
104 alert('发布失败,请稍后重试');
105 }
106 };
107
108 // 删除动态
Krishya8f2fec82025-06-04 21:54:46 +0800109 const handleDelete = async (dynamicId) => {
Krishyaf1d0ea82025-05-03 17:01:58 +0800110 if (!window.confirm('确定要删除这条动态吗?')) return;
111 try {
Krishya8f2fec82025-06-04 21:54:46 +0800112 // 修改为新的API路径
113 await axios.delete(`/echo/dynamic/me/deleteDynamic/${dynamicId}`);
Krishyaf1d0ea82025-05-03 17:01:58 +0800114 fetchFeeds();
Krishya8f2fec82025-06-04 21:54:46 +0800115 alert('删除成功');
Krishyaf1d0ea82025-05-03 17:01:58 +0800116 } catch (err) {
117 console.error('删除失败', err);
Krishya8f2fec82025-06-04 21:54:46 +0800118 alert('删除失败,请稍后重试');
119 }
120 };
121
122 // 点赞动态
123 const handleLike = async (dynamicId) => {
124 try {
125 // 调用新的点赞API
126 const res = await axios.post(`/echo/dynamic/like`, {
127 userId,
128 dynamicId
129 });
130
131 if (res.status === 200) {
132 // 更新本地状态
133 setFeeds(feeds.map(feed => {
134 if (feed.postNo === dynamicId) {
135 return {
136 ...feed,
137 postLikeNum: (feed.postLikeNum || 0) + 1,
138 liked: true
139 };
140 }
141 return feed;
142 }));
143 } else {
144 alert(res.data.message || '点赞失败');
145 }
146 } catch (err) {
147 console.error('点赞失败', err);
148 alert('点赞失败,请稍后重试');
149 }
150 };
151
152 // 取消点赞
153 const handleUnlike = async (dynamicId) => {
154 try {
155 // 调用新的取消点赞API
156 const res = await axios.delete(`/echo/dynamic/unlike`, {
157 data: { userId, dynamicId }
158 });
159
160 if (res.status === 200) {
161 // 更新本地状态
162 setFeeds(feeds.map(feed => {
163 if (feed.postNo === dynamicId) {
164 return {
165 ...feed,
166 postLikeNum: Math.max(0, (feed.postLikeNum || 0) - 1),
167 liked: false
168 };
169 }
170 return feed;
171 }));
172 } else {
173 alert(res.data.message || '取消点赞失败');
174 }
175 } catch (err) {
176 console.error('取消点赞失败', err);
177 alert('取消点赞失败,请稍后重试');
Krishyaf1d0ea82025-05-03 17:01:58 +0800178 }
179 };
180
181 return (
182 <div className="friend-moments-container">
183 <Header />
184 <div className="fm-header">
185 <button className="create-btn" onClick={() => setShowModal(true)}>
186 <Edit theme="outline" size="18" style={{ marginRight: '6px' }} />
187 创建动态
188 </button>
189 <div className="f-search-bar">
190 <input
191 className="search-input"
192 type="text"
193 value={query}
194 onChange={e => setQuery(e.target.value)}
195 placeholder="输入要搜索的动态"
196 />
197 <button className="search-btn" onClick={handleSearch}>搜索</button>
198 <button className="search-btn" onClick={handleReset}>重置</button>
199 </div>
200 </div>
201
202 <div className="feed-list">
203 {filteredFeeds.map(feed => (
Krishya8f2fec82025-06-04 21:54:46 +0800204 <div className="feed-item" key={feed.postNo}>
Krishyaf1d0ea82025-05-03 17:01:58 +0800205 {feed.title && <h4>{feed.title}</h4>}
Krishya8f2fec82025-06-04 21:54:46 +0800206 <p>{feed.postContent}</p>
Krishyaf1d0ea82025-05-03 17:01:58 +0800207
Krishya8f2fec82025-06-04 21:54:46 +0800208 {feed.imageUrl && feed.imageUrl.split(',').length > 0 && (
Krishyaf1d0ea82025-05-03 17:01:58 +0800209 <div className="feed-images">
Krishya8f2fec82025-06-04 21:54:46 +0800210 {feed.imageUrl.split(',').map((url, i) => (
Krishyaf1d0ea82025-05-03 17:01:58 +0800211 <img key={i} src={url} alt={`动态图${i}`} />
212 ))}
213 </div>
214 )}
215
216 <div className="feed-footer">
217 <span className="feed-date">
Krishya8f2fec82025-06-04 21:54:46 +0800218 {new Date(feed.postTime).toLocaleString()}
Krishyaf1d0ea82025-05-03 17:01:58 +0800219 </span>
Krishya8f2fec82025-06-04 21:54:46 +0800220 <div className="like-container">
221 {feed.liked ? (
222 <button className="unlike-btn" onClick={() => handleUnlike(feed.postNo)}>
223 已点赞 ({feed.postLikeNum || 0})
224 </button>
225 ) : (
226 <button className="like-btn" onClick={() => handleLike(feed.postNo)}>
227 点赞 ({feed.postLikeNum || 0})
228 </button>
229 )}
230 </div>
231 {feed.user_id === userId && (
232 <button className="delete-btn" onClick={() => handleDelete(feed.postNo)}>
Krishyaf1d0ea82025-05-03 17:01:58 +0800233 删除
234 </button>
235 )}
236 </div>
237 </div>
238 ))}
239 </div>
240
241 {/* Modal 对话框 */}
242 {showModal && (
243 <div className="modal-overlay" onClick={() => setShowModal(false)}>
244 <div className="modal-dialog" onClick={e => e.stopPropagation()}>
245 <h3>发布新动态</h3>
246 <input
247 type="text"
248 placeholder="标题"
249 value={title}
250 onChange={e => setTitle(e.target.value)}
251 />
252 <textarea
253 placeholder="写下你的内容..."
254 value={content}
255 onChange={e => setContent(e.target.value)}
256 />
Krishyaf1d0ea82025-05-03 17:01:58 +0800257 <label className="file-label">
258 选择图片
259 <input
260 type="file"
261 accept="image/*"
262 multiple
263 onChange={handleImageChange}
264 style={{ display: 'none' }}
265 />
266 </label>
267 <div className="cf-preview">
Krishya8f2fec82025-06-04 21:54:46 +0800268 {previewUrls.map((url, i) => ( // 使用定义的previewUrls
Krishyaf1d0ea82025-05-03 17:01:58 +0800269 <img key={i} src={url} alt={`预览${i}`} />
270 ))}
271 </div>
272 <div className="modal-actions">
273 <button className="btn cancel" onClick={() => setShowModal(false)}>
274 取消
275 </button>
276 <button className="btn submit" onClick={handleSubmit}>
277 发布
278 </button>
279 </div>
280 </div>
281 </div>
282 )}
283 </div>
284 );
285};
286
Krishya8f2fec82025-06-04 21:54:46 +0800287export default FriendMoments;