登录页面和我的页面初步

This commit is contained in:
禺狨 2023-06-25 15:19:43 +08:00
parent f93467db13
commit 5486507b3e
19 changed files with 349 additions and 32 deletions

View File

@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<title>PlayEdu</title>
</head>

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

1
public/js/DPlayer.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1
public/js/xg/hls.min.js vendored Normal file

File diff suppressed because one or more lines are too long

21
public/js/xg/index.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -41,7 +41,6 @@ export class HttpClient {
return Promise.resolve(response);
} else {
Toast.show({
icon: "fail",
content: msg,
});
}
@ -52,7 +51,6 @@ export class HttpClient {
let status = error.response.status;
if (status === 401) {
Toast.show({
icon: "fail",
content: "请重新登录",
});
GoLogin();

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

View File

@ -21,7 +21,7 @@ export const TabBarFooter: React.FC = () => {
) : (
<i
style={{ fontSize: 30, color: "#cccccc" }}
className="iconfont icon-waterprint"
className="iconfont icon-icon-shouye"
></i>
),
},

View File

@ -35,6 +35,12 @@ code {
height: 30px;
}
.main-body {
width: 100%;
float: left;
height: auto;
}
.adm-tab-bar-item-title {
font-size: 11px;
font-weight: 400;

View File

@ -0,0 +1,117 @@
.login-content {
position: fixed;
bottom: 0;
left: 0;
right: 0;
top: 0;
background-image: url("../../assets//images/login/bg.png");
background-size: 100% 100%;
.top-content {
width: 100%;
height: 150px;
box-sizing: border-box;
padding: 0px 20px;
display: flex;
justify-content: space-between;
align-items: center;
.title {
font-size: 24px;
font-weight: 600;
color: rgba(0, 0, 0, 0.88);
line-height: 24px;
}
}
.form-box {
width: 100%;
float: left;
height: auto;
box-sizing: border-box;
padding: 0px 20px;
margin-top: 30px;
.input-box {
width: 100%;
height: 109px;
background: #ffffff;
border-radius: 8px;
.input-item {
width: 100%;
height: 54px;
font-size: 16px;
font-weight: 400;
color: rgba(0, 0, 0, 0.3);
line-height: 54px;
box-sizing: border-box;
padding: 0px 15px;
}
.line {
width: auto;
height: 1px;
background: rgba(0, 0, 0, 0.05);
margin: 0px 15px;
}
}
.captcha-box {
width: 100%;
height: 54px;
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 20px;
.input-item {
width: 200px;
height: 54px;
background: #ffffff;
border-radius: 8px;
box-sizing: border-box;
padding: 0px 15px;
font-size: 16px;
font-weight: 400;
color: rgba(0, 0, 0, 0.3);
line-height: 54px;
}
.captcha-button {
width: 125px;
height: 54px;
border-radius: 4px;
overflow: hidden;
.catpcha-loading-box {
width: 125px;
height: 54px;
display: flex;
align-items: center;
justify-content: center;
}
.captcha {
width: 125px;
height: 54px;
border-radius: 4px;
}
}
}
.button-box {
width: 100%;
height: 54px;
margin-top: 30px;
.primary-button {
width: 100%;
height: 54px;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
}
}
.support-box {
position: fixed;
bottom: 90px;
left: 0;
right: 0;
font-size: 12px;
font-weight: 400;
color: rgba(0, 0, 0, 0.3);
line-height: 12px;
margin-top: 200px;
}
}
}

View File

@ -1,39 +1,165 @@
import { Button } from "antd-mobile";
import React, { useState, useEffect } from "react";
import { Button, Toast, SpinLoading, Input, Image } from "antd-mobile";
import styles from "./index.module.scss";
import { useDispatch, useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
import { login, system, user } from "../../api/index";
import { setToken } from "../../utils/index";
import { loginAction, logoutAction } from "../../store/user/loginUserSlice";
import banner from "../../assets/images/login/banner.png";
const LoginPage = () => {
const dispatch = useDispatch();
const navigate = useNavigate();
const [loading, setLoading] = useState<boolean>(false);
const [image, setImage] = useState<string>("");
const [email, setEmail] = useState<string>("");
const [password, setPassword] = useState<string>("");
const [captchaVal, setCaptchaVal] = useState<string>("");
const [captchaKey, setCaptchaKey] = useState<string>("");
const [captchaLoading, setCaptchaLoading] = useState(true);
const loginState = useSelector((state: any) => {
return state.loginUser.value;
});
return (
<>
<Button
onClick={() => {
dispatch(
loginAction({
user: {
name: "霸王",
},
})
);
}}
>
</Button>
useEffect(() => {
fetchImageCaptcha();
document.title = "登录";
}, []);
{loginState.isLogin && (
<Button
onClick={() => {
dispatch(logoutAction());
const fetchImageCaptcha = () => {
setCaptchaLoading(true);
system.imageCaptcha().then((res: any) => {
setImage(res.data.image);
setCaptchaKey(res.data.key);
setCaptchaLoading(false);
});
};
const loginSubmit = (e: any) => {
if (!email) {
Toast.show({
content: "请输入学员邮箱账号",
});
return;
}
if (!password) {
Toast.show({
content: "请输入密码",
});
return;
}
if (!captchaVal) {
Toast.show({
content: "请输入图形验证码",
});
return;
}
if (captchaVal.length < 4) {
Toast.show({
content: "图形验证码错误",
});
return;
}
if (loading) {
return;
}
handleSubmit();
};
const handleSubmit = () => {
if (loading) {
return;
}
setLoading(true);
login
.login(email, password, captchaKey, captchaVal)
.then((res: any) => {
const token = res.data.token;
setToken(token);
getUser();
})
.catch((e) => {
setLoading(false);
setCaptchaVal("");
fetchImageCaptcha();
});
};
const getUser = () => {
user.detail().then((res: any) => {
const data = res.data;
dispatch(loginAction(data));
setLoading(false);
navigate("/member", { replace: true });
});
};
return (
<div className={styles["login-content"]}>
<div className={styles["top-content"]}>
<div className={styles["title"]}></div>
<Image src={banner} width={150} height={150} />
</div>
<div className={styles["form-box"]}>
<div className={styles["input-box"]}>
<Input
className={styles["input-item"]}
placeholder="请输入学员邮箱账号"
value={email}
onChange={(val) => {
setEmail(val);
}}
>
{loginState.user.name}
</Button>
/>
<div className={styles["line"]}></div>
<Input
type="password"
className={styles["input-item"]}
placeholder="请输入密码"
value={password}
onChange={(val) => {
setPassword(val);
}}
/>
</div>
<div className={styles["captcha-box"]}>
<Input
value={captchaVal}
className={styles["input-item"]}
placeholder="请输入图形验证码"
onChange={(val) => {
setCaptchaVal(val);
}}
/>
<div className={styles["captcha-button"]}>
{captchaLoading && (
<div className={styles["catpcha-loading-box"]}>
<SpinLoading color="primary" />
</div>
)}
</>
{!captchaLoading && (
<Image
className={styles["captcha"]}
onClick={fetchImageCaptcha}
src={image}
/>
)}
</div>
</div>
<div className={styles["button-box"]}>
<Button
className={styles["primary-button"]}
disabled={captchaVal === "" || email === "" || password === ""}
color="primary"
loading={loading}
onClick={loginSubmit}
>
</Button>
</div>
<div className={styles["support-box"]}>PlayEdu提供技术支持</div>
</div>
</div>
);
};

View File

@ -0,0 +1,11 @@
.support-box {
position: fixed;
bottom: 90px;
left: 0;
right: 0;
font-size: 12px;
font-weight: 400;
color: rgba(0, 0, 0, 0.3);
line-height: 12px;
margin-top: 200px;
}

View File

@ -0,0 +1,32 @@
import { useEffect, useState } from "react";
import { user } from "../../api/index";
import styles from "./index.module.scss";
import { useSelector } from "react-redux";
import { TabBarFooter } from "../../components";
import moreIcon from "../../assets/images/commen/icon-more.png";
const MemberPage = () => {
const systemConfig = useSelector((state: any) => state.systemConfig.value);
const [loading, setLoading] = useState<boolean>(false);
const [tabKey, setTabKey] = useState(0);
const departments = useSelector(
(state: any) => state.loginUser.value.departments
);
const currentDepId = useSelector(
(state: any) => state.loginUser.value.currentDepId
);
useEffect(() => {
document.title = "我的";
}, []);
return (
<div className="main-body">
<div className={styles["content-box"]}></div>
<div className={styles["support-box"]}>PlayEdu提供技术支持</div>
<TabBarFooter></TabBarFooter>
</div>
);
};
export default MemberPage;

View File

@ -6,6 +6,7 @@ import { getToken } from "../utils";
import { InitPage } from "../pages/init";
import IndexPage from "../pages/index/index";
import LoginPage from "../pages/login";
import MemberPage from "../pages/member/index";
import PrivateRoute from "../components/private-route";
let RootPage: any = null;
@ -36,12 +37,16 @@ const routes: RouteObject[] = [
children: [
{
path: "/",
element: <IndexPage />,
element: <PrivateRoute Component={<IndexPage />} />,
},
{
path: "/login",
element: <LoginPage />,
},
{
path: "/member",
element: <PrivateRoute Component={<MemberPage />} />,
},
],
},
];