添加测试配置及登陆部分的测试
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