feat(auth): 实现登录注册功能并重构 App 组件

- 新增登录和注册页面组件
- 实现用户认证和权限管理逻辑
- 重构 App 组件,使用 Router 和 AuthProvider
- 添加管理员面板和论坛页面组件

Change-Id: Iaa4502616970e75e3268537f73c75dac8f60e24d
diff --git a/src/pages/AdminPanel.jsx b/src/pages/AdminPanel.jsx
deleted file mode 100644
index 1f641f2..0000000
--- a/src/pages/AdminPanel.jsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import React from 'react';
-import { Card, Table, Button, Space, Typography } from 'antd';
-import { UserOutlined, UploadOutlined, SettingOutlined } from '@ant-design/icons';
-
-const { Title } = Typography;
-
-const AdminPanel = () => {
-  // 模拟用户数据
-  const users = [
-    { key: '1', username: 'admin', role: '管理员', status: '正常', registrationDate: '2023-01-01' },
-    { key: '2', username: 'user1', role: '新人', status: '正常', registrationDate: '2023-02-15' },
-    { key: '3', username: 'user2', role: '老手', status: '禁用', registrationDate: '2023-03-20' },
-    { key: '4', username: 'user3', role: '黑户', status: '封禁', registrationDate: '2023-04-10' },
-    { key: '5', username: 'mod1', role: '版主', status: '正常', registrationDate: '2023-05-05' },
-  ];
-
-  const columns = [
-    { title: '用户名', dataIndex: 'username', key: 'username' },
-    { title: '角色', dataIndex: 'role', key: 'role' },
-    { title: '状态', dataIndex: 'status', key: 'status' },
-    { title: '注册日期', dataIndex: 'registrationDate', key: 'registrationDate' },
-    {
-      title: '操作',
-      key: 'action',
-      render: (_, record) => (
-        <Space size="middle">
-          <Button type="link">编辑</Button>
-          <Button type="link" danger>禁用</Button>
-        </Space>
-      ),
-    },
-  ];
-
-  return (
-    <div className="p-6">
-      <Title level={2}>管理员控制面板</Title>
-      <div className="flex gap-4 mb-6">
-        <Card title="用户统计" className="w-1/3">
-          <div className="flex items-center">
-            <UserOutlined className="text-2xl mr-2" />
-            <span className="text-xl">5 名用户</span>
-          </div>
-        </Card>
-        <Card title="资源统计" className="w-1/3">
-          <div className="flex items-center">
-            <UploadOutlined className="text-2xl mr-2" />
-            <span className="text-xl">25 个资源</span>
-          </div>
-        </Card>
-        <Card title="系统状态" className="w-1/3">
-          <div className="flex items-center">
-            <SettingOutlined className="text-2xl mr-2" />
-            <span className="text-xl">运行正常</span>
-          </div>
-        </Card>
-      </div>
-      <Card title="用户管理">
-        <Table columns={columns} dataSource={users} />
-      </Card>
-    </div>
-  );
-};
-
-export default AdminPanel;
\ No newline at end of file
diff --git a/src/pages/Login.jsx b/src/pages/Login.jsx
deleted file mode 100644
index f27ac02..0000000
--- a/src/pages/Login.jsx
+++ /dev/null
@@ -1,114 +0,0 @@
-import React, { useState } from 'react';
-import { useNavigate, Link } from 'react-router-dom';
-import { Form, Input, Button, Checkbox, Card, message, Typography, Space, Divider } from 'antd';
-import { UserOutlined, LockOutlined } from '@ant-design/icons';
-import request from '../utils/request'; // 替换为我们的请求工具
-
-const { Title, Text } = Typography;
-
-const Login = () => {
-  const [loading, setLoading] = useState(false);
-  const navigate = useNavigate();
-
-  const onFinish = async (values) => {
-    setLoading(true);
-    try {
-      const response = await request.post('/api/auth/login', {
-        username: values.username,
-        password: values.password
-      });
-      
-      if (response.data.code === 200) {
-        // 登录成功
-        localStorage.setItem('token', response.data.data.token);
-        localStorage.setItem('user', JSON.stringify(response.data.data.user));
-        
-        // 存储用户权限信息
-        if (response.data.data.permissions) {
-          localStorage.setItem('permissions', JSON.stringify(response.data.data.permissions));
-        }
-        
-        message.success('登录成功');
-        navigate('/');
-      } else {
-        message.error(response.data.message || '登录失败');
-      }
-    } catch (error) {
-      console.error('登录错误:', error);
-      // 错误处理已在拦截器中完成,这里不需要额外处理
-    } finally {
-      setLoading(false);
-    }
-  };
-
-  return (
-    <div className="flex justify-center items-center min-h-screen bg-gray-100 p-4">
-      <Card className="w-full max-w-md shadow-lg">
-        <div className="text-center mb-6">
-          <Title level={2} className="mb-2">PT网站登录</Title>
-          <Text type="secondary">欢迎回来,请登录您的账号</Text>
-        </div>
-        
-        <Form
-          name="login"
-          initialValues={{ remember: true }}
-          onFinish={onFinish}
-          size="large"
-          layout="vertical"
-        >
-          <Form.Item
-            name="username"
-            rules={[{ required: true, message: '请输入用户名!' }]}
-          >
-            <Input prefix={<UserOutlined />} placeholder="用户名" />
-          </Form.Item>
-          
-          <Form.Item
-            name="password"
-            rules={[{ required: true, message: '请输入密码!' }]}
-          >
-            <Input.Password prefix={<LockOutlined />} placeholder="密码" />
-          </Form.Item>
-          
-          <Form.Item>
-            <div className="flex justify-between items-center">
-              <Form.Item name="remember" valuePropName="checked" noStyle>
-                <Checkbox>记住我</Checkbox>
-              </Form.Item>
-              <a className="text-blue-500 hover:text-blue-700" href="#">
-                忘记密码
-              </a>
-            </div>
-          </Form.Item>
-
-          <Form.Item>
-            <Button type="primary" htmlType="submit" className="w-full" loading={loading}>
-              登录
-            </Button>
-          </Form.Item>
-          
-          <Divider plain>或者</Divider>
-          
-          <div className="text-center">
-            <Text type="secondary" className="mr-2">还没有账号?</Text>
-            <Link to="/register" className="text-blue-500 hover:text-blue-700">立即注册</Link>
-          </div>
-        </Form>
-        
-        <div className="mt-6 p-4 bg-gray-50 rounded-md">
-          <Text type="secondary" className="block mb-2">提示:测试账号</Text>
-          <ul className="space-y-1 text-sm text-gray-600">
-            <li>管理员: admin / admin123</li>
-            <li>普通用户: user / user123</li>
-            <li>版主: moderator / mod123</li>
-            <li>老手: veteran / vet123</li>
-            <li>新人: newbie / new123</li>
-            <li>黑户: blacklisted / black123</li>
-          </ul>
-        </div>
-      </Card>
-    </div>
-  );
-};
-
-export default Login;
\ No newline at end of file
diff --git a/src/pages/NotFound.test.jsx b/src/pages/NotFound.test.jsx
deleted file mode 100644
index edfaf05..0000000
--- a/src/pages/NotFound.test.jsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import { describe, it, expect } from 'vitest';
-import { render, screen } from '@testing-library/react';
-import { BrowserRouter } from 'react-router-dom';
-import NotFound from './NotFound';
-
-describe('NotFound 组件', () => {
-  it('应该渲染 404 页面', () => {
-    render(
-      <BrowserRouter>
-        <NotFound />
-      </BrowserRouter>
-    );
-    
-    expect(screen.getByText('404')).toBeInTheDocument();
-    expect(screen.getByText('抱歉,您访问的页面不存在。')).toBeInTheDocument();
-    expect(screen.getByText('返回首页')).toBeInTheDocument();
-  });
-});
\ No newline at end of file
diff --git a/src/pages/NotFound.jsx b/src/pages/NotFoundPage.jsx
similarity index 85%
rename from src/pages/NotFound.jsx
rename to src/pages/NotFoundPage.jsx
index 9dd4cdb..8c174f2 100644
--- a/src/pages/NotFound.jsx
+++ b/src/pages/NotFoundPage.jsx
@@ -2,7 +2,7 @@
 import { Button, Result } from 'antd';
 import { Link } from 'react-router-dom';
 
