feat: 登录

This commit is contained in:
mozzie 2023-03-03 16:21:45 +08:00
parent 166986e31f
commit e8da3e4c5a
6 changed files with 371 additions and 70 deletions

View File

@ -17,11 +17,6 @@ body {
#bs-app { #bs-app {
position: relative; position: relative;
> main {
position: absolute;
left: 0;
right: 0;
}
} }
@keyframes gradient { @keyframes gradient {

View File

@ -64,3 +64,10 @@ header {
} }
} }
} }
.sms-group {
display: grid;
grid-template-columns: 2fr 1fr;
column-gap: 10px;
align-items: center;
}

View File

@ -1,11 +1,60 @@
import "./index.less"; import "./index.less";
import { Input, Space } from "@arco-design/web-react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { routerList } from "../../router"; import { routerList } from "../../router";
import {
Input,
Modal,
Form,
Message,
Button,
Space,
Radio,
Tooltip,
} from "@arco-design/web-react";
import FormItem from "@arco-design/web-react/es/Form/form-item";
const InputSearch = Input.Search; const InputSearch = Input.Search;
const RadioGroup = Radio.Group;
import { useEffect, useRef, useState } from "react";
import Row from "@arco-design/web-react/es/Table/summary/row";
import Col from "@arco-design/web-react/es/Grid/col";
type TLoginMethod = "usePass" | "useSms";
const DURATION = 120; // 验证码倒计时
function Nav() { function Nav() {
const navigate = useNavigate(); const navigate = useNavigate();
const [loginForm] = Form.useForm();
const [visible, setVisible] = useState(false);
const [confirmLoading, setConfirmLoading] = useState(false);
const [loginMethod, setLoginMethod] = useState<TLoginMethod>("useSms");
let [countdown, setCountdown] = useState(DURATION);
const timer = useRef<any>();
const onOk = () => {
loginForm.validate().then((res) => {
setConfirmLoading(true);
setTimeout(() => {
Message.success("Success !");
setVisible(false);
setConfirmLoading(false);
}, 1500);
});
};
const onClickSmsBtn = () => {
setTimeout(() => {
Message.success("验证码已发送");
timer.current = setInterval(() => setCountdown(countdown--), 1000);
}, 500);
};
useEffect(() => {
if (countdown === 0) {
clearInterval(timer.current);
setCountdown(DURATION);
}
}, [countdown]);
return ( return (
<header> <header>
@ -34,8 +83,57 @@ function Nav() {
<InputSearch allowClear placeholder="搜索" style={{ width: 150 }} /> <InputSearch allowClear placeholder="搜索" style={{ width: 150 }} />
</div> </div>
<div className="end"> <div className="end">
<span></span> <span onClick={() => setVisible(true)}></span>
<span></span> <Modal
title={
<RadioGroup
type="button"
defaultValue="useSms"
onChange={(e) => setLoginMethod(e)}
>
<Radio value="useSms"></Radio>
<Radio value="usePass"></Radio>
</RadioGroup>
}
style={{ width: "360px" }}
visible={visible}
onOk={onOk}
okText="登录"
cancelText="取消"
closeIcon={false}
confirmLoading={confirmLoading}
onCancel={() => setVisible(false)}
>
<Form form={loginForm} layout="vertical">
<FormItem field="用户名" rules={[{ required: true }]} label="">
<Input size="large" placeholder="用户名/手机号" />
</FormItem>
{loginMethod === "useSms" ? (
<FormItem required style={{ marginBottom: 0 }}>
<div className="sms-group">
<Input size="large" placeholder="验证码" type="text" />
<Button
size="large"
type="primary"
onClick={onClickSmsBtn}
disabled={countdown !== DURATION}
>
{countdown === DURATION ? "获取验证码" : `${countdown}s`}
</Button>
</div>
</FormItem>
) : (
<FormItem
field="密码"
rules={[{ required: true }]}
style={{ marginBottom: 0 }}
label=""
>
<Input size="large" type="password" placeholder="密码" />
</FormItem>
)}
</Form>
</Modal>
</div> </div>
</nav> </nav>
</header> </header>

View File

@ -0,0 +1,50 @@
import { Form, Input, Message, Modal } from "@arco-design/web-react";
import FormItem from "@arco-design/web-react/es/Form/form-item";
import { useState } from "react";
function LoginModal() {
const [loginForm] = Form.useForm();
const [visible, setVisible] = useState(false);
const [confirmLoading, setConfirmLoading] = useState(false);
const onOk = () => {
loginForm.validate().then((res) => {
setConfirmLoading(true);
setTimeout(() => {
Message.success("Success !");
setVisible(false);
setConfirmLoading(false);
}, 1500);
});
};
return (
<Modal
style={{ width: "400px" }}
visible={visible}
onOk={onOk}
okText="登录"
cancelText="取消"
closeIcon={false}
confirmLoading={confirmLoading}
onCancel={() => setVisible(false)}
>
<Form form={loginForm} layout="vertical">
<FormItem field="username" rules={[{ required: true }]} label="">
<Input placeholder="用户名/手机号" />
</FormItem>
<FormItem
required
field="password"
rules={[{ required: true }]}
style={{ marginBottom: 0 }}
label=""
>
<Input placeholder="密码" type="password" />
</FormItem>
</Form>
</Modal>
);
}
export default LoginModal;

View File

@ -1,43 +1,132 @@
.subscribe { .subscribe {
padding: 100px 0 20px 0; padding-top: 100px;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
// background: linear-gradient(
// to right bottom,
// hsl(0deg 0% 100%),
// hsl(222deg 92% 65% / 13%)
// );
// background: linear-gradient(
// to right bottom,
// hsl(0, 0%, 100%),
// hsl(0deg 0% 0% / 21%)
// );
background-repeat: no-repeat;
background-position: center;
background-size: cover;
background-image: url(https://images.unsplash.com/photo-1483794344563-d27a8d18014e?ixlib=rb-0.3.5&s=62d4e79…&auto=format&fit=crop&w=1950&q=80);
h2 { h2 {
text-align: center; font-size: 24px;
} }
h4 { h4 {
text-align: center;
font-weight: 400; font-weight: 400;
color: var(--color-text-4); color: var(--color-text-3);
}
} }
.options { .options {
padding-top: 100px; margin-top: 100px;
display: grid; position: relative;
grid-template-columns: 1fr 1fr 1fr; display: flex;
column-gap: 20px;
> section { > section {
position: relative;
width: 30%;
padding: 40px; padding: 40px;
text-align: center; &.popular {
position: absolute;
right: 5%;
width: 35%;
height: 120%;
top: -10%;
background: #fff;
box-shadow: 0 0.75rem 2rem 0 rgba(0, 0, 0, 0.1);
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.125);
.sell {
color: rgb(var(--primary-5));
}
}
.original {
color: var(--color-text-3);
font-size: 16px;
text-decoration: line-through;
font-weight: 300;
letter-spacing: 3px;
}
.price { .price {
position: relative;
display: inline-block;
font-family: DINCondensed-Bold, "Century Gothic", CenturyGothic, font-family: DINCondensed-Bold, "Century Gothic", CenturyGothic,
AppleGothic, sans-serif; AppleGothic, sans-serif;
font-weight: bold; font-weight: bold;
font-size: 48px; font-size: 48px;
color: var(--color-text-2); color: var(--color-text-2);
line-height: 1;
margin-top: 16px;
letter-spacing: 1px; letter-spacing: 1px;
line-height: 1;
&::before {
position: absolute;
content: "¥";
left: -20px;
top: 0;
font-size: 20px;
}
} }
h3 { h3 {
margin: 40px 0 0 0;
font-size: 18px; font-size: 18px;
font-weight: bold; font-weight: bold;
color: var(--color-text-2); color: var(--color-text-2);
letter-spacing: 5px; letter-spacing: 5px;
margin-top: 40px;
} }
p { p {
margin: 10px 0 30px 0;
color: var(--color-text-3); color: var(--color-text-3);
letter-spacing: 1px; letter-spacing: 1px;
line-height: 1.9; line-height: 1.9;
} }
ul {
margin-top: 30px;
list-style: none;
padding: 0;
li {
display: flex;
align-items: center;
color: var(--color-text-2);
margin-bottom: 10px;
span {
color: var(--color-text-4);
}
div {
padding-left: 10px;
span {
padding-left: 10px;
} }
} }
} }
}
}
}
.overlay {
width: 100%;
padding: 20px;
background: rgba(255, 255, 255, 0.375);
box-shadow: 0 0.75rem 2rem 0 rgba(0, 0, 0, 0.1);
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.125);
}
.text-gradient {
background-image: linear-gradient(
45deg,
hsl(357, 95%, 50%) 25%,
hsl(417, 95%, 50%)
);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}

View File

@ -1,41 +1,103 @@
import { Button } from "@arco-design/web-react"; import { Button } from "@arco-design/web-react";
import Checkmark12Filled from "@ricons/fluent/Checkmark12Filled";
import { Icon } from "@ricons/utils";
import "./index.less"; import "./index.less";
// 季度:三个月内,在线学习 ninghao.net 上的所有课程,通过高效的内容,快速掌握各种软件应用开发技术。 // 季度:三个月内,在线学习 ninghao.net 上的所有课程,通过高效的内容,快速掌握各种软件应用开发技术。
function Subscribe() { function Subscribe() {
return ( return (
<div className="container subscribe"> <div className="subscribe">
<div className="container">
<h2></h2> <h2></h2>
<h4></h4> <h4></h4>
<div className="options"> <div className="options overlay">
<section className="bs-shadow"> <section>
<h3></h3> <div className="original">1,299</div>
<div className="price">199</div> <div className="price">199</div>
<h3></h3>
<p> <p>
线 ninghao.net 线 ninghao.net
</p> </p>
<Button></Button> <Button type="outline"></Button>
<ul>
<li>
<Icon size={20}>
<Checkmark12Filled />
</Icon>
<div>
<span></span>
</div>
</li>
<li>
<Icon size={20}>
<Checkmark12Filled />
</Icon>
<div>
<span></span>
</div>
</li>
</ul>
</section> </section>
<section className="bs-shadow"> <section>
<h3></h3> <div className="original">1,299</div>
<div className="price">299</div> <div className="price">299</div>
<p>
线 ninghao.net
</p>
<Button></Button>
</section>
<section className="bs-shadow">
<h3></h3> <h3></h3>
<div className="price">399</div>
<p> <p>
线 ninghao.net 线 ninghao.net
</p> </p>
<Button></Button> <Button type="outline"></Button>
<ul>
<li>
<Icon size={20}>
<Checkmark12Filled />
</Icon>
<div>
<span></span>
</div>
</li>
<li>
<Icon size={20}>
<Checkmark12Filled />
</Icon>
<div>
<span></span>
</div>
</li>
</ul>
</section> </section>
{/* popular */}
<section className="popular">
<div className="original">1,299</div>
<div className="price">399</div>
<h3></h3>
<p>
线 ninghao.net
</p>
<Button type="primary"></Button>
<ul>
<li>
<Icon size={20}>
<Checkmark12Filled />
</Icon>
<div>
<span></span>
</div>
</li>
<li>
<Icon size={20}>
<Checkmark12Filled />
</Icon>
<div>
<span></span>
</div>
</li>
</ul>
</section>
</div>
</div> </div>
</div> </div>
); );