feat: 通用平台登录页更新

develop
JINGYJ 1 year ago
parent 67fac9673f
commit d13742c852

@ -18,7 +18,7 @@ export default [
{
name: 'login',
path: '/user/login',
component: './User/Login',
component: './User/Login/index1',
},
],
},

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

@ -0,0 +1,538 @@
// import Footer from '@/components/Footer';
import { login } from '@/services/ant-design-pro/api';
import { getFakeCaptcha } from '@/services/ant-design-pro/login';
import {
KeyOutlined,
LockOutlined,
MobileOutlined,
UserOutlined,
} from '@ant-design/icons';
import {
LoginForm,
LoginFormPage,
ProConfigProvider,
ProFormCaptcha,
ProFormCheckbox,
ProFormText,
} from '@ant-design/pro-components';
import { useEmotionCss } from '@ant-design/use-emotion-css';
import { FormattedMessage, history, SelectLang, useIntl, useModel, Helmet } from '@umijs/max';
import {Alert, Image, message, theme} from 'antd';
import Settings from '../../../../config/defaultSettings';
import React, {useEffect, useState} from 'react';
import { flushSync } from 'react-dom';
import styles from './login1.less'
import {postBaseCaptcha, postBaseLogin} from "@/services/system/Base";
import {postMenuGetMenu} from "@/services/system/Menu";
import {getLocale} from "@@/exports";
import {getAllRouteNameTile} from "@/utils/common";
import {addLocale} from "@@/plugin-locale";
import zhCN from "@/locales/zh-CN";
import Logo from "../../../../public/sst_logo.png"
// const ActionIcons = () => {
// const langClassName = useEmotionCss(({ token }) => {
// return {
// marginLeft: '8px',
// color: 'rgba(0, 0, 0, 0.2)',
// fontSize: '24px',
// verticalAlign: 'middle',
// cursor: 'pointer',
// transition: 'color 0.3s',
// '&:hover': {
// color: token.colorPrimaryActive,
// },
// };
// });
// return (
// <>
// <AlipayCircleOutlined key="AlipayCircleOutlined" className={langClassName} />
// <TaobaoCircleOutlined key="TaobaoCircleOutlined" className={langClassName} />
// <WeiboCircleOutlined key="WeiboCircleOutlined" className={langClassName} />
// </>
// );
// };
const Lang = () => {
const langClassName = useEmotionCss(({ token }) => {
return {
display: 'none',
width: 42,
height: 42,
lineHeight: '42px',
position: 'fixed',
right: 16,
// zIndex: 99,
borderRadius: token.borderRadius,
':hover': {
backgroundColor: token.colorBgTextHover,
},
};
});
return (
<div className={langClassName} data-lang>
{SelectLang && <SelectLang />}
</div>
);
};
const LoginMessage: React.FC<{
content: string;
}> = ({ content }) => {
return (
<Alert
style={{
marginBottom: 24,
}}
message={content}
type="error"
showIcon
/>
);
};
const Login: React.FC = () => {
const [userLoginState, setUserLoginState] = useState<API.LoginResult>({});
const [type] = useState<string>('account');
const { initialState, setInitialState } = useModel('@@initialState');
const { token } = theme.useToken();
const [captcha, setCaptcha] = useState<string>('');
const [captchaId, setCaptchaId] = useState<string>('');
const [loginLoading, setLoginLoading] = useState<boolean>(false);
const containerClassName = useEmotionCss(() => {
return {
display: 'flex',
flexDirection: 'column',
height: '100vh',
overflow: 'auto',
backgroundImage:
"url('https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/V-_oS6r-i7wAAAAAAAAAAAAAFl94AQBr')",
backgroundSize: '100% 100%',
};
});
const intl = useIntl();
const refreshCaptcha = () => {
postBaseCaptcha().then((r: API.Response) => {
let resp_data: API.SysCaptchaResponse = r.data
setCaptcha(resp_data?.picPath ||'')
setCaptchaId(resp_data?.captchaId || '')
})
}
useEffect(()=>{
refreshCaptcha()
}, [])
const fetchUserInfo = async () => {
const userInfo = await initialState?.fetchUserInfo?.();
const menus = await postMenuGetMenu();
if (userInfo) {
console.log(22, userInfo)
if (getLocale() === 'zh-CN') {
let localData = getAllRouteNameTile(menus.data.routes, '')
let localRes:any = {}
localData.forEach((v)=>{
localRes[`menu${v.name}`] = v.title
})
console.log(localRes)
addLocale("zh-CN", localRes,{
momentLocale: "zh-CN",
antd: zhCN
});
}
flushSync(() => {
setInitialState((s) => ({
...s,
currentUser: userInfo,
menuData: menus.data.routes
}));
});
}
};
const handleSubmit = async (values: API.Login) => {
try {
// 登录
//{username: "admin", password: "123456", captcha: "5531", captchaId: "GMeC0be8js61jFfbBaXz"}
const msg = await postBaseLogin({...values, captchaId: captchaId})
// const msg = await login({ ...values, type });
if (msg.success === true) {
const defaultLoginSuccessMessage = intl.formatMessage({
id: 'pages.login.success',
defaultMessage: '登录成功!',
});
message.success(defaultLoginSuccessMessage);
localStorage.setItem('access', msg.data?.token || '');
fetchUserInfo().then(()=>{
const urlParams = new URL(window.location.href).searchParams;
console.log(222, urlParams.get('redirect'))
history.push(urlParams.get('redirect') || '/');
});
return;
// GetUserProfile().then(r=>{
// console.log(223, r)
// })
}
// 如果失败去设置用户错误信息
setUserLoginState({ status: msg.success ? 'ok': 'error', type: type, currentAuthority: msg.data?.token || ''});
} catch (error) {
const defaultLoginFailureMessage = intl.formatMessage({
id: 'pages.login.failure',
defaultMessage: '登录失败,请重试!',
});
message.error(defaultLoginFailureMessage);
refreshCaptcha()
} finally {
setLoginLoading(false)
}
};
const { status, type: loginType } = userLoginState;
return (
<div className={containerClassName}>
<Helmet>
<title>
{intl.formatMessage({
id: 'menu.login',
defaultMessage: '登录页',
})}
- {Settings.title}
</title>
</Helmet>
<Lang />
<div
style={{
flex: '1',
// padding: '32px 0',
}}
className={styles.loginFrom}
>
<div className={styles.loginBox}>
<div className={styles.loginLeft} >
<img className={styles.loginlogo} src={Logo}></img>
</div>
<ProConfigProvider>
<LoginForm
containerStyle={{
maxWidth: 496,
height: 566,
background: 'white',
padding: 48,
paddingTop: 107,
borderStartEndRadius: 16,
borderEndEndRadius: 16,
boxShadow: '0px 4px 16px 0px rgba(0, 0, 0, 0.15)'
}}
submitter={{
submitButtonProps:{
size:'large',
style:{
width: '100%',
borderRadius: '4px',
backgroundColor: '#154DDD',
}
}
}}
title="欢迎登录"
initialValues={{
autoLogin: false,
}}
loading={loginLoading}
onFinish={async (values) => {
await handleSubmit(values as API.LoginParams);
}}
>
{status === 'error' && loginType === 'account' && (
<LoginMessage
content={intl.formatMessage({
id: 'pages.login.accountLogin.errorMessage',
defaultMessage: '账户或密码错误(admin/ant.design)',
})}
/>
)}
{type === 'account' && (
<>
<ProFormText
name="username"
fieldProps={{
size: 'large',
prefix: <UserOutlined className={'prefixIcon'} />,
}}
placeholder={'用户名:'}
rules={[
{
required: true,
message: '请输入用户名!',
},
]}
/>
<ProFormText.Password
name="password"
fieldProps={{
size: 'large',
prefix: (
<LockOutlined
style={{
color: token.colorText,
}}
className={'prefixIcon'}
/>
),
}}
placeholder={'密码:'}
rules={[
{
required: true,
message: '请输入密码!',
},
]}
/>
<ProFormText
name="captcha"
fieldProps={{
size: 'large',
prefix: <KeyOutlined />,
}}
placeholder={intl.formatMessage({
id: 'pages.login.captcha.placeholder',
defaultMessage: '验证码:',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.captcha.required"
defaultMessage="请输入验证码!"
/>
),
},
]}
addonAfter={<Image style={{backgroundColor:'white'}} width={120} preview={false} src={captcha} onClick={refreshCaptcha}></Image>}
/>
</>
)}
{status === 'error' && loginType === 'mobile' && <LoginMessage content="验证码错误" />}
<div
style={{
marginBlockEnd: 24,
}}
>
<ProFormCheckbox noStyle name="autoLogin">
</ProFormCheckbox>
<a
style={{
float: 'right',
color: '#154DDD'
}}
>
</a>
</div>
</LoginForm>
</ProConfigProvider>
</div>
{/* <LoginFormPage
backgroundImageUrl='/sst.png'
submitter={{
submitButtonProps:{
size:'large',
style:{
width: '100%',
borderRadius: '4px',
backgroundColor: '#FF6D00',
}
}
}}
mainStyle={
{
width: 'auto',
}
}
containerStyle={{
maxWidth: '75vw',
height: 555,
background: 'white',
padding: 80
}}
title="欢迎登录"
initialValues={{
autoLogin: false,
}}
loading={loginLoading}
onFinish={async (values) => {
await handleSubmit(values as API.LoginParams);
}}
>
{status === 'error' && loginType === 'account' && (
<LoginMessage
content={intl.formatMessage({
id: 'pages.login.accountLogin.errorMessage',
defaultMessage: '账户或密码错误(admin/ant.design)',
})}
/>
)}
{type === 'account' && (
<>
<ProFormText
name="username"
fieldProps={{
size: 'large',
prefix: (
<UserOutlined
style={{
color: token.colorText,
}}
className={'prefixIcon'}
/>
),
}}
placeholder={'用户名:'}
rules={[
{
required: true,
message: '请输入用户名!',
},
]}
/>
<ProFormText.Password
name="password"
fieldProps={{
size: 'large',
prefix: (
<LockOutlined
style={{
color: token.colorText,
}}
className={'prefixIcon'}
/>
),
}}
placeholder={'密码:'}
rules={[
{
required: true,
message: '请输入密码!',
},
]}
/>
</>
)}
{status === 'error' && loginType === 'mobile' && <LoginMessage content="验证码错误" />}
{type === 'mobile' && (
<>
<ProFormText
fieldProps={{
size: 'large',
prefix: <MobileOutlined />,
}}
name="mobile"
placeholder={intl.formatMessage({
id: 'pages.login.phoneNumber.placeholder',
defaultMessage: '手机号',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.phoneNumber.required"
defaultMessage="请输入手机号!"
/>
),
},
{
pattern: /^1\d{10}$/,
message: (
<FormattedMessage
id="pages.login.phoneNumber.invalid"
defaultMessage="手机号格式错误!"
/>
),
},
]}
/>
<ProFormCaptcha
fieldProps={{
size: 'large',
prefix: <LockOutlined />,
}}
captchaProps={{
size: 'large',
}}
placeholder={intl.formatMessage({
id: 'pages.login.captcha.placeholder',
defaultMessage: '请输入验证码',
})}
captchaTextRender={(timing, count) => {
if (timing) {
return `${count} ${intl.formatMessage({
id: 'pages.getCaptchaSecondText',
defaultMessage: '获取验证码',
})}`;
}
return intl.formatMessage({
id: 'pages.login.phoneLogin.getVerificationCode',
defaultMessage: '获取验证码',
});
}}
name="captcha"
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.captcha.required"
defaultMessage="请输入验证码!"
/>
),
},
]}
onGetCaptcha={async (phone) => {
const result = await getFakeCaptcha({
phone,
});
if (!result) {
return;
}
message.success('获取验证码成功验证码为1234');
}}
/>
</>
)}
<div
style={{
marginBottom: 24,
}}
>
<ProFormCheckbox noStyle name="autoLogin">
<FormattedMessage id="pages.login.rememberMe" defaultMessage="记住用户名" />
</ProFormCheckbox>
<a
style={{
float: 'right',
color: '#FF6D00'
}}
>
<FormattedMessage id="pages.login.forgotPassword" defaultMessage="忘记密码" />
</a>
</div>
</LoginFormPage> */}
</div>
{/* <Footer /> */}
</div>
);
};
export default Login;

