完成强制跳转登录页面、完成用户信息存储

This commit is contained in:
wzhqwq 2021-07-30 13:08:37 +08:00
父節點 9b71c1f527
當前提交 1b66a5467a
共有 13 個檔案被更改,包括 178 行新增60 行删除

查看文件

@ -6,6 +6,7 @@
"axios": "^0.21.1",
"cra-template": "1.1.2",
"dotenv": "^10.0.0",
"qs": "^6.10.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",

二進制
public/image/user.jpg Normal file

未顯示二進位檔案。

之後

寬度:  |  高度:  |  大小: 33 KiB

查看文件

@ -5,6 +5,7 @@ a.btn {
color: white !important;
border-radius: .3em;
padding: .375em 0;
line-height: 1.5em;
font-size: 1.1em;
cursor: pointer;
transition: filter .3s ease-out;
@ -14,7 +15,7 @@ a.btn {
}
.btn:disabled {
cursor: not-allowed;
filter: grayscale(100%);
filter: grayscale(100%) opacity(.5);
}
.btn:active {
color: white !important;
@ -58,3 +59,18 @@ button.btn {
border-radius: .15em;
width: 6em;
}
.sdu,
.user {
height: 100%;
display: flex;
align-items: center;
}
.sdu-logo,
.user-logo {
height: 100%;
}
.sdu-name {
height: 30px;
margin-left: 10px;
}

查看文件

@ -1,21 +1,43 @@
import './App.css';
import { Route, SingleRouter } from './components/SingleRouter/SingleRouter';
import { Redirect, Route, SingleRouter } from './components/SingleRouter/SingleRouter';
import { AppContainer } from './index/index';
import { UploadContainer } from './upload/upload';
import { LogInContainer } from './login/login';
import { ReviewContainer } from './review/review';
import History from './helper/history';
import { Component } from 'react';
import { UserContext } from './helper/Context';
function App() {
// TODO check login
return (
<SingleRouter history={History}>
<Route path="/" component={AppContainer} />
<Route path="/upload" component={UploadContainer} />
<Route path="/login" component={LogInContainer} />
<Route path="/review" component={ReviewContainer} />
</SingleRouter>
);
class App extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
role: -1
};
this.setUserData = this.setUserData.bind(this);
}
setUserData({ name, role }) {
this.setState({ name, role });
}
render() {
return (
<UserContext.Provider value={{ userData: this.state, setUserData: this.setUserData }}>
<SingleRouter>
<Route path="/" component={AppContainer} />
<Route path="/upload" component={UploadContainer} />
<Route path="/login" component={LogInContainer} />
<Route path="/review" component={ReviewContainer} />
<Route component={CheckLogIn} />
</SingleRouter>
</UserContext.Provider>
);
}
}
function CheckLogIn() {
return localStorage.getItem('jwt') ? null : <Redirect from={/^\/.*/} to="/login" />;
}
export default App;

查看文件

