添加测试配置及登陆部分的测试

Change-Id: I6fa1fe23ad8773548927fdc921dceab841f2368a
diff --git a/src/api/auth.ts b/src/api/auth.ts
new file mode 100644
index 0000000..bc6d413
--- /dev/null
+++ b/src/api/auth.ts
@@ -0,0 +1,3 @@
+export const postUserLogin= '/auth/login';
+export const postUserRegister= '/auth/register';
+export const postVerifivateCode="/auth/send_verification_code";
\ No newline at end of file
diff --git a/src/api/user.ts b/src/api/user.ts
index 2c5e46c..30fbfff 100644
--- a/src/api/user.ts
+++ b/src/api/user.ts
@@ -1,5 +1 @@
-export const queryUserName='/user/${id}';
-export const getUserInfo= '/user/info';
-export const userLogin= '/user/login';
-export const userLogout= '/user/logout';
-export const userRegister= '/user/register';
\ No newline at end of file
+export const getUserInfo="/user"
\ No newline at end of file
diff --git a/src/components/selfStatus/selfStatus.tsx b/src/components/selfStatus/selfStatus.tsx
index 40d3ac3..be2a3bc 100644
--- a/src/components/selfStatus/selfStatus.tsx
+++ b/src/components/selfStatus/selfStatus.tsx
@@ -2,8 +2,11 @@
 import { useAppSelector } from "../../hooks/store";
 import style from "./style.module.css"
 
+interface SelfStatusProps {
+    className?: string;
+}
 