-const NotFound = () => {
+const NotFoundPage = () => {
   return (
     <Result
       status="404"
@@ -17,4 +17,4 @@
   );
 };
 
-export default NotFound;
\ No newline at end of file
+export default NotFoundPage;
\ No newline at end of file
diff --git a/src/pages/Register.jsx b/src/pages/Register.jsx
deleted file mode 100644
index 65de07e..0000000
--- a/src/pages/Register.jsx
+++ /dev/null
@@ -1,118 +0,0 @@
-import React, { useState } from 'react';
-import { useNavigate, Link } from 'react-router-dom';
-import { Form, Input, Button, Card, message, Typography, Divider } from 'antd';
-import { UserOutlined, LockOutlined, MailOutlined } from '@ant-design/icons';
-import axios from 'axios';
-// 删除 import './Register.css';
-
-const { Title, Text } = Typography;
-
-const Register = () => {
-  const [loading, setLoading] = useState(false);
-  const navigate = useNavigate();
-
-  const onFinish = async (values) => {
-    setLoading(true);
-    try {
-      const response = await axios.post('/api/auth/register', {
-        username: values.username,
-        email: values.email,
-        password: values.password
-      });
-      
-      if (response.data.code === 200) {
-        message.success('注册成功!');
-        navigate('/login');
-      } else {
-        message.error(response.data.message || '注册失败');
-      }
-    } catch (error) {
-      console.error('注册错误:', error);
-      message.error('注册失败,请检查网络连接');
-    } finally {
-      setLoading(false);
-    }
-  };
-
-  return (
-    <div className="flex justify-center items-center min-h-screen bg-gray-100">
-      <Card className="w-full max-w-md">
-        <div className="text-center mb-6">
-          <Title level={2} className="mb-3">注册账号</Title>
-          <Text type="secondary">创建您的PT网站账号</Text>
-        </div>
-        
-        <Form
-          name="register"
-          onFinish={onFinish}
-          size="large"
-          layout="vertical"
-        >
-          <Form.Item
-            name="username"
-            rules={[
-              { required: true, message: '请输入用户名!' },
-              { min: 3, message: '用户名至少3个字符' },
-              { max: 20, message: '用户名最多20个字符' }
-            ]}
-          >
-            <Input prefix={<UserOutlined />} placeholder="用户名" />
-          </Form.Item>
-          
-          <Form.Item
-            name="email"
-            rules={[
-              { required: true, message: '请输入邮箱!' },
-              { type: 'email', message: '请输入有效的邮箱地址!' }
-            ]}
-          >
-            <Input prefix={<MailOutlined />} placeholder="邮箱" />
-          </Form.Item>
-          
-          <Form.Item
-            name="password"
-            rules={[
-              { required: true, message: '请输入密码!' },
-              { min: 6, message: '密码至少6个字符' }
-            ]}
-          >
-            <Input.Password prefix={<LockOutlined />} placeholder="密码" />
-          </Form.Item>
-          
-          <Form.Item
-            name="confirm"
-            dependencies={['password']}
-            rules={[
-              { required: true, message: '请确认密码!' },
-              ({ getFieldValue }) => ({
-                validator(_, value) {
-                  if (!value || getFieldValue('password') === value) {
-                    return Promise.resolve();
-                  }
-                  return Promise.reject(new Error('两次输入的密码不一致!'));
-                },
-              }),
-            ]}
-          >
-            <Input.Password prefix={<LockOutlined />} placeholder="确认密码" />
-          </Form.Item>
-
-          <Form.Item>
-            <Button type="primary" htmlType="submit" className="w-full" loading={loading}>
-              注册
-            </Button>
-          </Form.Item>
-          
-          <Divider plain>或者</Divider>
-          
-          <div className="text-center mt-2">
-            <Text type="secondary">已有账号?</Text>
-            <Link to="/login">立即登录</Link>
-          </div>
-        </Form>
-      </Card>
-    </div>
-  );
-};
-
-export default Register;
\ No newline at end of file
diff --git a/src/pages/Unauthorized.jsx b/src/pages/UnauthorizedPage.jsx
similarity index 84%
rename from src/pages/Unauthorized.jsx
rename to src/pages/UnauthorizedPage.jsx
index 6e93266..30efee6 100644
--- a/src/pages/Unauthorized.jsx
+++ b/src/pages/UnauthorizedPage.jsx
@@ -2,7 +2,7 @@
 import { Result, Button } from 'antd';
 import { Link } from 'react-router-dom';
 
-const Unauthorized = () => {
+const UnauthorizedPage = () => {
   return (
     <Result
       status="403"
@@ -17,4 +17,4 @@
   );
 };
 
-export default Unauthorized;
\ No newline at end of file
+export default UnauthorizedPage;
\ No newline at end of file