blob: a01df086b47f09e6354a0834eda68b123dc58fad [file] [log] [blame]
ym9234558e9f2025-06-09 20:16:16 +08001import React, { useEffect, useState } from 'react';
2import {
3 Table,
4 Button,
5 Modal,
6 Image,
7 message,
8 Tag,
9 Space,
10 Input,
11 Tooltip,
12} from 'antd';
13import { ExclamationCircleOutlined, SearchOutlined } from '@ant-design/icons';
14import {
15 getAllPostsSorted,
16 searchPosts,
17 deletePost,
18 togglePinPost,
19} from '../api/post';
20
21const { confirm } = Modal;
22
23const PostAdminPanel = () => {
24 const [posts, setPosts] = useState([]);
25 const [loading, setLoading] = useState(false);
26 const [keyword, setKeyword] = useState('');
27
28 const fetchPosts = async () => {
29 setLoading(true);
30 try {
31 const data = keyword.trim()
32 ? await searchPosts(keyword.trim())
33 : await getAllPostsSorted();
34 setPosts(data);
35 } catch (error) {
36 message.error('获取帖子失败');
37 } finally {
38 setLoading(false);
39 }
40 };
41
42 useEffect(() => {
43 fetchPosts();
44 }, []);
45
46 const handleSearch = () => {
47 fetchPosts();
48 };
49
50 const handleDelete = (postid) => {
51 confirm({
52 title: '确认删除该帖子吗?',
53 icon: <ExclamationCircleOutlined />,
54 okText: '删除',
55 okType: 'danger',
56 cancelText: '取消',
57 onOk: async () => {
58 try {
59 const res = await deletePost(postid);
60 if (res) {
61 message.success('删除成功');
62 fetchPosts();
63 } else {
64 message.error('删除失败');
65 }
66 } catch {
67 message.error('删除请求失败');
68 }
69 },
70 });
71 };
72
73 const handlePinToggle = async (postid) => {
74 try {
75 const res = await togglePinPost(postid);
76 if (res === true || res === false) {
77 // ✅ 用后端返回的状态更新 UI
78 const newPosts = posts.map(post => {
79 if (post.postid === postid) {
80 return {
81 ...post,
82 is_pinned: res ? 1 : 0,
83 };
84 }
85 return post;
86 });
87 setPosts(newPosts);
88 message.success(`帖子${res ? '已置顶' : '已取消置顶'}`);
89 } else {
90 message.error('更新失败');
91 }
92 } catch {
93 message.error('更新置顶状态失败');
94 }
95 };
96
97
98
99
100 const columns = [
101 {
102 title: 'ID',
103 dataIndex: 'postid',
104 key: 'postid',
105 width: 80,
106 fixed: 'left',
107 },
108 {
109 title: '用户ID',
110 dataIndex: 'userid',
111 key: 'userid',
112 width: 100,
113 },
114 {
115 title: '标题',
116 dataIndex: 'postTitle',
117 key: 'postTitle',
118 width: 200,
119 ellipsis: true,
120 },
121 {
122 title: '内容',
123 dataIndex: 'postContent',
124 key: 'postContent',
125 ellipsis: { showTitle: false },
126 render: (text) => (
127 <Tooltip placement="topLeft" title={text}>
128 {text}
129 </Tooltip>
130 ),
131 },
132 {
133 title: '标签',
134 dataIndex: 'tags',
135 key: 'tags',
136 render: (tags) =>
137 tags ? tags.split(',').map((tag) => <Tag key={tag}>{tag}</Tag>) : <Tag color="default">无</Tag>,
138 },
139 {
140 title: '图片',
141 dataIndex: 'photo',
142 key: 'photo',
143 width: 100,
144 render: (url) =>
145 url ? (
146 <Image
147 src={`http://localhost:8080${url}`}
148 width={80}
149 height={80}
150 style={{ objectFit: 'cover' }}
151 />
152 ) : (
153 <Tag color="default">无</Tag>
154 ),
155 },
156 {
157 title: '点赞数',
158 dataIndex: 'likes',
159 key: 'likes',
160 width: 100,
161 render: (likes) => <Tag color="blue">{likes}</Tag>,
162 },
163 {
164 title: '置顶状态',
165 dataIndex: 'is_pinned',
166 key: 'is_pinned',
167 width: 100,
168 render: (val) =>
169 val ? <Tag color="green">已置顶</Tag> : <Tag color="default">未置顶</Tag>,
170 },
171 {
172 title: '发布时间',
173 dataIndex: 'postCreatedTime',
174 key: 'postCreatedTime',
175 width: 180,
176 render: (time) =>
177 time ? new Date(time).toLocaleString() : <Tag color="default">暂无</Tag>,
178 },
179 {
180 title: '操作',
181 key: 'action',
182 width: 180,
183 fixed: 'right',
184 render: (_, record) => (
185 <Space size="middle">
186 <Button
187 type="primary"
188 onClick={() => handlePinToggle(record.postid, record.is_pinned)}
189 >
190 {Boolean(record.is_pinned) ? '取消置顶' : '置顶'}
191 </Button>
192
193 <Button danger onClick={() => handleDelete(record.postid)}>
194 删除
195 </Button>
196 </Space>
197 ),
198 },
199 ];
200
201 return (
202 <div style={{ padding: 20 }}>
203 <h2 style={{ marginBottom: 20 }}>帖子管理面板</h2>
204 <Space style={{ marginBottom: 16 }}>
205 <Input
206 placeholder="请输入关键词"
207 value={keyword}
208 onChange={(e) => setKeyword(e.target.value)}
209 style={{ width: 300 }}
210 />
211 <Button type="primary" icon={<SearchOutlined />} onClick={handleSearch}>
212 搜索
213 </Button>
214 <Button onClick={() => { setKeyword(''); fetchPosts(); }}>
215 重置
216 </Button>
217 </Space>
218 <Table
219 rowKey="postid"
220 columns={columns}
221 dataSource={posts}
222 loading={loading}
223 scroll={{ x: 1600 }}
224 pagination={{ pageSize: 10 }}
225 bordered
226 size="middle"
227 />
228 </div>
229 );
230};
231
232export default PostAdminPanel;