-const SelfStatus: React.FC = () => {
+const SelfStatus: React.FC<SelfStatusProps> = () => {
     const userName = useAppSelector(state => state.user.userName);
     const role = useAppSelector(state => state.user.role);
     const uploadTraffic = useAppSelector(state => state.user.uploadTraffic);
@@ -23,9 +26,11 @@
                     <p className={style.role}>角色: {role}</p>
                     <p className={style.uploadTraffic}>上传量: {uploadTraffic}</p>
                     <p className={style.downloadTraffic}>下载量: {downloadTraffic}</p>
+
                     <p className={style.shareRatio}>
                         分享率: {uploadTraffic && downloadTraffic ? (uploadTraffic / downloadTraffic).toFixed(2) : "N/A"}
                     </p>
+                    <p className={style.downloadPoints}>下载积分: {downloadPoints}</p>
                 </div>
                 <button className={style.signInButton}>签到</button>
             </div>
diff --git a/src/components/selfStatus/style.module.css b/src/components/selfStatus/style.module.css
index 4e80ece..bcf883c 100644
--- a/src/components/selfStatus/style.module.css
+++ b/src/components/selfStatus/style.module.css
@@ -8,37 +8,41 @@
     border-radius: 10px;
     background-color: #f9f9f9;
     width: 100%;
-    height: 200px; /* Adjust height as needed */
+    height: 100%; /* Adjust height as needed */
     box-sizing: border-box;
+    overflow:hidden;
 }
 
 .left {
+    border:1px solid #ccc;
     display: flex;
     flex-direction: column;
     align-items: center;
     justify-content: flex-start;
-    width: 20%; /* Adjust width for avatar section */
+    width: 35%; /* Adjust width for avatar section */
 }
 
 .avatar {
-    width: 80px;
-    height: 80px;
+    width: 100%;
+    height: 100%;
     border-radius: 50%;
     object-fit: cover;
     margin-bottom: 10px;
 }
 .right {
+    border:1px solid #aaa;
     display: flex;
     flex-direction: column;
-    justify-content: space-between;
+    justify-content: flex-start;
     align-items: flex-start;
-    width: 75%; /* Adjust width for info and button section */
+    width: 55%; /* Adjust width for info and button section */
 }
 
 .info {
     display: flex;
     flex-direction: column;
     align-items: flex-start;
+    justify-content: flex-start;
     margin-bottom: 10px;
 }
 
@@ -50,6 +54,7 @@
 .role,
 .uploadTraffic,
 .downloadTraffic,
+.downloadPoints,
 .shareRatio {
     font-size: 14px;
     margin-bottom: 5px;
diff --git a/src/global.css b/src/global.css
index 7dfec7b..8d1922e 100644
--- a/src/global.css
+++ b/src/global.css
@@ -9,4 +9,16 @@
     align-items: center;
     font-family: Arial, sans-serif; /* Optional: Set a global font */
     box-sizing: border-box;
+}
+.root {
+    margin: 0;
+    padding: 0;
+    height: 100vh;
+    width: 100vw;
+    background-color: #e6f7ff; /* Light blue background */
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    font-family: Arial, sans-serif; /* Optional: Set a global font */
+    box-sizing: border-box;
 }
\ No newline at end of file
diff --git a/src/mock/auth.d.ts b/src/mock/auth.d.ts
new file mode 100644
index 0000000..70d0d39
--- /dev/null
+++ b/src/mock/auth.d.ts
@@ -0,0 +1,3 @@
+import type MockAdapter from 'axios-mock-adapter';
+
+export declare function setupAuthMock(mock: MockAdapter): void;
\ No newline at end of file
diff --git a/src/mock/auth.js b/src/mock/auth.js
new file mode 100644
index 0000000..3cc837b
--- /dev/null
+++ b/src/mock/auth.js
@@ -0,0 +1,16 @@
+import Mock from 'mockjs';
+import MockAdapter from 'axios-mock-adapter';
+import {postUserLogin} from '@/api/auth'; // Import the API endpoint
+
+/**
+ * 设置用户相关的 Mock 接口
+ * @param {MockAdapter} mock 
+ */
+export function setupAuthMock(mock){
+    mock.onPost(postUserLogin).reply(config => {
+        let data = Mock.mock({
+          "token": '11111111111111111',
+        });
+        return [200, data];
+      });
+}    
diff --git a/src/mock/index.ts b/src/mock/index.ts
index 1b2b722..b07a1be 100644
--- a/src/mock/index.ts
+++ b/src/mock/index.ts
@@ -1,6 +1,6 @@
 import MockAdapter from 'axios-mock-adapter';
 import instance from '@/utils/axios'
-import {setupUserMock}  from './user'
+import {setupAuthMock}  from './auth'
 
 // 创建 Mock 实例
 export const mock = new MockAdapter(instance, { 
@@ -13,7 +13,7 @@
   if (process.env.NODE_ENV !== 'development') return
 
   // 加载各模块 Mock
-  setupUserMock(mock)
+  setupAuthMock(mock)
   
   console.log('Mock 模块已加载')
 }
diff --git a/src/mock/user.js b/src/mock/user.js
index 4bca1f8..e3ae653 100644
--- a/src/mock/user.js
+++ b/src/mock/user.js
@@ -1,23 +1,21 @@
 import Mock from 'mockjs';
 import MockAdapter from 'axios-mock-adapter';
-
-import { userLogin } from '@/api/user'; // Import the API endpoint
+import {getUserInfo} from '@/api/user'// Import the API endpoint
 
 /**
  * 设置用户相关的 Mock 接口
  * @param {MockAdapter} mock 
  */
 export function setupUserMock(mock){
-    mock.onPost(userLogin).reply(config => {
+    mock.onGet(getUserInfo).reply(config => {
         let data = Mock.mock({
-          "userId": 0,
-          "userName": '',
-          "role": '',
-          "isLogin": false,
-          "uploadTraffic": 0,
-          "downloadTraffic": 0,
-          "downloadPoints": 0,
-          "avatar": 'D:/Code/projects/react/G8Frontend/public/avatar.jpg',
+            'userId' : '001',
+            'userName' : 'san3yuan',
+            'role' : 'manager',
+            'uploadTraffic' : 0,
+            'downloadTraffic': 0,
+            'downloadPoints' : 0,
+            'avatar' : 0,
         });
         return [200, data];
       });
diff --git a/src/route/index.tsx b/src/route/index.tsx
index 5c69c6c..d857a36 100644
--- a/src/route/index.tsx
+++ b/src/route/index.tsx
@@ -1,7 +1,7 @@
 import { createBrowserRouter } from 'react-router-dom'
 import PrivateRoute from './privateRoute'
 import { useSelector } from 'react-redux'
-import Login from '../views/login'
+import Login from '../views/login/login'
 import React from 'react'
 import Forum from '../views/forum'
 import { RootState } from '@/store'
@@ -9,7 +9,8 @@
 const router = createBrowserRouter([
     {
         path: '/',
-        element:<PrivateRoute
+        element:
+        <PrivateRoute
         role={0} // 判断是否登录
         redirectPath="/login"/>, 
         children: [
diff --git a/src/store/userReducer.ts b/src/store/userReducer.ts
index f335c25..61cacb8 100644
--- a/src/store/userReducer.ts
+++ b/src/store/userReducer.ts
@@ -1,7 +1,7 @@
 import { createSlice } from '@reduxjs/toolkit';
 
 interface UserState {
-    userId: number;
+    userId: string;
     userName: string;
     role: string;
     isLogin: boolean;
@@ -12,7 +12,7 @@
 }
 
 const initialState: UserState = {
-    userId: 0,
+    userId: '',
     userName: '',
     role: '',
     isLogin: false,
@@ -28,20 +28,21 @@
     initialState,
     reducers: {
         login: (state, action) => {
-                
+            localStorage.setItem('token', action.payload.token);
+            state.isLogin = true;
+        },
+        getUserInfo: (state, action) => {
+            
             state.userId = action.payload.userId;
             state.userName = action.payload.userName;
             state.role = action.payload.role;
-            state.isLogin = true;
             state.uploadTraffic = action.payload.uploadTraffic;
             state.downloadTraffic = action.payload.downloadTraffic;
             state.downloadPoints = action.payload.downloadPoints;
             state.avatar = action.payload.avatar;
-
-            console.log('userId', state.userId);
         },
         logout: (state) => {
-            state.userId = 0;
+            state.userId = '';
             state.userName = '';
             state.role = '';
             state.isLogin = false;
diff --git a/src/utils/axios.ts b/src/utils/axios.ts
index c7639b0..1eaad87 100644
--- a/src/utils/axios.ts
+++ b/src/utils/axios.ts
@@ -13,7 +13,7 @@
   instance.interceptors.request.use(
     (config) => {
       // 添加认证 token
-      const token = localStorage.getItem('access_token')
+      const token = localStorage.getItem('token')
       if (token) {
         config.headers.Authorization = `Bearer ${token}`
       }
diff --git a/src/utils/request.ts b/src/utils/request.ts
index 7701fc0..c025c6c 100644
--- a/src/utils/request.ts
+++ b/src/utils/request.ts
@@ -25,7 +25,7 @@
 }
 
 // 开发环境启用 Mock
-if (process.env.NODE_ENV === 'development') {
+if (process.env.NODE_ENV !== 'production') {
   require('../mock') // 你的 Mock 配置文件
 }
 
diff --git a/src/views/forum/index.module.css b/src/views/forum/index.module.css
new file mode 100644
index 0000000..53cf91c
--- /dev/null
+++ b/src/views/forum/index.module.css
@@ -0,0 +1,12 @@
+.selfStatus{
+    width:25%;
+    height:45%;
+    position: absolute;
+    right:0%;
+    top:0%;
+    
+}
+.container{
+    width:100%;
+    height:100%;
+}
\ No newline at end of file
diff --git a/src/views/forum/index.tsx b/src/views/forum/index.tsx
index 6e8ad59..dbceffd 100644
--- a/src/views/forum/index.tsx
+++ b/src/views/forum/index.tsx
@@ -2,14 +2,16 @@
 import { Navigate } from "react-router";
 import SelfStatus from "@/components/selfStatus/selfStatus";
 
+import style from "./index.module.css";
+
 export default function Forum() {
 
 
     return (
-        <div>
-            <SelfStatus/>
-            <h1>Forum</h1>
-            <p>Welcome to the forum!</p>
+        <div className={style.container}>
+            <div className={style.selfStatus}>
+                <SelfStatus />
+            </div>
         </div>
     );
 }
\ No newline at end of file
diff --git a/src/views/login/index.tsx b/src/views/login/index.tsx
deleted file mode 100644
index 4cb66a5..0000000
--- a/src/views/login/index.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import React, { useEffect } from 'react';
-import { useApi } from '@/hooks/request';
-import request from '@/utils/request';
-import { userLogin } from '@/api/user';
-import { useAppDispatch } from '@/hooks/store';
-import { RootState } from '@/store';
-import style from './login.module.css';
-import { useSelector } from 'react-redux';
-import { useNavigate } from 'react-router';
-
-const Login: React.FC = () => {
-    const dispatch = useAppDispatch();
-    const { data, loading, error, refresh } = useApi(() => request.post(userLogin), false);
-
-    const nav = useNavigate();
-    const handleLogin = async () => {
-        const res = await refresh();
-        console.log(res);
-        dispatch({ type: "user/login", payload: res });
-        nav('/');
-        
-    };
-    const userName = useSelector((state: RootState) => state.user.userName);
-
-    return (
-
-        <div className={style.form}>
-            <img alt = "logo"></img>
-            <input type="email" className={style.email} placeholder="Enter your email" />
-            <input type="password" className={style.password} placeholder="Enter your password" />
-            <button className={style.submit} onClick={handleLogin}>Login</button>
-            <button>Register</button>
-        </div>
-    );
-};
-
-export default Login;
\ No newline at end of file
diff --git a/src/views/login/login.module.css b/src/views/login/login.module.css
index 7571160..dca1df4 100644
--- a/src/views/login/login.module.css
+++ b/src/views/login/login.module.css
@@ -16,7 +16,11 @@
     box-sizing: border-box; /* Include padding and border in width/height */
     
 }
-
+.form .logo{
+    width: 100px; /* Set a fixed width for the logo */
+    height: auto; /* Maintain aspect ratio */
+    margin-bottom: 20px; /* Space between logo and form */
+}
 
 .form input {
     margin: 5px;
@@ -57,7 +61,7 @@
     background-color: #45a049; /* Darker green */
 }
 
-.form button {
+.form .register {
     margin: 10px;
     padding: 10px;
     border-radius: 5px;
@@ -70,6 +74,20 @@
     max-width: 300px;
 }
 
-.form button:hover {
+.form .register:hover {
     background-color: #0056b3; /* Darker blue */
+}
+
+.form .forget{
+    border: none;
+    text-decoration: underline;
+    align-content: flex-end;
+    
+}
+
+.form .forget:hover{
+    border: none;
+    text-decoration: underline;
+    align-content: flex-end;
+    color: #007BFF; /* Blue */
 }
\ No newline at end of file
diff --git a/src/views/login/login.tsx b/src/views/login/login.tsx
new file mode 100644
index 0000000..26b7842
--- /dev/null
+++ b/src/views/login/login.tsx
@@ -0,0 +1,61 @@
+import React, { useEffect } from 'react';
+import { useApi } from '@/hooks/request';
+import request from '@/utils/request';
+import { postUserLogin} from '@/api/auth';
+import { useAppDispatch } from '@/hooks/store';
+import { RootState } from '@/store';
+import style from './login.module.css';
+import { useState } from 'react';
+import { useSelector } from 'react-redux';
+import { useNavigate } from 'react-router';
+import logo from '&/asserts/logo.png';
+import { getUserInfo } from '@/api/user';
+
+
+const Login: React.FC = () => {
+    const [email, setEmail] = useState('');
+    const [password, setPassword] = useState('');
+    const dispatch = useAppDispatch();
+    const { refresh: postUserLoginRefresh } = useApi(() => request.post(postUserLogin, {}), false);
+    const { refresh: getUserInfoRefresh } = useApi(async () => await request.get(getUserInfo), false);
+
+    const nav = useNavigate();
+    const handleLogin = async () => {
+        try {
+            const res = await postUserLoginRefresh();
+            if (res==null ||(res as any).error) {
+                alert('Login failed. Please check your credentials.');
+                return;
+            }
+            dispatch({ type: "user/login", payload: res });
+            
+            const userInfo = await getUserInfoRefresh();
+            if (userInfo==null || (userInfo as any).error) {
+                alert('Failed to fetch user information.');
+                return;
+            }
+            dispatch({ type: "user/getUserInfo", payload: userInfo });
+            nav('/');
+        } catch (error) {
+            alert('An unexpected error occurred. Please try again later.');
+            if (error instanceof Error) {
+              console.error(error.message); // 明确访问 message 属性
+            } else {
+              console.error('Unknown error occurred');
+            }
+        }
+    };
+
+    return (
+        <div className={style.form}>
+            <img className={style.logo} src={logo} alt="logo"></img>
+            <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} className={style.email} placeholder="Enter your email" />
+            <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} className={style.password} placeholder="Enter your password" />
+            <button className={style.submit} onClick={handleLogin}>登录</button>
+            <button className={style.register}>注册</button>
+            <button className={style.forget}> 忘记密码</button>
+        </div>
+    );
+};
+
+export default Login;
\ No newline at end of file