提交 6f13e17d 作者: ZhangLingKun

功能:登录注册

上级 b73b397e
......@@ -2125,7 +2125,7 @@ packages:
version: 7.22.5
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': registry.npmmirror.com/@babel/types@7.23.0
'@babel/types': 7.23.0
dev: false
registry.npmmirror.com/@babel/helper-module-imports@7.22.15:
......@@ -2134,7 +2134,7 @@ packages:
version: 7.22.15
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': registry.npmmirror.com/@babel/types@7.23.0
'@babel/types': 7.23.0
dev: false
registry.npmmirror.com/@babel/helper-plugin-utils@7.22.5:
......@@ -2144,20 +2144,6 @@ packages:
engines: {node: '>=6.9.0'}
dev: false
registry.npmmirror.com/@babel/helper-string-parser@7.22.5:
resolution: {integrity: sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz}
name: '@babel/helper-string-parser'
version: 7.22.5
engines: {node: '>=6.9.0'}
dev: false
registry.npmmirror.com/@babel/helper-validator-identifier@7.22.20:
resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz}
name: '@babel/helper-validator-identifier'
version: 7.22.20
engines: {node: '>=6.9.0'}
dev: false
registry.npmmirror.com/@babel/plugin-syntax-jsx@7.22.5(@babel/core@7.23.2):
resolution: {integrity: sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz}
id: registry.npmmirror.com/@babel/plugin-syntax-jsx/7.22.5
......@@ -2179,17 +2165,6 @@ packages:
dependencies:
regenerator-runtime: registry.npmmirror.com/regenerator-runtime@0.14.0
registry.npmmirror.com/@babel/types@7.23.0:
resolution: {integrity: sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@babel/types/-/types-7.23.0.tgz}
name: '@babel/types'
version: 7.23.0
engines: {node: '>=6.9.0'}
dependencies:
'@babel/helper-string-parser': registry.npmmirror.com/@babel/helper-string-parser@7.22.5
'@babel/helper-validator-identifier': registry.npmmirror.com/@babel/helper-validator-identifier@7.22.20
to-fast-properties: registry.npmmirror.com/to-fast-properties@2.0.0
dev: false
registry.npmmirror.com/@ctrl/tinycolor@3.6.1:
resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz}
name: '@ctrl/tinycolor'
......@@ -3708,7 +3683,7 @@ packages:
optional: true
dependencies:
'@typescript-eslint/parser': registry.npmmirror.com/@typescript-eslint/parser@6.10.0(eslint@8.0.0)(typescript@5.0.2)
debug: registry.npmmirror.com/debug@3.2.7
debug: 3.2.7
eslint: registry.npmmirror.com/eslint@8.0.0
eslint-import-resolver-node: registry.npmmirror.com/eslint-import-resolver-node@0.3.9
eslint-import-resolver-typescript: registry.npmmirror.com/eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.10.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.0)(eslint@8.0.0)
......@@ -6510,13 +6485,6 @@ packages:
engines: {node: '>=12'}
dev: true
registry.npmmirror.com/to-fast-properties@2.0.0:
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz}
name: to-fast-properties
version: 2.0.0
engines: {node: '>=4'}
dev: false
registry.npmmirror.com/to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz}
name: to-regex-range
......
......@@ -89,3 +89,19 @@ export type GetAccountInfo = InterFunction<
createTime: string;
}
>;
// 测试-手机号登录
export type TestPhoneLogin = InterFunction<
{
phone: string;
},
{
authStatus: null;
nickName: string;
phoneNum: string;
portType: number;
sessionKey: null;
token: string;
uid: string;
userAccountId: number;
}
>;
......@@ -2,6 +2,7 @@ import {
GetAccountInfo,
GetAppletQRCode,
GetLoginInfo,
TestPhoneLogin,
} from '@/api/interface/common';
import request from '../request';
......@@ -25,4 +26,8 @@ export class CommonAPI {
// 获取用户信息
static getAccountInfo: GetAccountInfo = (params) =>
request.get('/userapp/user-account/info', { params });
// 测试-手机号登录
static testPhoneLogin: TestPhoneLogin = (params) =>
request.get('/userapp/auth/testPhoneLogin', { params });
}
......@@ -56,14 +56,15 @@ service.interceptors.response.use(
const isServer = typeof window === 'undefined';
if (isServer) {
// 如果是服务端
return Promise.reject(data);
// eslint-disable-next-line no-alert
window.confirm(data.message || '啊呀,出错了');
// window.confirm(data.message || '啊呀,出错了');
// eslint-disable-next-line no-restricted-globals
history.back();
} else {
// 如果还有其他报错那么就弹出报错信息(不需要对每个接口的报错做单独判断)
message.error(data.message || '啊呀,出错了').then();
// history.back();
}
// 如果还有其他报错那么就弹出报错信息(不需要对每个接口的报错做单独判断)
message.error(data.message || '啊呀,出错了').then();
return Promise.reject(data);
}
// 网络错误或链接超时
......
import React, { useEffect, useState } from 'react';
import { ReloadOutlined } from '@ant-design/icons';
import { message, Modal } from 'antd';
import Cookies from 'js-cookie';
import { useDispatch, useSelector } from 'react-redux';
import styled from 'styled-components';
import { CommonAPI } from '@/api';
import { RootState } from '@/store';
import { GlobalDataState } from '@/store/module/globalData';
import { setSystem } from '@/store/module/system';
import { setUserInfo } from '@/store/module/userInfo';
export const LoginModalWrap = styled.div`
position: relative;
width: 100%;
display: flex;
align-items: center;
justify-content: flex-start;
flex-direction: column;
box-sizing: border-box;
padding: 0.68rem 0;
.qrcode {
position: relative;
width: 10.68rem;
height: 10.68rem;
margin: 1.5rem 0 1rem 0;
//background-image: url('https://file.iuav.com/file/sharefly-qrcode-wx.jpg');
//background-size: 100% 100%;
//background-size: cover;
//background-position: center;
.image {
width: 100%;
height: 100%;
object-fit: cover;
}
.shadow {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
flex-direction: column;
background: rgba(0, 0, 0, 0.68);
.refresh {
position: relative;
width: 3rem;
height: 3rem;
border-radius: 50%;
background: #fff;
margin-bottom: 1rem;
&:active {
filter: brightness(0.9);
transform: rotate(360deg);
transition: all 0.3s ease-in-out;
}
}
.text {
color: #fff;
}
}
}
.title {
color: #222;
font-size: 16px;
font-weight: bold;
}
.text {
color: #333;
font-size: 12px;
line-height: 20px;
text-align: center;
}
.action {
color: #999;
font-size: 12px;
line-height: 20px;
text-align: center;
margin: 1rem 0;
text-decoration: underline;
cursor: pointer;
&:hover,
&:active {
color: #ff552d;
}
}
`;
// 定时器暂存
let timer: NodeJS.Timer;
const LoginModalView = ({
open,
onCancel,
}: {
open: boolean;
onCancel: () => void;
}) => {
// system
const globalData = useSelector(
(state: RootState) => state.globalData,
) as GlobalDataState;
// store
const dispatch = useDispatch();
// 获取小程序二维码唯一标识
const [randomLoginCode, setRandomLoginCode] = useState<string>(
`${parseInt(String(Math.random() * 10001), 10)}`,
);
// 二维码是否过期
const [qrCodeExpired, setQrCodeExpired] = useState<boolean>(false);
// 登录二维码的地址
const [qrCodeData, setQrCodeData] = useState<string>();
// 获取登录二维码
const getQrcodeLogin = async () => {
// 获取二维码
const res = await CommonAPI.getAppletQRCode({
page: 'page-identity/identity-empower/index',
scene: `randomLoginCode=${randomLoginCode}&port=0`,
});
if (res && res.code === '200') {
if (!res.result) {
message.warning('获取登录二维码失败');
return;
}
// 设置当前登录的二维码
setQrCodeData(`data:image/png;base64,${res.result}`);
// 设置二维码倒计时
setQrCodeExpiredTimer();
}
};
// 跳转管理平台
const handleBackEnd = () => {
window.open('https://admin.iuav.com');
};
// 刷新二维码
const handleRefresh = () => {
setRandomLoginCode(`${parseInt(String(Math.random() * 10001), 10)}`);
getQrcodeLogin().then(() => {
setQrCodeExpired(false);
});
};
// 定时器设置二维码过期
const setQrCodeExpiredTimer = () => {
setTimeout(
() => {
setQrCodeExpired(true);
// 关闭定时器
if (timer) clearInterval(timer);
},
1000 * 60 * 5,
);
};
// 获取登录信息
const getLoginInfo = async () => {
if (!randomLoginCode) return;
const res = await CommonAPI.getLoginInfo({
randomLoginCode,
});
// console.log('获取登录信息 --->', res);
if (res && res.code === '200') {
// 关闭定时器
if (timer) clearInterval(timer);
// 刷新二维码
setQrCodeExpired(true);
// 关闭弹窗
onCancel?.();
// 设置用户信息
dispatch(setUserInfo(res.result));
// 设置token
dispatch(setSystem({ token: res.result.token }));
// 设置token
Cookies.set('SHAREFLY-WEB-TOKEN', res.result.token);
message.success('登录成功');
// 刷新当前页面
window.location.reload();
}
};
// 设置定时器轮询获取信息
const setLoginInfoTimer = () => {
timer = setInterval(async () => {
await getLoginInfo();
}, 2500);
};
// 关闭弹窗
const handleClose = () => {
onCancel?.();
// 关闭定时器
if (timer) clearInterval(timer);
};
// 组件挂载
useEffect(() => {
if (!open) {
// 关闭定时器
if (timer) clearInterval(timer);
return;
}
// 获取二维码
getQrcodeLogin().then(() => {
setQrCodeExpired(false);
setLoginInfoTimer();
});
}, [open]);
return (
<Modal open={open} footer={null} onCancel={handleClose}>
<LoginModalWrap>
<div className="title">
{globalData?.loginModalTitle || `微信扫码登录`}
</div>
<div className="qrcode">
{qrCodeData && (
<img src={qrCodeData} alt="登录二维码" className="image" />
)}
{qrCodeExpired && (
<div className="flex-center animate__animated animate__fast animate__fadeIn shadow">
<div className="refresh flex-center" onClick={handleRefresh}>
<ReloadOutlined style={{ fontSize: '20px' }} />
</div>
<div className="text">二维码已过期,请重新扫描</div>
</div>
)}
</div>
<div className="text">微信扫一扫,打开小程序</div>
<div className="text">即可登录/注册</div>
<div
className="action"
onClick={handleBackEnd}
style={{ visibility: 'hidden' }}
>
管理平台登录 {'>'}
</div>
<div className="text">「云享飞,让天空为世界所用」</div>
</LoginModalWrap>
</Modal>
);
};
export default LoginModalView;
......@@ -169,10 +169,11 @@ const MallCartSubmitWrap = styled.div`
.submit-remark {
position: relative;
width: 100%;
min-height: 4.5rem;
min-height: 4rem;
background: #f2f7ff;
border: 0.04rem solid #d0eaf5;
padding: 0.67rem;
padding: 0.67rem 0.67rem 1.3rem 0.67rem;
box-sizing: border-box;
margin-bottom: 1rem;
.remark-view {
position: relative;
......
import React, { useEffect, useState } from 'react';
import { Button, Checkbox, Col, Form, Input, message, Row } from 'antd';
import { useDispatch, useSelector } from 'react-redux';
import styled from 'styled-components';
import LayoutView from '@/components/layout';
import { RootState } from '@/store';
import { setGlobalData } from '@/store/module/globalData';
import { SystemState } from '@/store/module/system';
const UserSignupView = () => {
// store
const dispatch = useDispatch();
// system
const system = useSelector((state: RootState) => state.system) as SystemState;
// 表单钩子
const [formRef] = Form.useForm<{
password: string;
username: string;
code: string;
}>();
// 是否选择协议
const [checkValue, setCheckValue] = useState<boolean>(false);
// 提交数据
const handleSubmit = async () => {
if (!checkValue) {
await message.warning('请先阅读并接受用户协议和隐私协议');
return;
}
const values = await formRef.validateFields().catch((err) => {
Promise.all(
err?.errorFields?.map((i: { errors: string[] }) =>
message.warning(i?.errors[0]),
),
);
});
if (!values) return;
message.loading('注册中...');
};
// 跳转回登录
const handleLogin = () => {
dispatch(setGlobalData({ loginModalVisible: true }));
};
// 获取二维码
const handleGetCode = async () => {
await message.loading('获取中...');
};
// 页面挂载
useEffect(() => {
if (!system?.token) return;
// 如果有token则跳转回首页
window.location.href = '/';
}, [system]);
return (
<LayoutView placeholder={false}>
<UserSignupBg />
<UserSignupWrap>
<div className="login-title"></div>
<div className="login-box">
<div className="title">欢迎注册</div>
<div className="already mb-14">
<span>已有账号?</span>
<span className="bold cursor-pointer" onClick={handleLogin}>
登录
</span>
</div>
<Form
name="signForm"
form={formRef}
autoComplete="off"
className="w-full"
size="large"
labelAlign="left"
labelCol={{ span: 4 }}
>
<Form.Item
label="手机号"
name="username"
required={false}
rules={[{ required: true, message: '请输入登录的账号' }]}
>
<Input placeholder="请输入手机号" maxLength={11} allowClear />
</Form.Item>
<Form.Item
label="密码"
name="password"
required={false}
rules={[{ required: true, message: '请输入密码' }]}
>
<Input
placeholder="请输入密码"
type="password"
maxLength={20}
allowClear
autoComplete="new-password"
/>
</Form.Item>
<Form.Item label="验证码">
<Row gutter={8}>
<Col span={15}>
<Form.Item
name="code"
noStyle
rules={[
{
required: true,
message: '请输入验证码',
},
]}
>
<Input
placeholder="请输入验证码"
maxLength={8}
allowClear
/>
</Form.Item>
</Col>
<Col span={8}>
<Button onClick={handleGetCode}>获取验证码</Button>
</Col>
</Row>
</Form.Item>
</Form>
<div
className={`submit mt-14 cursor-pointer ${checkValue && 'active'}`}
onClick={handleSubmit}
>
立即注册
</div>
<div className="checkbox mt-4">
<Checkbox
checked={checkValue}
onChange={(e) => setCheckValue(e.target?.checked)}
>
<span>阅读并接受</span>
<span className="bold cursor-pointer">云享飞用户协议</span>
<span></span>
<span className="bold cursor-pointer">隐私协议</span>
</Checkbox>
</div>
</div>
</UserSignupWrap>
</LayoutView>
);
};
export default UserSignupView;
// 样式
const UserSignupWrap = styled.div`
position: relative;
height: 99.8vh;
max-width: 1190px;
margin: 0 auto;
display: flex;
align-items: center;
justify-content: flex-end;
box-sizing: border-box;
padding: 0 5% 0 0;
.login-title {
position: absolute;
top: 15%;
left: 0;
width: 9.25rem;
height: 2.08rem;
background-image: url('https://file.iuav.com/file/sharefly-signup-title.png');
background-size: cover;
}
.login-box {
position: relative;
width: 23.29rem;
height: 28.5rem;
background: rgba(255, 255, 255, 0.86);
border-radius: 0.58rem;
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
padding: 1.83rem 1.83rem 0;
.title {
position: relative;
width: 100%;
font-size: 20px;
font-weight: bold;
color: #333333;
letter-spacing: 1px;
margin-bottom: 0.2rem;
}
.already {
position: relative;
width: 100%;
color: #999999;
.bold {
color: #fd562c;
}
}
.submit {
position: relative;
box-sizing: border-box;
width: 19.38rem;
height: 2.5rem;
background: #ffab95;
border-radius: 1.29rem;
text-align: center;
line-height: 2.25rem;
color: #ffffff;
}
.active {
background: #fd562c;
}
.checkbox {
.bold {
color: #fd562c;
margin: 0 0.25rem;
}
}
}
@media screen and (max-width: 1200px) {
padding: 0;
justify-content: center;
}
@media screen and (min-width: 1550px) {
padding: 0;
}
`;
// 图片
const UserSignupBg = styled.div`
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 99.8vh;
background-image: url('https://file.iuav.com/file/sharefly-signup-bg.png');
background-size: cover;
`;
......@@ -16,6 +16,12 @@ module.exports = {
screens: {
xl: '1190px',
},
colors: {
333: '#333',
777: '#777',
999: '#999',
aaa: '#aaa',
},
},
},
plugins: [],
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论