一、页面效果
1、密码登录
2、手机号验证码登录
3、修改密码
二、代码
这里只给出了页面实现的代码,具体的前端发送请求,后台接口的代码可以到github上克隆下来。
前端
后台
目录结构:
index.js
import { useState } from 'react';
import { Link, useHistory } from 'react-router-dom';
import { Form, Button, message, Tabs, Checkbox, Row, Col } from "antd";
import { pwdLogin, codeLogin } from "../../service/login";
import { LOGINWAY } from "../../utils/Enum";
import PwdLogin from "./PwdLogin";
import CodeLogin from "./CodeLogin";
import 'antd/dist/antd.css';
import './Login.css';
function Login() {
const history = useHistory(); // 使用useHistory做页面跳转导航
const [loginWay, setLogin] = useState(LOGINWAY.PWDLOGIN);
function onSubmit(values) {
loginWay === LOGINWAY.PWDLOGIN ? passwordLogin(values) : vertifyCodeLogin(values);
}
async function passwordLogin(values) {
try {
const response = await pwdLogin(values); // 发送登录请求
const { code, msg } = response;
if (code === 0) {
message.success(msg);
history.push('/'); // 登录成功后页面跳转
} else {
message.error(msg);
}
} catch (err) {
console.log(err);
message.error('请求错误');
}
return;
}
async function vertifyCodeLogin(values) {
try {
const response = await codeLogin(values); // 发送登录请求
const { code, msg } = response;
if (code === 0) {
message.success(msg);
} else {
message.error(msg);
}
} catch (err) {
console.log(err);
message.error('请求错误');
}
return;
}
return (
<div className="login">
<Form
onFinish={onSubmit}
>
<Tabs
defaultActiveKey="1"
onChange={(e) => { setLogin(parseInt(e)) }}
centered={true}
size='large'
>
<Tabs.TabPane key="1" tab="账号密码登录"></Tabs.TabPane>
<Tabs.TabPane key="0" tab="手机号登录"></Tabs.TabPane>
</Tabs>
{loginWay ? <PwdLogin /> : <CodeLogin />}
{loginWay ? <div style={{ "marginBottom": "24px", "textAlign": "left" }}>
<Checkbox>自动登录</Checkbox>
<span style={{ float: "right" }}><Link to='/editpwd'>忘记密码 ?</Link></span>
</div> : ' '}
<Form.Item>
<Row>
<Col span={11}>
<Button
block
size="large"
type='primary'
htmlType='submit'
>
登录
</Button>
</Col>
<Col span={2} />
<Col span={11}>
<Button
block
size="large"
>
<Link to='/sign'>注册</Link>
</Button>
</Col>
</Row>
</Form.Item>
</Form>
</div>
);
}
export default Login;
PwdLogin.js
import { Form, Input } from "antd";
import { EyeInvisibleOutlined, EyeTwoTone, UserOutlined, LockOutlined } from '@ant-design/icons';
function pwdLogin() {
return (
<>
<Form.Item
name="username"
rules={[
{
required: true,
message: "用户名不能为空",
}
]}
>
<Input
size="large"
autoComplete="off"
placeholder="用户名"
prefix={<UserOutlined />}
/>
</Form.Item>
<Form.Item
name="password"
rules={[
{
required: true,
message: "密码不能为空",
}, {
min: 5,
max: 10,
message: "请输入5-10位以内的密码"
}, {
pattern: '[0-9A-Za-z]',
message: "密码只能为数字或字母"
}
]}
>
<Input.Password
size="large"
autoComplete="off"
type="password"
placeholder="密码"
prefix={<LockOutlined />}
iconRender={visible => (visible ? <EyeTwoTone /> : <EyeInvisibleOutlined />)}
/>
</Form.Item>
</>
)
}
export default pwdLogin;
CodeLogin.js
import React, { useState } from 'react';
import { Form, Input, Row, Col, Button, message } from "antd";
import { MobileOutlined, MailOutlined } from '@ant-design/icons';
import { sendCode } from '../../service/login';
function CodeLogin() {
const [phoneNumber, setPoneNumber] = useState('');
const [buttonStatus, setButtonStatus] = useState(false);
const [content, setContent] = useState('获取验证码');
let timer;
async function getCode() { // 获取验证码
try {
const result = await sendCode({ phonenumber: phoneNumber });
const { code = 1, data = "error" } = result;
if (code === 0) {
message.success(`验证码为:${data}`);
} else {
message.error('用户不存在');
}
} catch (err) {
console.log(err);
message.error('请求失败');
}
}
function buttonClick() {
if (!phoneNumber) {
message.error('手机号为空!');
return;
}
getCode();
setContent('60s后重新获取');
setButtonStatus(true); // 点击获取按钮之后,按钮禁用
let index = 60;
timer = setInterval(() => { // 倒计时
index--;
setContent(`${index}s后重新获取`);
if (index === 0) {
clearInterval(timer);
index = 60;
setButtonStatus(false);
setContent('验证码');
}
}, 1000);
}
function inputNumber(e) {
const { value = 'error' } = e.target;
setPoneNumber(value);
}
return (
<>
<Form.Item
name="phonenumber"
rules={[
{
required: true,
message: "手机号码不能为空",
}, {
pattern: "^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\\d{8}$",
message: "请输入正确的手机号码"
}
]}
>
<Input
autoComplete="off"
size="large"
placeholder="手机号"
prefix={<MobileOutlined />}
onChange={inputNumber} />
</Form.Item>
<Form.Item
name="verifyCode"
rules={[
{
required: true,
message: "验证码不能为空"
}
]}
>
<Row>
<Col span={14}>
<Input
size="large"
autoComplete="off"
placeholder="验证码"
prefix={<MailOutlined />}
/>
</Col>
<Col span={1} />
<Col span={9}>
<Button
size="large"
block
disabled={buttonStatus}
onClick={buttonClick}
>
{content}
</Button>
</Col>
</Row>
</Form.Item>
</>
)
}
export default CodeLogin;
修改密码:
EditPwd.js
import { useState } from 'react';
import { Link } from 'react-router-dom';
import { Form, Tabs, Input, Button, Row, Col, message } from 'antd';
import { EyeInvisibleOutlined, EyeTwoTone, LockOutlined, MobileOutlined, MailOutlined } from '@ant-design/icons';
import { sendCode } from '../../service/login';
import { editpwd } from '../../service/editpwd';
import { RES_CODES } from '../../utils/Enum';
import './Edit.css';
function EditPwd() {
const [phoneNumber, setPoneNumber] = useState('');
const [buttonStatus, setButtonStatus] = useState(false);
const [content, setContent] = useState('获取验证码');
let timer;
async function onSubmit(values) { // 修改密码
if (Reflect.has(values, 'confirm_password')) {
Reflect.deleteProperty(values, 'confirm_password');
}
try {
const result = await editpwd(values);
const { code, msg } = result;
if (code === RES_CODES.SUCCESS) {
message.success(msg);
} else {
message.error(msg);
}
} catch (err) {
console.log(err);
message.error('请求错误');
}
}
async function getCode() { // 获取验证码
try {
const vertifyCode = await sendCode({ phonenumber: phoneNumber });
const { code, data } = vertifyCode;
if (code === RES_CODES.SUCCESS) {
message.success(`验证码为: ${data}`);
} else {
message.error('请求错误');
}
} catch (err) {
console.log(err);
message.error('请求错误');
}
}
function inputNumber(e) {
const { value = 'error' } = e.target;
setPoneNumber(value);
}
function buttonClick() { // 获取验证码点击事件
if (!phoneNumber) {
message.error('手机号为空!');
return;
}
getCode();
setContent('60s后重新获取');
setButtonStatus(true);
let index = 60;
timer = setInterval(() => {
index--;
setContent(`${index}s后重新获取`);
if (index === 0) {
clearInterval(timer);
index = 60;
setButtonStatus(false);
setContent('验证码');
}
}, 1000);
}
return (
<div className="editpwd">
<Form onFinish={onSubmit}>
<Tabs centered='true' size='large'>
<Tabs.TabPane tab="修改密码"></Tabs.TabPane>
</Tabs>
<Form.Item
name="phonenumber"
rules={[
{
required: true,
message: "手机号不能为空",
}, {
pattern: "^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\\d{8}$",
message: "请输入正确的手机号"
}
]}
>
<Input
size='large'
placeholder="手机号"
prefix={<MobileOutlined />}
onChange={inputNumber}
/>
</Form.Item>
<Form.Item
name="verifyCode"
rules={[
{
required: true,
message: "验证码不能为空"
}
]}
>
<Row>
<Col span={14}>
<Input
size="large"
autoComplete="off"
placeholder="验证码"
prefix={<MailOutlined />}
/>
</Col>
<Col span={1} />
<Col span={9}>
<Button
size="large"
block
disabled={buttonStatus}
onClick={buttonClick}
>
{content}
</Button>
</Col>
</Row>
</Form.Item>
<Form.Item
name="password"
rules={[
{
required: true,
message: '密码不能为空'
}, {
min: 5,
max: 10,
message: '密码长度为5-10'
}, {
pattern: '[0-9A-Za-z]',
message: "密码只能为数字或字母"
}
]}
>
<Input.Password
size='large'
placeholder="新密码"
prefix={<LockOutlined />}
iconRender={visible => (visible ? <EyeTwoTone /> : <EyeInvisibleOutlined />)}
/>
</Form.Item>
<Form.Item
name="confirm_password"
dependencies={["password"]}
rules={[
{
required: true,
message: '密码不能为空'
}, {
min: 5,
max: 10,
message: '密码长度为5-10'
}, {
pattern: '[0-9A-Za-z]',
message: "密码只能为数字或字母"
},
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue('password') === value) {
return Promise.resolve();
}
return Promise.reject(new Error('两次输入的密码不一致'));
}
}),
]}
>
<Input.Password
size='large'
placeholder="再次输入新密码"
prefix={<LockOutlined />}
iconRender={visible => (visible ? <EyeTwoTone /> : <EyeInvisibleOutlined />)}
/>
</Form.Item>
<Form.Item>
<Button
size="large"
className="login-form-button"
type='primary'
htmlType='submit'
>
修改密码
</Button>
</Form.Item>
<Form.Item>
<Row>
<Col span={11}>
<Button
block
size="large"
>
<Link to='/login'>登录</Link>
</Button>
</Col>
<Col span={2} />
<Col span={11}>
<Button
size="large"
className="login-form-button"
>
<Link to='/sign'>注册</Link>
</Button>
</Col>
</Row>
</Form.Item>
</Form>
</div>
)
}
export default EditPwd;