add css module compile rule and a login guard
Change-Id: I5c99e236f92d3b6c6d0060b36cf90a252df93a95
diff --git a/src/components/selfStatus/selfStatus.tsx b/src/components/selfStatus/selfStatus.tsx
index e954852..40d3ac3 100644
--- a/src/components/selfStatus/selfStatus.tsx
+++ b/src/components/selfStatus/selfStatus.tsx
@@ -1,28 +1,36 @@
import React from "react";
import { useAppSelector } from "../../hooks/store";
-import "./style.css"
+import style from "./style.module.css"
-const SelfStatus :React.FC = () => {
- const userName = useAppSelector(state => state.user.userName)
- const role = useAppSelector(state => state.user.role)
- const uploadTraffic = useAppSelector(state => state.user.uploadTraffic)
- const downloadTraffic = useAppSelector(state => state.user.downloadTraffic)
- const downloadPoints = useAppSelector(state => state.user.downloadPoints)
- const avatar = useAppSelector(state => state.user.avatar)
- const islogin = useAppSelector(state => state.user.isLogin)
- return <>
- <div className="user">
- <img className="avatar" src={avatar}></img>
- <p className="userName">{userName},欢迎你</p>
+const SelfStatus: React.FC = () => {
+ const userName = useAppSelector(state => state.user.userName);
+ const role = useAppSelector(state => state.user.role);
+ const uploadTraffic = useAppSelector(state => state.user.uploadTraffic);
+ const downloadTraffic = useAppSelector(state => state.user.downloadTraffic);
+ const downloadPoints = useAppSelector(state => state.user.downloadPoints);
+ const avatar = useAppSelector(state => state.user.avatar);
+ console.log(avatar)
+
+ return (
+ <div className={style.container}>
+ <div className={style.left}>
+ <img className={style.avatar} src={avatar} alt="User Avatar" />
</div>
- <div className="info" >
- <p className="uploadTraffic">上传量:{uploadTraffic}</p>
- <p>下载量:{downloadTraffic}</p>
- <p>下载积分:{downloadPoints}</p>
+ <div className={style.right}>
+ <div className={style.info}>
+ <p className={style.userName}>{userName}</p>
+ <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>
+ </div>
+ <button className={style.signInButton}>签到</button>
</div>
+ </div>
+ );
+};
- </>
-}
-
-export default SelfStatus
+export default SelfStatus;
diff --git a/src/components/selfStatus/style.css b/src/components/selfStatus/style.css
deleted file mode 100644
index afb50a0..0000000
--- a/src/components/selfStatus/style.css
+++ /dev/null
@@ -1,19 +0,0 @@
-
-.user{
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- margin-top: 20px;
-}
-.user img {
- width:40%;
- border-radius: 20px;
- margin-top: 20px;
-}
-.info p{
- font-size: 20px;
- font-weight: bold;
- margin-top: 20px;
-}
-
diff --git a/src/components/selfStatus/style.module.css b/src/components/selfStatus/style.module.css
new file mode 100644
index 0000000..4e80ece
--- /dev/null
+++ b/src/components/selfStatus/style.module.css
@@ -0,0 +1,71 @@
+.container {
+ display: flex;
+ flex-direction: row;
+ align-items: flex-start;
+ justify-content: space-between;
+ padding: 20px;
+ border: 1px solid #ccc;
+ border-radius: 10px;
+ background-color: #f9f9f9;
+ width: 100%;
+ height: 200px; /* Adjust height as needed */
+ box-sizing: border-box;
+}
+
+.left {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: flex-start;
+ width: 20%; /* Adjust width for avatar section */
+}
+
+.avatar {
+ width: 80px;
+ height: 80px;
+ border-radius: 50%;
+ object-fit: cover;
+ margin-bottom: 10px;
+}
+.right {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ align-items: flex-start;
+ width: 75%; /* Adjust width for info and button section */
+}
+
+.info {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ margin-bottom: 10px;
+}
+
+.userName {
+ font-size: 18px;
+ font-weight: bold;
+ margin-bottom: 5px;
+}
+.role,
+.uploadTraffic,
+.downloadTraffic,
+.shareRatio {
+ font-size: 14px;
+ margin-bottom: 5px;
+}
+
+.signInButton {
+ align-self: flex-end;
+ padding: 10px 20px;
+ font-size: 14px;
+ background-color: #4CAF50;
+ color: white;
+ border: none;
+ border-radius: 5px;
+ cursor: pointer;
+}
+
+.signInButton:hover {
+ background-color: #45a049;
+}
\ No newline at end of file
diff --git a/src/global.css b/src/global.css
new file mode 100644
index 0000000..7dfec7b
--- /dev/null
+++ b/src/global.css
@@ -0,0 +1,12 @@
+body {
+ 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/index.tsx b/src/index.tsx
index e66ba06..4bd29bd 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -4,6 +4,7 @@
import router from "./route";
import store from "./store/index";
import { RouterProvider } from "react-router";
+import './global.css';
const root = createRoot(document.getElementById('root')!)
root.render(
diff --git a/src/mock/index.ts b/src/mock/index.ts
index 9bb29d3..1b2b722 100644
--- a/src/mock/index.ts
+++ b/src/mock/index.ts
@@ -14,6 +14,7 @@
// 加载各模块 Mock
setupUserMock(mock)
+
console.log('Mock 模块已加载')
}
diff --git a/src/mock/user.js b/src/mock/user.js
index 2ffb8c7..4bca1f8 100644
--- a/src/mock/user.js
+++ b/src/mock/user.js
@@ -17,7 +17,7 @@
"uploadTraffic": 0,
"downloadTraffic": 0,
"downloadPoints": 0,
- "avatar": ''
+ "avatar": 'D:/Code/projects/react/G8Frontend/public/avatar.jpg',
});
return [200, data];
});
diff --git a/src/route/index.tsx b/src/route/index.tsx
index da0720e..5c69c6c 100644
--- a/src/route/index.tsx
+++ b/src/route/index.tsx
@@ -1,18 +1,31 @@
import { createBrowserRouter } from 'react-router-dom'
import PrivateRoute from './privateRoute'
+import { useSelector } from 'react-redux'
import Login from '../views/login'
import React from 'react'
import Forum from '../views/forum'
+import { RootState } from '@/store'
const router = createBrowserRouter([
{
path: '/',
- element: <Forum /> // 论坛主页面
+ element:<PrivateRoute
+ role={0} // 判断是否登录
+ redirectPath="/login"/>,
+ children: [
+ {
+ index: true,
+ element: <Forum /> // 论坛主页面
+ },
+ ]
},
{
path: '/login',
element: <Login /> // 登录页作为独立路由
}
+
+
+
]
)
diff --git a/src/route/privateRoute.tsx b/src/route/privateRoute.tsx
index 8391f90..992f372 100644
--- a/src/route/privateRoute.tsx
+++ b/src/route/privateRoute.tsx
@@ -1,22 +1,35 @@
import { Navigate, Outlet } from 'react-router-dom'
import React from 'react'
+import { useSelector } from 'react-redux'
interface PrivateRouteProps {
- isAllowed: boolean
+ role: number
redirectPath?: string
children?: React.ReactNode
}
const PrivateRoute = ({
- isAllowed,
+ role,
redirectPath = '/login',
children
}: PrivateRouteProps) => {
- if (!isAllowed) {
+ const isLogin = useSelector((state: any) => state.user.isLogin)
+ const userRole = useSelector((state: any) => state.user.role)
+
+ if (!isLogin) {
return <Navigate to={redirectPath} replace />
}
- return children ? children : <Outlet />
+ if (role && role >= userRole) {
+ return <Navigate to={redirectPath} replace />
+ }
+
+ return children ? (
+ <>{children}</>
+ ) : (
+ <Outlet />
+ )
+
}
export default PrivateRoute
\ No newline at end of file
diff --git a/src/views/forum/index.tsx b/src/views/forum/index.tsx
index 6090868..6e8ad59 100644
--- a/src/views/forum/index.tsx
+++ b/src/views/forum/index.tsx
@@ -1,11 +1,13 @@
import React from "react";
import { Navigate } from "react-router";
+import SelfStatus from "@/components/selfStatus/selfStatus";
export default function Forum() {
return (
<div>
+ <SelfStatus/>
<h1>Forum</h1>
<p>Welcome to the forum!</p>
</div>
diff --git a/src/views/login/index.tsx b/src/views/login/index.tsx
index 9c1abc2..4cb66a5 100644
--- a/src/views/login/index.tsx
+++ b/src/views/login/index.tsx
@@ -1,29 +1,37 @@
import React, { useEffect } from 'react';
import { useApi } from '@/hooks/request';
import request from '@/utils/request';
-import {userLogin} from '@/api/user';
+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 () => {
- // 点击时调用 execute 发起请求
const res = await refresh();
console.log(res);
- // 请求完成后可以使用返回的数据进行分发
dispatch({ type: "user/login", payload: res });
+ nav('/');
+
};
+ const userName = useSelector((state: RootState) => state.user.userName);
+
return (
- <div>
- <input type='email'></input>
- <input></input>
- <button onClick={handleLogin}>Login</button>
+
+ <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
new file mode 100644
index 0000000..7571160
--- /dev/null
+++ b/src/views/login/login.module.css
@@ -0,0 +1,75 @@
+.form {
+ display: flex;
+ flex-direction: column;
+ align-items: center; /* Center items horizontally */
+ justify-content: center; /* Center items vertically */
+ height: 40%; /* Occupy 40% of the viewport height */
+ width:25%;
+ background-color: #f0f8ff; /* Light blue background */
+ box-shadow: 3px 3px 5px 6px #ccc;
+ position: absolute; /* Position the form absolutely */
+ top: 50%; /* Move to the middle of the viewport */
+ left: 50%; /* Center horizontally */
+ transform: translate(-50%, -50%); /* Adjust for centering */
+ border-radius: 10px; /* Add rounded corners */
+ padding: 20px; /* Add padding for better spacing */
+ box-sizing: border-box; /* Include padding and border in width/height */
+
+}
+
+
+.form input {
+ margin: 5px;
+ padding: 5px;
+ border-radius: 5px;
+ border: 1px solid #ccc;
+ font-size: 16px;
+ width: 80%; /* Adjust width for better appearance */
+ max-width: 300px; /* Limit maximum width */
+ box-sizing: border-box;
+}
+
+.form .email,
+.form .password {
+ margin: 10px;
+ padding: 10px;
+ border-radius: 5px;
+ border: 1px solid #ccc;
+ font-size: 16px;
+ width: 80%;
+ max-width: 300px;
+}
+
+.form .submit {
+ margin: 10px;
+ padding: 10px;
+ border-radius: 5px;
+ border: 1px solid #ccc;
+ font-size: 16px;
+ background-color: #4CAF50; /* Green */
+ color: white;
+ cursor: pointer;
+ width: 80%;
+ max-width: 300px;
+}
+
+.form .submit:hover {
+ background-color: #45a049; /* Darker green */
+}
+
+.form button {
+ margin: 10px;
+ padding: 10px;
+ border-radius: 5px;
+ border: none;
+ font-size: 16px;
+ background-color: #007BFF; /* Blue */
+ color: white;
+ cursor: pointer;
+ width: 80%;
+ max-width: 300px;
+}
+
+.form button:hover {
+ background-color: #0056b3; /* Darker blue */
+}
\ No newline at end of file