Merge "管理员端用户管理"
diff --git a/src/components/UserManagement.jsx b/src/components/UserManagement.jsx
new file mode 100644
index 0000000..c0ede42
--- /dev/null
+++ b/src/components/UserManagement.jsx
@@ -0,0 +1,418 @@
+import React, { useState, useEffect } from 'react';
+import { 
+  Table, 
+  Button, 
+  Modal, 
+  Image, 
+  message, 
+  Spin, 
+  Input, 
+  Select,
+  Pagination,
+  Space
+} from 'antd';
+import { ExclamationCircleOutlined } from '@ant-design/icons';
+import axios from 'axios';
+
+const { confirm } = Modal;
+const { Option } = Select;
+
+const UserManagement = () => {
+  // 状态管理
+  const [users, setUsers] = useState([]);
+  const [isLoading, setIsLoading] = useState(false);
+  const [error, setError] = useState(null);
+  const [currentUserId, setCurrentUserId] = useState(null);
+  const [applyExamLoading, setApplyExamLoading] = useState(false);
+  const [searchKeyword, setSearchKeyword] = useState('');
+  const [currentPage, setCurrentPage] = useState(1);
+  const [pageSize, setPageSize] = useState(10);
+
+  // 获取当前用户ID
+  useEffect(() => {
+    const userId = 1; // 示例,实际从认证系统获取
+    setCurrentUserId(userId ? parseInt(userId) : null);
+  }, []);
+
+  // 获取所有用户数据
+  useEffect(() => {
+    fetchAllUsers();
+  }, [searchKeyword]);
+
+  // 获取所有用户的函数
+  const fetchAllUsers = async () => {
+    setIsLoading(true);
+    setError(null);
+    try {
+      const res = await axios.get('http://localhost:8080/user/alluser');
+      setUsers(res.data.data);
+      setCurrentPage(1); // 重置为第一页
+    } catch (err) {
+      console.error('获取用户失败', err);
+      setError('获取用户列表失败,请稍后重试');
+      message.error('获取用户列表失败');
+    } finally {
+      setIsLoading(false);
+    }
+  };
+  console.log('当前用户列表:', users);
+
+  // 删除用户
+  const handleDeleteUser = async (username) => {
+    confirm({
+      title: '确认删除',
+      icon: <ExclamationCircleOutlined />,
+      content: '确定要删除这个用户吗?此操作不可恢复!',
+      onOk: async () => {
+        try {
+          await axios.delete(`http://localhost:8080/user/DeleteUser`, {
+            params: { username: username }
+          });
+          setUsers(users.filter(user => user.username !== username));
+          message.success('用户删除成功');
+        } catch (err) {
+          console.error('用户删除失败', err);
+          if (err.response && err.response.status === 403) {
+            message.error('无权删除此用户');
+          } else {
+            message.error('删除用户失败');
+          }
+        }
+      }
+    });
+  };
+
+  // 搜索种子
+  const handleSearch = async () => {
+    if (!searchKeyword.trim()) {
+      fetchAllUsers();
+      return;
+    }
+
+    setIsLoading(true);
+    setError(null);
+    try {
+      const res = await axios.get(`http://localhost:8080/user/finduser`, {
+        params: { keyword: searchKeyword },
+      });
+      setUsers(res.data.data);
+      setCurrentPage(1); // 搜索后重置为第一页
+    } catch (err) {
+      console.error('搜索失败', err);
+      setError('搜索失败,请稍后重试');
+      message.error('搜索失败');
+    } finally {
+      setIsLoading(false);
+    }
+  };
+
+  // 月度下载量考核
+  const handleMonthExam = async () => {
+    if (!currentUserId) {
+      message.warning('请先登录');
+      return;
+    }
+    
+    setApplyExamLoading(true);
+    try {
+      const now = new Date();
+      const year = now.getFullYear();
+      const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始,补零
+      const day = String(now.getDate()).padStart(2, '0');        // 日期补零
+      const formattedDate = `${year}-${month}-${day}`;
+
+      const currentDate = new Date();
+        const lastMonthDate = new Date(
+            currentDate.getFullYear(),
+            currentDate.getMonth() - 1,  // 月份减1
+            currentDate.getDate()       // 保持相同的日
+        );
+
+        if (lastMonthDate.getDate() !== currentDate.getDate()) {
+            lastMonthDate.setDate(0); // 设置为上个月的最后一天
+        }
+        const year1 = lastMonthDate.getFullYear();
+        const month1 = String(lastMonthDate.getMonth() + 1).padStart(2, '0');
+        const day1 = String(lastMonthDate.getDate()).padStart(2, '0');
+        const formattedDate1 = `${year1}-${month1}-${day1}`;
+
+
+
+      const res = await axios.post('http://localhost:8080/exam/MonthDownload', null, {
+        params: { startDate: formattedDate1,endDate: formattedDate }
+      });
+      
+      if (res.data.success) {
+        message.success(res.data.message);
+        fetchAllUsers(); // 刷新种子列表
+      }
+    } catch (err) {
+      console.error('月度考核失败', err);
+      if (err.response && err.response.status === 403) {
+        message.error('无权执行此操作');
+      } else {
+        message.error('月度考核失败');
+      }
+    } finally {
+      setApplyExamLoading(false);
+    }
+  };
+
+  // 季度上传量考核
+  const handleQuarterExam = async () => {
+    if (!currentUserId) {
+      message.warning('请先登录');
+      return;
+    }
+    
+    setApplyExamLoading(true);
+    try {
+      const now = new Date();
+      const year = now.getFullYear();
+      const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始,补零
+      const day = String(now.getDate()).padStart(2, '0');        // 日期补零
+      const formattedDate = `${year}-${month}-${day}`;
+
+      const currentDate = new Date();
+
+        const lastMonthDate = new Date(
+            currentDate.getFullYear(),
+            currentDate.getMonth() - 3,  // 月份减1
+            currentDate.getDate()       // 保持相同的日
+        );
+
+        if (lastMonthDate.getDate() !== currentDate.getDate()) {
+            lastMonthDate.setDate(0); // 设置为上个月的最后一天
+        }
+        const year1 = lastMonthDate.getFullYear();
+        const month1 = String(lastMonthDate.getMonth() + 1).padStart(2, '0');
+        const day1 = String(lastMonthDate.getDate()).padStart(2, '0');
+        const formattedDate1 = `${year1}-${month1}-${day1}`;
+
+
+
+      const res = await axios.post('http://localhost:8080/exam/QuarterUpload', null, {
+        params: { startDate: formattedDate1,endDate: formattedDate }
+      });
+      
+      if (res.data.success) {
+        message.success(res.data.message);
+        fetchAllUsers(); // 刷新种子列表
+      }
+    } catch (err) {
+      console.error('季度考核失败', err);
+      if (err.response && err.response.status === 403) {
+        message.error('无权执行此操作');
+      } else {
+        message.error('月度考核失败');
+      }
+    } finally {
+      setApplyExamLoading(false);
+    }
+  };
+
+  // 分页数据计算
+  const getCurrentPageData = () => {
+    const start = (currentPage - 1) * pageSize;
+    const end = start + pageSize;
+    return users;//.slice(start, end);
+  };
+
+  // 页码变化处理
+  const handlePageChange = (page) => {
+    setCurrentPage(page);
+  };
+
+  // 每页条数变化处理
+  const handlePageSizeChange = (current, size) => {
+    setPageSize(size);
+    setCurrentPage(1); // 重置为第一页
+  };
+
+  // 格式化文件大小
+  const formatFileSize = (bytes) => {
+    if (bytes === 0) return '0 Bytes';
+    const k = 1024;
+    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
+    const i = Math.floor(Math.log(bytes) / Math.log(k));
+    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
+  };
+
+  ////////////////////////////////////////////////////////////////////////////
+  return (
+    <div className="p-4 max-w-7xl mx-auto">
+      <h1 className="text-2xl font-bold mb-6">用户管理</h1>
+
+      {/* 搜索框 */}
+      <div className="mb-4 flex items-center">
+        <Input
+          placeholder="搜索用户..."
+          value={searchKeyword}
+          onChange={(e) => setSearchKeyword(e.target.value)}
+          style={{ width: 300 }}
+          onPressEnter={handleSearch}
+        />
+        <Button 
+          type="primary" 
+          onClick={handleSearch}
+          style={{ marginLeft: 8 }}
+        >
+          搜索
+        </Button>
+      </div>
+
+      {/* 右上角按钮 */}
+      <Space>
+        <Button
+            type="primary"
+            loading={applyExamLoading}
+            onClick={handleMonthExam}
+        >
+            月度下载量检查
+        </Button>
+        <Button
+            type="primary"
+            loading={applyExamLoading}
+            onClick={handleQuarterExam}
+        >
+            季度上传量检查
+        </Button>
+    </Space>
+
+      {/* 加载状态 */}
+      {isLoading && <Spin size="large" style={{ display: 'block', margin: '100px auto' }} />}
+
+      {/* 错误提示 */}
+      {error && <div className="mb-4 p-3 bg-red-100 text-red-700 rounded border border-red-200">{error}</div>}
+
+      {/* 种子列表表格 */}
+      {!isLoading && !error && (
+        <>
+          <Table
+            columns={[
+              {
+                title: '用户名',
+                dataIndex: 'username',
+                key: 'username'
+              },
+              {
+                title: '密码',
+                dataIndex: 'password',
+                key: 'password'
+              },
+              {
+                title: '上传量',
+                dataIndex: 'user_upload',
+                key: 'user_upload',
+                render: (size) => formatFileSize(size)
+              },
+              {
+                title: '下载量',
+                dataIndex: 'user_download',
+                key: 'user_download',
+                render: (size) => formatFileSize(size)
+              },
+              {
+                title: '保种积分',
+                dataIndex: 'credit',
+                key: 'credit',
+              },
+              {
+                              title: '头像',
+                              dataIndex: 'image',
+                              key: 'image',
+                              render: (text) => text ? (
+                                <Image 
+                                  src={text} 
+                                  width={50} 
+                                  height={50} 
+                                  preview={{ maskClosable: true }}
+                                />
+                              ) : (
+                                <div className="w-16 h-16 bg-gray-200 flex items-center justify-center">无头像</div>
+                              )
+                            },
+              {
+                title: '性别',
+                dataIndex: 'sex',
+                key: 'sex',
+              },
+              {
+                title: '用户id',
+                dataIndex: 'userid',
+                key: 'userid'
+              },
+              {
+                title: '用户等级',
+                dataIndex: 'grade_id',
+                key: 'grade_id'
+              },
+              {
+                title: 'passkey',
+                dataIndex: 'passkey',
+                key: 'passkey'
+              },
+              {
+                title: '分享率',
+                dataIndex: 'ratio',
+                key: 'ratio'
+              },
+              {
+                title: '年龄',
+                dataIndex: 'age',
+                key: 'age'
+              },
+              {
+                title: '邮箱',
+                dataIndex: 'email',
+                key: 'email'
+              },
+              {
+                title: '用户权限',
+                dataIndex: 'permission',
+                key: 'permission'
+              },
+              {
+                title: '操作',
+                key: 'action',
+                render: (_, record) => (
+                  <Space>
+                    <Button 
+                      danger 
+                      onClick={() => handleDeleteUser(record.username)}
+                      loading={isLoading}
+                    >
+                      删除
+                    </Button>
+                  </Space>
+                )
+              }
+            ]}
+            dataSource={getCurrentPageData()}
+            rowKey="userid"
+            pagination={false}
+            loading={isLoading}
+          />
+
+          {/* 分页控件 */}
+          {users.length > 0 && (
+            <div style={{ marginTop: 16, textAlign: 'center' }}>
+              <Pagination
+                current={currentPage}
+                pageSize={pageSize}
+                total={users.length}
+                onChange={handlePageChange}
+                onShowSizeChange={handlePageSizeChange}
+                showSizeChanger
+                showTotal={(total) => `共 ${total} 条记录`}
+                pageSizeOptions={['10', '20', '50']}
+              />
+            </div>
+          )}
+        </>
+      )}
+    </div>
+  );
+};
+
+export default UserManagement;
\ No newline at end of file