@ -0,0 +1,50 @@
.loginFrom {
.loginBox {
flex: 1;
width: 100vw;
height: 100vh;
background-image: url('../../../../public/sst.png');
background-size: 100% 100%;
background-repeat: no-repeat;
display: flex;
justify-content: center;
align-items: center;
}
.loginLeft {
position: relative;
width: 704px;
height: 566px;
background-image: url('../../../../public/loginBoxLeft.png');
background-size: 100% 100%;
background-repeat: no-repeat;
.loginlogo {
position: absolute;
top: -100px;
left: 0;
}
}
:global {
.ant-pro-form-login-container {
.ant-pro-form-login-top .css-dev-only-do-not-override-1lxmgnh {
width: 400px;
margin-bottom: 32px;
font-weight: 400;
}
:where(.css-dev-only-do-not-override-1lxmgnh).ant-pro-form-login-main {
min-width: 400px;
max-width: 580px;
margin: 0;
}
.ant-pro-form-login-main .css-dev-only-do-not-override-1lxmgnh {
width: 400px;
}
:where(.css-dev-only-do-not-override-qgg3xn).ant-input-affix-wrapper-lg {
padding: 7px 11px;
font-size: 16px;
line-height: 1.5;
border-radius: 4px;
}
}
}
}
Loading…
Cancel
Save