blob: c0ede42477dac7b0195d9ca3d31a0141cffd1fcf [file] [log] [blame]
2130105043969c92025-06-09 23:15:40 +08001import React, { useState, useEffect } from 'react';
2import {
3 Table,
4 Button,
5 Modal,
6 Image,
7 message,
8 Spin,
9 Input,
10 Select,
11 Pagination,
12 Space
13} from 'antd';
14import { ExclamationCircleOutlined } from '@ant-design/icons';
15import axios from 'axios';
16
17const { confirm } = Modal;
18const { Option } = Select;
19
20const UserManagement = () => {
21 // 状态管理
22 const [users, setUsers] = useState([]);
23 const [isLoading, setIsLoading] = useState(false);
24 const [error, setError] = useState(null);
25 const [currentUserId, setCurrentUserId] = useState(null);
26 const [applyExamLoading, setApplyExamLoading] = useState(false);
27 const [searchKeyword, setSearchKeyword] = useState('');
28 const [currentPage, setCurrentPage] = useState(1);
29 const [pageSize, setPageSize] = useState(10);
30
31 // 获取当前用户ID
32 useEffect(() => {
33 const userId = 1; // 示例,实际从认证系统获取
34 setCurrentUserId(userId ? parseInt(userId) : null);
35 }, []);
36
37 // 获取所有用户数据
38 useEffect(() => {
39 fetchAllUsers();
40 }, [searchKeyword]);
41
42 // 获取所有用户的函数
43 const fetchAllUsers = async () => {
44 setIsLoading(true);
45 setError(null);
46 try {
47 const res = await axios.get('http://localhost:8080/user/alluser');
48 setUsers(res.data.data);
49 setCurrentPage(1); // 重置为第一页
50 } catch (err) {
51 console.error('获取用户失败', err);
52 setError('获取用户列表失败,请稍后重试');
53 message.error('获取用户列表失败');
54 } finally {
55 setIsLoading(false);
56 }
57 };
58 console.log('当前用户列表:', users);
59
60 // 删除用户
61 const handleDeleteUser = async (username) => {
62 confirm({
63 title: '确认删除',
64 icon: <ExclamationCircleOutlined />,
65 content: '确定要删除这个用户吗?此操作不可恢复!',
66 onOk: async () => {
67 try {
68 await axios.delete(`http://localhost:8080/user/DeleteUser`, {
69 params: { username: username }
70 });
71 setUsers(users.filter(user => user.username !== username));
72 message.success('用户删除成功');
73 } catch (err) {
74 console.error('用户删除失败', err);
75 if (err.response && err.response.status === 403) {
76 message.error('无权删除此用户');
77 } else {
78 message.error('删除用户失败');
79 }
80 }
81 }
82 });
83 };
84
85 // 搜索种子
86 const handleSearch = async () => {
87 if (!searchKeyword.trim()) {
88 fetchAllUsers();
89 return;
90 }
91
92 setIsLoading(true);
93 setError(null);
94 try {
95 const res = await axios.get(`http://localhost:8080/user/finduser`, {
96 params: { keyword: searchKeyword },
97 });
98 setUsers(res.data.data);
99 setCurrentPage(1); // 搜索后重置为第一页
100 } catch (err) {
101 console.error('搜索失败', err);
102 setError('搜索失败,请稍后重试');
103 message.error('搜索失败');
104 } finally {
105 setIsLoading(false);
106 }
107 };
108
109 // 月度下载量考核
110 const handleMonthExam = async () => {
111 if (!currentUserId) {
112 message.warning('请先登录');
113 return;
114 }
115
116 setApplyExamLoading(true);
117 try {
118 const now = new Date();
119 const year = now.getFullYear();
120 const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始,补零
121 const day = String(now.getDate()).padStart(2, '0'); // 日期补零
122 const formattedDate = `${year}-${month}-${day}`;
123
124 const currentDate = new Date();
125 const lastMonthDate = new Date(
126 currentDate.getFullYear(),
127 currentDate.getMonth() - 1, // 月份减1
128 currentDate.getDate() // 保持相同的日
129 );
130
131 if (lastMonthDate.getDate() !== currentDate.getDate()) {
132 lastMonthDate.setDate(0); // 设置为上个月的最后一天
133 }
134 const year1 = lastMonthDate.getFullYear();
135 const month1 = String(lastMonthDate.getMonth() + 1).padStart(2, '0');
136 const day1 = String(lastMonthDate.getDate()).padStart(2, '0');
137 const formattedDate1 = `${year1}-${month1}-${day1}`;
138
139
140
141 const res = await axios.post('http://localhost:8080/exam/MonthDownload', null, {
142 params: { startDate: formattedDate1,endDate: formattedDate }
143 });
144
145 if (res.data.success) {
146 message.success(res.data.message);
147 fetchAllUsers(); // 刷新种子列表
148 }
149 } catch (err) {
150 console.error('月度考核失败', err);
151 if (err.response && err.response.status === 403) {
152 message.error('无权执行此操作');
153 } else {
154 message.error('月度考核失败');
155 }
156 } finally {
157 setApplyExamLoading(false);
158 }
159 };
160
161 // 季度上传量考核
162 const handleQuarterExam = async () => {
163 if (!currentUserId) {
164 message.warning('请先登录');
165 return;
166 }
167
168 setApplyExamLoading(true);
169 try {
170 const now = new Date();
171 const year = now.getFullYear();
172 const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始,补零
173 const day = String(now.getDate()).padStart(2, '0'); // 日期补零
174 const formattedDate = `${year}-${month}-${day}`;
175
176 const currentDate = new Date();
177
178 const lastMonthDate = new Date(
179 currentDate.getFullYear(),
180 currentDate.getMonth() - 3, // 月份减1
181 currentDate.getDate() // 保持相同的日
182 );
183
184 if (lastMonthDate.getDate() !== currentDate.getDate()) {
185 lastMonthDate.setDate(0); // 设置为上个月的最后一天
186 }
187 const year1 = lastMonthDate.getFullYear();
188 const month1 = String(lastMonthDate.getMonth() + 1).padStart(2, '0');
189 const day1 = String(lastMonthDate.getDate()).padStart(2, '0');
190 const formattedDate1 = `${year1}-${month1}-${day1}`;
191
192
193
194 const res = await axios.post('http://localhost:8080/exam/QuarterUpload', null, {
195 params: { startDate: formattedDate1,endDate: formattedDate }
196 });
197
198 if (res.data.success) {
199 message.success(res.data.message);
200 fetchAllUsers(); // 刷新种子列表
201 }
202 } catch (err) {
203 console.error('季度考核失败', err);
204 if (err.response && err.response.status === 403) {
205 message.error('无权执行此操作');
206 } else {
207 message.error('月度考核失败');
208 }
209 } finally {
210 setApplyExamLoading(false);
211 }
212 };
213
214 // 分页数据计算
215 const getCurrentPageData = () => {
216 const start = (currentPage - 1) * pageSize;
217 const end = start + pageSize;
218 return users;//.slice(start, end);
219 };
220
221 // 页码变化处理
222 const handlePageChange = (page) => {
223 setCurrentPage(page);
224 };
225
226 // 每页条数变化处理
227 const handlePageSizeChange = (current, size) => {
228 setPageSize(size);
229 setCurrentPage(1); // 重置为第一页
230 };
231
232 // 格式化文件大小
233 const formatFileSize = (bytes) => {
234 if (bytes === 0) return '0 Bytes';
235 const k = 1024;
236 const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
237 const i = Math.floor(Math.log(bytes) / Math.log(k));
238 return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
239 };
240
241 ////////////////////////////////////////////////////////////////////////////
242 return (
243 <div className="p-4 max-w-7xl mx-auto">
244 <h1 className="text-2xl font-bold mb-6">用户管理</h1>
245
246 {/* 搜索框 */}
247 <div className="mb-4 flex items-center">
248 <Input
249 placeholder="搜索用户..."
250 value={searchKeyword}
251 onChange={(e) => setSearchKeyword(e.target.value)}
252 style={{ width: 300 }}
253 onPressEnter={handleSearch}
254 />
255 <Button
256 type="primary"
257 onClick={handleSearch}
258 style={{ marginLeft: 8 }}
259 >
260 搜索
261 </Button>
262 </div>
263
264 {/* 右上角按钮 */}
265 <Space>
266 <Button
267 type="primary"
268 loading={applyExamLoading}
269 onClick={handleMonthExam}
270 >
271 月度下载量检查
272 </Button>
273 <Button
274 type="primary"
275 loading={applyExamLoading}
276 onClick={handleQuarterExam}
277 >
278 季度上传量检查
279 </Button>
280 </Space>
281
282 {/* 加载状态 */}
283 {isLoading && <Spin size="large" style={{ display: 'block', margin: '100px auto' }} />}
284
285 {/* 错误提示 */}
286 {error && <div className="mb-4 p-3 bg-red-100 text-red-700 rounded border border-red-200">{error}</div>}
287
288 {/* 种子列表表格 */}
289 {!isLoading && !error && (
290 <>
291 <Table
292 columns={[
293 {
294 title: '用户名',
295 dataIndex: 'username',
296 key: 'username'
297 },
298 {
299 title: '密码',
300 dataIndex: 'password',
301 key: 'password'
302 },
303 {
304 title: '上传量',
305 dataIndex: 'user_upload',
306 key: 'user_upload',
307 render: (size) => formatFileSize(size)
308 },
309 {
310 title: '下载量',
311 dataIndex: 'user_download',
312 key: 'user_download',
313 render: (size) => formatFileSize(size)
314 },
315 {
316 title: '保种积分',
317 dataIndex: 'credit',
318 key: 'credit',
319 },
320 {
321 title: '头像',
322 dataIndex: 'image',
323 key: 'image',
324 render: (text) => text ? (
325 <Image
326 src={text}
327 width={50}
328 height={50}
329 preview={{ maskClosable: true }}
330 />
331 ) : (
332 <div className="w-16 h-16 bg-gray-200 flex items-center justify-center">无头像</div>
333 )
334 },
335 {
336 title: '性别',
337 dataIndex: 'sex',
338 key: 'sex',
339 },
340 {
341 title: '用户id',
342 dataIndex: 'userid',
343 key: 'userid'
344 },
345 {
346 title: '用户等级',
347 dataIndex: 'grade_id',
348 key: 'grade_id'
349 },
350 {
351 title: 'passkey',
352 dataIndex: 'passkey',
353 key: 'passkey'
354 },
355 {
356 title: '分享率',
357 dataIndex: 'ratio',
358 key: 'ratio'
359 },
360 {
361 title: '年龄',
362 dataIndex: 'age',
363 key: 'age'
364 },
365 {
366 title: '邮箱',
367 dataIndex: 'email',
368 key: 'email'
369 },
370 {
371 title: '用户权限',
372 dataIndex: 'permission',
373 key: 'permission'
374 },
375 {
376 title: '操作',
377 key: 'action',
378 render: (_, record) => (
379 <Space>
380 <Button
381 danger
382 onClick={() => handleDeleteUser(record.username)}
383 loading={isLoading}
384 >
385 删除
386 </Button>
387 </Space>
388 )
389 }
390 ]}
391 dataSource={getCurrentPageData()}
392 rowKey="userid"
393 pagination={false}
394 loading={isLoading}
395 />
396
397 {/* 分页控件 */}
398 {users.length > 0 && (
399 <div style={{ marginTop: 16, textAlign: 'center' }}>
400 <Pagination
401 current={currentPage}
402 pageSize={pageSize}
403 total={users.length}
404 onChange={handlePageChange}
405 onShowSizeChange={handlePageSizeChange}
406 showSizeChanger
407 showTotal={(total) => `共 ${total} 条记录`}
408 pageSizeOptions={['10', '20', '50']}
409 />
410 </div>
411 )}
412 </>
413 )}
414 </div>
415 );
416};
417
418export default UserManagement;