@ -1,6 +1,6 @@
.spinner {
width: 20px;
height: 20px;
width: 1.5em;
height: 1.5em;
margin: 0 auto;
}
.spinner > svg {

查看文件

@ -0,0 +1,53 @@
import './userControl.css';
import { images } from '../../resources.json';
import { UserContext } from '../../helper/Context';
import Spinner from '../Spinner/Spinner';
import { get } from '../../helper/axios';
import { apis } from '../../helper/apis';
import { alert } from '../../helper/alert';
export default function UserControl(props) {
return (
<UserContext.Consumer>
{({ userData, setUserData }) => (
userData.role === 2
? (
<div className="user">
<button
className="btn btn-hollow btn-straight"
onClick={() => setUserData({ role: -1, name: '' })}
>退出审核</button>
</div>
) : (
<div className="user">
{
userData.role === -1
? (
<Spinner />
) : (
<div className="user-avatar">
<img src={images.avatar} alt="user avatar" />
</div>
)
}
<div className="user-name">{userData.name || "加载中"}</div>
{
(() => {
if (userData.role !== -1) return null;
get(apis.getProfile).then(({ data, status, networkStatus }) => {
if (networkStatus !== 200) return;
if (!status) return alert('获取用户信息失败:' + data + ',请稍候刷新再试');
setUserData({
name: data.realName,
role: data.role
});
});
return null;
})()
}
</div>
)
)}
</UserContext.Consumer>
);
}

查看文件

@ -0,0 +1,19 @@
.user-name {
height: 100%;
font-size: 18px;
height: 50px;
line-height: 50px;
color: white;
margin-left: 10px;
}
.user-avatar {
width: 40px;
height: 40px;
}
.user-avatar > img {
border-radius: 50%;
width: 100%;
height: 100%;
}

3
src/helper/Context.js Normal file
查看文件

@ -0,0 +1,3 @@
import { createContext } from "react";
export const UserContext = createContext({});

查看文件

@ -1,11 +1,13 @@
import axios from 'axios';
import { failed } from './alert';
import qs from 'qs';
import History from './history';
export function get(url) {
return send(
axios.get(url, {
headers: {
Authorization: 'Bearer ' + localStorage.getItem('jwt'),
Authorization: localStorage.getItem('jwt'),
"Allow-Control-Allow-Origin": "*"
}
}),
@ -14,9 +16,9 @@ export function get(url) {
}
export function post(url, data) {
return send(
axios.post(url, data, {
axios.post(url, qs.stringify(data), {
headers: {
Authorization: 'Bearer ' + localStorage.getItem('jwt'),
Authorization: localStorage.getItem('jwt'),
"Allow-Control-Allow-Origin": "*"
}
}),
@ -33,6 +35,7 @@ async function send(xhr, retryFunc) {
}
try {
const { data } = await xhr;
console.log("recv: ", data);
return {
...data,
networkStatus: 200
@ -43,16 +46,16 @@ async function send(xhr, retryFunc) {
networkStatus: err?.response?.status ?? -1,
status: false
};
if (err?.response?.status === 401) {
History.force('/login');
return failData;
}
waitToSend.push(retryFunc);
if (err.message === 'Network Error')
return await failed('您的设备似乎断网了,请检查网络后重试或刷新', flushWaitList) || failData;
else if (err?.response?.status === 401)
History.force('/login');
else if (err?.response?.status === 504)
if (err?.response?.status === 504)
return await failed('请求超时,请耐心等待几秒后重试或刷新', flushWaitList) || failData;
else
return await failed('服务器出现问题,请稍后重试或刷新', flushWaitList) || failData;
return failData;
return await failed('服务器出现问题,请稍后重试或刷新', flushWaitList) || failData;
}
}

查看文件

@ -1,4 +1,8 @@
import { Component } from 'react';
import { apis } from '../helper/apis';
import { post } from '../helper/axios';
import History from '../helper/history';
import Spinner from '../components/Spinner/Spinner';
import './login.css';
export class LogInContainer extends Component {
@ -7,6 +11,7 @@ export class LogInContainer extends Component {
this.state = {
username: '',
password: '',
processing: false,
error: false,
errorMessage: '',
};
@ -20,40 +25,57 @@ export class LogInContainer extends Component {
handleSubmit(e) {
e.preventDefault();
const { username, password } = this.state;
this.props.login(username, password);
if (!username)
return this.setState({ error: true, errorMessage: '学号不能为空' });
if (!password)
return this.setState({ error: true, errorMessage: '密码不能为空' });
if (!username.match(/^\d*$/))
return this.setState({ error: true, errorMessage: '学号必须为数字' });
this.setState({ processing: true });
post(apis.login, { username, password }).then(({ data, status, networkStatus }) => {
this.setState({ processing: false });
if (networkStatus !== 200) return;
if (!status) return this.setState({ error: true, errorMessage: data });
localStorage.setItem('jwt', data);
History.replace('/');
});
}
render() {
const { error, errorMessage } = this.state;
const { error, errorMessage, processing } = this.state;
return (
<div className="login">
<h1>Login</h1>
<h1>登录</h1>
<form onSubmit={this.handleSubmit.bind(this)}>
<div className="form-group">
<label htmlFor="username">Username</label>
<input
type="text"
name="username"
className="form-control"
placeholder="Username"
placeholder="学号"
onChange={this.handleChange.bind(this)}
/>
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input
type="password"
name="password"
className="form-control"
placeholder="Password"
placeholder="密码"
onChange={this.handleChange.bind(this)}
/>
</div>
<button type="submit" className="btn btn-primary">
Login
<button type="submit" className="btn btn-straight btn-sdu" disabled={processing || !this.state.username || !this.state.password}>
{
processing
? (
<Spinner />
)
: "登录"
}
</button>
{error &&
<div className="alert alert-danger">
<div className={"alert"}>
{errorMessage}
</div>}
</form>

查看文件

@ -2,6 +2,7 @@
"images": {
"poster": "image/poster.jpg",
"icon": "image/sdu_icon.png",
"name": "image/sdu_name.png"
"name": "image/sdu_name.png",
"avatar": "image/user.jpg"
}
}

查看文件

@ -8,26 +8,6 @@
background-color: #9D0004;
}
.sdu,
.user {
height: 100%;
display: flex;
align-items: center;
}
.sdu-logo,
.user-logo {
height: 100%;
}
.sdu-name {
height: 40px;
margin-left: 10px;
}
.user-name {
height: 100%;
line-height: 60px;
font-size: 24px;
}
.content {
width: 800px;
margin: 0 auto;

查看文件

@ -7,6 +7,7 @@ import { alert } from '../helper/alert';
import { images } from '../resources.json';
import './upload.css';
import UserControl from '../components/UserControl/UserControl';
export class UploadContainer extends Component {
constructor(props) {
@ -60,10 +61,7 @@ export class UploadContainer extends Component {
<img src={images.icon} className="sdu-logo" alt="logo" />
<img src={images.name} className="sdu-name" alt="" />
</div>
<div className="user">
<img src="" className="user-avatar" alt="avatar" />
<div className="user-name"></div>
</div>
<UserControl />
</div>
<div className="content">
<div className="message-box">