blob: c6b2e69f47cf9ad7f82d1a5eaa10bc349e5203ec [file] [log] [blame] [edit]
import React, { useState, useEffect } from 'react';
import {
createPost,
findPinnedPosts,
likePost,
unlikePost,
searchPosts,
getAllPostsSorted,
findPostsByUserId,
} from '../api/post';
import Comment from './Comment';
import RequestBoard from './RequestBoard';
import './Post.css';
const Post = () => {
const [title, setTitle] = useState('');
const [content, setContent] = useState('');
const [tags, setTags] = useState('');
const [photo, setPhoto] = useState(null);
const [posts, setPosts] = useState([]);
const [searchKeyword, setSearchKeyword] = useState('');
const [imagePreview, setImagePreview] = useState(null);
const [showCreateForm, setShowCreateForm] = useState(false);
const [currentView, setCurrentView] = useState('posts');
const [currentUser, setCurrentUser] = useState(null);
const [userDecorations, setUserDecorations] = useState({});
useEffect(() => {
const storedUser = JSON.parse(localStorage.getItem('user'));
if (storedUser) setCurrentUser(storedUser);
}, []);
useEffect(() => {
loadPinnedPosts();
}, []);
useEffect(() => {
if (posts.length > 0) {
fetchUserDecorations(posts);
}
}, [posts]);
const fetchUserDecorations = async (posts) => {
const decorations = {};
await Promise.all(
posts.map(async (post) => {
if (!decorations[post.userid]) {
try {
const res = await fetch(`http://localhost:8080/user/getDecoration?userid=${post.userid}`);
const json = await res.json();
if (json.success) {
decorations[post.userid] = json.data;
}
} catch (error) {
console.error(`获取用户 ${post.userid} 的装饰信息失败`, error);
}
}
})
);
setUserDecorations(decorations);
};
const loadPinnedPosts = async () => {
const data = await findPinnedPosts();
setPosts(data);
setCurrentView('posts');
};
const loadAllPosts = async () => {
const data = await getAllPostsSorted();
setPosts(data);
setCurrentView('posts');
};
const loadMyPosts = async () => {
if (!currentUser) return;
const data = await findPostsByUserId(currentUser.userid);
setPosts(data);
setCurrentView('posts');
};
const handleCreate = async () => {
if (!currentUser) {
alert('请先登录再发帖');
return;
}
const formData = new FormData();
formData.append('userid', currentUser.userid);
formData.append('post_title', title);
formData.append('post_content', content);
formData.append('tags', tags);
formData.append('rannge', 'public');
if (photo) formData.append('photo', photo);
const success = await createPost(formData);
if (success) {
alert('帖子创建成功');
loadPinnedPosts();
setTitle('');
setContent('');
setTags('');
setPhoto(null);
setShowCreateForm(false);
} else {
alert('创建失败');
}
};
const handleLike = async (postid) => {
await likePost(postid);
loadPinnedPosts();
};
const handleUnlike = async (postid) => {
await unlikePost(postid);
loadPinnedPosts();
};
const handleSearch = async () => {
const result = await searchPosts(searchKeyword);
setPosts(result);
setCurrentView('posts');
};
const showRequestBoard = () => {
setCurrentView('requests');
};
return (
<div className="post-container">
<div className="post-actions">
<div className="action-group">
{currentUser && (
<button
className="post-button primary"
onClick={() => setShowCreateForm(!showCreateForm)}
>
{showCreateForm ? '收起发布表单' : '创建新帖子'}
</button>
)}
<input
type="text"
placeholder="搜索关键词"
value={searchKeyword}
onChange={(e) => setSearchKeyword(e.target.value)}
className="post-input"
/>
<button className="post-button primary-outline" onClick={handleSearch}>搜索</button>
</div>
<div className="action-group">
<button className="post-button primary-outline" onClick={loadPinnedPosts}>置顶帖子</button>
<button className="post-button primary-outline" onClick={loadAllPosts}>所有帖子</button>
{currentUser && (
<button className="post-button primary-outline" onClick={loadMyPosts}>我的帖子</button>
)}
<button className="post-button primary-outline" onClick={showRequestBoard}>需求帖子</button>
</div>
</div>
{showCreateForm && currentUser && currentView !== 'requests' && (
<div className="post-form-card">
<div className="post-form-user-info">
{currentUser.image ? (
<img
src={currentUser.image}
alt="头像"
className="post-form-user-avatar"
/>
) : (
<div className="post-form-user-avatar-placeholder">
<div className="avatar-initial">
{currentUser.username?.charAt(0) || 'U'}
</div>
</div>
)}
<div className="post-form-username">{currentUser.username}</div>
<div className="post-form-user-label">发布者</div>
</div>
<h2 className="post-form-title">发布新帖子</h2>
<input
type="text"
placeholder="标题"
value={title}
onChange={(e) => setTitle(e.target.value)}
className="post-input"
/>
<textarea
placeholder="内容"
value={content}
onChange={(e) => setContent(e.target.value)}
className="post-textarea"
/>
<input
type="text"
placeholder="标签(逗号分隔)"
value={tags}
onChange={(e) => setTags(e.target.value)}
className="post-input"
/>
<input
type="file"
onChange={(e) => setPhoto(e.target.files[0])}
className="post-file"
/>
<button className="post-button primary" onClick={handleCreate}>
发布
</button>
</div>
)}
{currentView === 'requests' ? (
<RequestBoard
currentUserId={currentUser?.userid}
onBack={() => setCurrentView('posts')}
/>
) : (
posts.length > 0 ? (
<div className="post-list">
{posts.map((post) => {
const decoration = userDecorations[post.userid] || {};
const avatar = decoration.image || '';
const username = decoration.username || '匿名用户';
return (
<div className="post-card" key={post.postid}>
<div className="post-author-info">
{avatar ? (
<img
src={avatar}
alt="头像"
className="post-author-avatar"
/>
) : (
<div className="post-author-avatar-placeholder">
<div className="avatar-initial">{username.charAt(0)}</div>
</div>
)}
<div className="post-author-details">
<div className="post-author-name">{username}</div>
<div className="post-meta">发布时间: {post.postCreatedTime}</div>
</div>
</div>
<div className="post-header">
<div className="post-info">
<h3 className="post-title">{post.postTitle}</h3>
<p className="post-content">{post.postContent}</p>
<div className="post-meta">标签: {post.tags || '无标签'}</div>
<div className="post-actions-inline">
<span>👍 {post.likes}</span>
<button className="post-link like" onClick={() => handleLike(post.postid)}>点赞</button>
<button className="post-link unlike" onClick={() => handleUnlike(post.postid)}>取消点赞</button>
</div>
</div>
{post.photo && (
<img
src={`http://localhost:8080${post.photo}`}
alt="post"
className="post-image"
onClick={() => setImagePreview(`http://localhost:8080${post.photo}`)}
/>
)}
</div>
<div className="post-comment">
<Comment postId={post.postid} currentUser={currentUser} />
</div>
</div>
);
})}
</div>
) : (
<div className="post-empty-state">
<p className="post-empty-message">暂无内容</p>
</div>
)
)}
{imagePreview && (
<div className="image-modal" onClick={() => setImagePreview(null)}>
<div className="image-modal-content" onClick={(e) => e.stopPropagation()}>
<img src={imagePreview} alt="preview" className="image-modal-img" />
<button className="image-modal-close" onClick={() => setImagePreview(null)}>×</button>
</div>
</div>
)}
</div>
);
};
export default Post;