blob: 5c0ce2655c27afd2a52a7a571b8a8b99ce2eb7a0 [file] [log] [blame]
ym923bfa214f2025-06-09 18:10:32 +08001import React, { useEffect, useState } from 'react';
2import {
3 Table, Button, Modal, Image, message, Tag,
4 Space, Input, Tooltip, Form, Upload
5} from 'antd';
6import {
7 ExclamationCircleOutlined, SearchOutlined, UploadOutlined
8} from '@ant-design/icons';
9import {
10 getAllActivities,
11 searchActivitiesByTitle,
12 deleteActivity,
13 createActivity,
14 updateActivity
15} from '../api/activity';
16
17const { confirm } = Modal;
18
19const ActivityAdminPanel = () => {
20 const [activities, setActivities] = useState([]);
21 const [loading, setLoading] = useState(false);
22 const [keyword, setKeyword] = useState('');
23 const [modalVisible, setModalVisible] = useState(false);
24 const [editMode, setEditMode] = useState(false);
25 const [currentActivity, setCurrentActivity] = useState(null);
26 const [form] = Form.useForm();
27
28 const fetchActivities = async () => {
29 setLoading(true);
30 try {
31 const data = keyword.trim()
32 ? await searchActivitiesByTitle(keyword.trim())
33 : await getAllActivities();
34 setActivities(data.data || []);
35 } catch (error) {
36 message.error('获取公告失败');
37 } finally {
38 setLoading(false);
39 }
40 };
41
42 useEffect(() => {
43 fetchActivities();
44 }, []);
45
46 const handleSearch = () => {
47 fetchActivities();
48 };
49
50 const handleDelete = (activityid) => {
51 confirm({
52 title: '确认删除该公告吗?',
53 icon: <ExclamationCircleOutlined />,
54 okText: '删除',
55 okType: 'danger',
56 cancelText: '取消',
57 onOk: async () => {
58 try {
59 const res = await deleteActivity(activityid);
60 if (res.data === true) {
61 message.success('删除成功');
62 fetchActivities();
63 } else {
64 message.error('删除失败');
65 }
66 } catch {
67 message.error('删除请求失败');
68 }
69 },
70 });
71 };
72
73 const openEditModal = (record) => {
74 setEditMode(true);
75 setCurrentActivity(record);
76 form.setFieldsValue({
77 activityid: record.activityid,
78 title: record.title,
79 content: record.content,
80 isShow: record.is_show,
81 });
82 setModalVisible(true);
83 };
84
85 const openCreateModal = () => {
86 setEditMode(false);
87 form.resetFields();
88 setModalVisible(true);
89 };
90
91 const handleModalOk = async () => {
92 try {
93 const values = await form.validateFields();
94 const formData = new FormData();
95 Object.keys(values).forEach(key => {
96 if (key !== 'photo' && values[key] !== undefined) {
97 formData.append(key, values[key]);
98 }
99 });
100 if (values.photo && values.photo.file) {
101 formData.append('photo', values.photo.file);
102 }
103
104 const res = editMode
105 ? await updateActivity(formData)
106 : await createActivity(formData);
107
108 if (res.data === true) {
109 message.success(editMode ? '修改成功' : '创建成功');
110 setModalVisible(false);
111 fetchActivities();
112 } else {
113 message.error('提交失败');
114 }
115 } catch (error) {
116 message.error('提交失败,请检查表单');
117 }
118 };
119
120 const columns = [
121 {
122 title: 'ID',
123 dataIndex: 'activityid',
124 key: 'activityid',
125 width: 80,
126 },
127 {
128 title: '标题',
129 dataIndex: 'title',
130 key: 'title',
131 width: 200,
132 ellipsis: true,
133 },
134 {
135 title: '内容',
136 dataIndex: 'content',
137 key: 'content',
138 ellipsis: { showTitle: false },
139 render: (text) => (
140 <Tooltip placement="topLeft" title={text}>
141 {text}
142 </Tooltip>
143 ),
144 },
145 {
146 title: '图片',
147 dataIndex: 'photo',
148 key: 'photo',
149 width: 100,
150 render: (url) =>
151 url ? (
152 <Image
153 src={`http://localhost:8080${url}`}
154 width={80}
155 height={80}
156 style={{ objectFit: 'cover' }}
157 />
158 ) : (
159 <Tag color="default">无</Tag>
160 ),
161 },
162 {
163 title: '展示状态',
164 dataIndex: 'is_show',
165 key: 'is_show',
166 width: 100,
167 render: (val) =>
168 val === 0 ? <Tag color="green">展示</Tag> : <Tag color="red">隐藏</Tag>,
169 },
170 {
171 title: '发布时间',
172 dataIndex: 'time',
173 key: 'time',
174 width: 180,
175 render: (time) =>
176 time ? new Date(time).toLocaleString() : <Tag color="default">暂无</Tag>,
177 },
178 {
179 title: '操作',
180 key: 'action',
181 width: 180,
182 render: (_, record) => (
183 <Space size="middle">
184 <Button type="primary" onClick={() => openEditModal(record)}>
185 修改
186 </Button>
187 <Button danger onClick={() => handleDelete(record.activityid)}>
188 删除
189 </Button>
190 </Space>
191 ),
192 },
193 ];
194
195 return (
196 <div style={{ padding: 20 }}>
197 <h2 style={{ marginBottom: 20 }}>公告管理面板</h2>
198 <Space style={{ marginBottom: 16 }}>
199 <Input
200 placeholder="请输入标题关键词"
201 value={keyword}
202 onChange={(e) => setKeyword(e.target.value)}
203 style={{ width: 300 }}
204 />
205 <Button type="primary" icon={<SearchOutlined />} onClick={handleSearch}>
206 搜索
207 </Button>
208 <Button onClick={() => { setKeyword(''); fetchActivities(); }}>
209 重置
210 </Button>
211 <Button type="primary" onClick={openCreateModal}>
212 新建公告
213 </Button>
214 </Space>
215 <Table
216 rowKey="activityid"
217 columns={columns}
218 dataSource={activities}
219 loading={loading}
220 scroll={{ x: 1200 }}
221 pagination={{ pageSize: 8 }}
222 bordered
223 size="middle"
224 />
225
226 <Modal
227 title={editMode ? '修改公告' : '新建公告'}
228 open={modalVisible}
229 onOk={handleModalOk}
230 onCancel={() => setModalVisible(false)}
231 okText="提交"
232 cancelText="取消"
233 destroyOnClose
234 >
235 <Form form={form} layout="vertical" preserve={false}>
236 {editMode && (
237 <Form.Item name="activityid" hidden>
238 <Input />
239 </Form.Item>
240 )}
241 <Form.Item
242 name="title"
243 label="标题"
244 rules={[{ required: true, message: '请输入标题' }]}
245 >
246 <Input />
247 </Form.Item>
248 <Form.Item
249 name="content"
250 label="内容"
251 rules={[{ required: true, message: '请输入内容' }]}
252 >
253 <Input.TextArea rows={4} />
254 </Form.Item>
255 <Form.Item name="isShow" label="是否展示">
256 <Input placeholder="0 表示展示,1 表示隐藏" />
257 </Form.Item>
258 <Form.Item name="photo" label="上传图片">
259 <Upload beforeUpload={() => false} maxCount={1}>
260 <Button icon={<UploadOutlined />}>选择文件</Button>
261 </Upload>
262 </Form.Item>
263 </Form>
264 </Modal>
265 </div>
266 );
267};
268
269export default ActivityAdminPanel;