import { login } from './service';
|
import { sendRequest } from '@/utils/antdUtils';
|
import { LockOutlined, SafetyOutlined, UserOutlined } from '@ant-design/icons';
|
import { LoginForm, ProFormText } from '@ant-design/pro-components';
|
import { useEmotionCss } from '@ant-design/use-emotion-css';
|
import { Helmet, history, SelectLang, useIntl, useModel } from '@umijs/max';
|
import { Alert, message, Space } from 'antd';
|
// import CryptoJS from 'crypto-js';
|
import React, { useRef, useState } from 'react';
|
import Captcha from 'react-captcha-code';
|
import { useAccess } from 'umi';
|
import Settings from '../../../config/defaultSettings';
|
import logo from '../../../public/logo/logo.png';
|
import EditPwd from './editPwd.jsx';
|
import { updatePwd } from './service.js';
|
import './style.less';
|
|
const Lang = () => {
|
const langClassName = useEmotionCss(({ token }) => {
|
return {
|
width: 42,
|
height: 42,
|
lineHeight: '42px',
|
position: 'fixed',
|
right: 16,
|
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 = (props) => {
|
const [userLoginState, setUserLoginState] = useState<API.LoginResult>({});
|
const [modalVisible, handleModalVisible] = useState<Boolean>(false);
|
const [captcha, setCaptcha] = useState<String>('');
|
const captchaRef = useRef();
|
const [type, setType] = useState<string>('username');
|
const { initialState, setInitialState } = useModel('@@initialState');
|
const access = useAccess();
|
const style1 = {
|
display: 'flex',
|
};
|
const containerClassName = useEmotionCss(() => {
|
return {
|
height: '100vh',
|
overflow: 'auto',
|
};
|
});
|
|
const intl = useIntl();
|
|
const getUserInfo = async (data: any) => {
|
const defaultLoginSuccessMessage = intl.formatMessage({
|
id: 'pages.login.success',
|
defaultMessage: '登录成功!',
|
});
|
const userInfo = data.userInfo.user
|
localStorage.setItem('userInfo', JSON.stringify(userInfo));
|
|
setInitialState((s: any) => ({
|
...s,
|
token: 'data.token.access_token',
|
currentUser: userInfo,
|
settings: Settings,
|
}));
|
|
message.success(defaultLoginSuccessMessage);
|
const urlParams = new URL(window.location.href).searchParams;
|
setTimeout(() => {
|
history.push(urlParams.get('redirect') || '/Welcome');
|
}, 0);
|
};
|
|
const filterPermission = (list: any[], arr: any[]) => {
|
return list.map((item) => {
|
if (item.children) {
|
filterPermission(item.children, arr);
|
}
|
arr.push(item);
|
return item;
|
});
|
};
|
|
const handleClick = (e: String) => {
|
setCaptcha(e);
|
};
|
// 生成随机字符串
|
const generateRandomString = (length: number) => {
|
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
const str = [];
|
for (let i = 0; i < length; i++) {
|
const randomIndex = Math.floor(Math.random() * chars.length);
|
str.push(chars[randomIndex]);
|
}
|
return str.join('');
|
};
|
const handleSubmit = async (values: API.LoginParams) => {
|
try {
|
// 登录
|
const res = await login({ ...values });
|
if (res.code == 200) {
|
let accessObj: any = {};
|
localStorage.setItem('access', JSON.stringify(accessObj));
|
setInitialState((s: any) => ({
|
...s,
|
permission: accessObj,
|
}));
|
localStorage.setItem('token', res.token);
|
getUserInfo(res);
|
return;
|
} else {
|
throw new Error('登录发生错误');
|
}
|
// 如果失败去设置用户错误信息
|
// setUserLoginState(res);
|
} catch (error) {
|
captchaRef?.current?.refresh();
|
}
|
};
|
|
const { status, type: loginType } = userLoginState;
|
|
return (
|
<div className={containerClassName}>
|
<div className="loginContent">
|
<Helmet>
|
<title>
|
{intl.formatMessage({
|
id: 'menu.login',
|
defaultMessage: '登录页',
|
})}
|
- {Settings.title}
|
</title>
|
</Helmet>
|
<Lang />
|
|
<div
|
style={{
|
position: 'absolute',
|
top: '50%',
|
left: '50%',
|
transform: 'translate(-50%,-50%)',
|
display: 'flex',
|
flexDirection: 'column',
|
alignItems: 'center',
|
}}
|
>
|
{/* <div style={{ width: '787px' }}>
|
<h1
|
style={{ fontSize: '48px', color: '#fff', textAlign: 'center', marginBottom: '48px' }}
|
>
|
三个身边
|
</h1>
|
</div> */}
|
<LoginForm
|
contentStyle={{
|
minWidth: 280,
|
maxWidth: '75vw',
|
}}
|
logo={logo}
|
title=""
|
subTitle={' '}
|
initialValues={{
|
autoLogin: true,
|
}}
|
// actions={[
|
// <FormattedMessage
|
// key="loginWith"
|
// id="pages.login.loginWith"
|
// defaultMessage="其他登录方式"
|
// />,
|
// <ActionIcons key="icons" />,
|
// ]}
|
onFinish={async (values) => {
|
if (values.code != captcha) {
|
captchaRef?.current?.refresh();
|
message.error('验证码输入错误');
|
return;
|
}
|
delete values.code;
|
await handleSubmit(values as API.LoginParams);
|
}}
|
>
|
{/* <Tabs
|
activeKey={type}
|
onChange={setType}
|
centered
|
items={[
|
{
|
key: 'username',
|
label: intl.formatMessage({
|
id: 'pages.login.accountLogin.tab',
|
defaultMessage: '账户密码登录',
|
}),
|
},
|
{
|
key: 'mobile',
|
label: intl.formatMessage({
|
id: 'pages.login.phoneLogin.tab',
|
defaultMessage: '手机号登录',
|
}),
|
},
|
]}
|
/> */}
|
|
{status === 'error' && loginType === 'username' && (
|
<LoginMessage
|
content={intl.formatMessage({
|
id: 'pages.login.accountLogin.errorMessage',
|
defaultMessage: '账户或密码错误(admin/ant.design)',
|
})}
|
/>
|
)}
|
{type === 'username' && (
|
<>
|
<ProFormText
|
name="username"
|
fieldProps={{
|
size: 'large',
|
prefix: <UserOutlined />,
|
}}
|
placeholder="请输入账号"
|
rules={[
|
{
|
required: true,
|
message: '请输入账号',
|
},
|
]}
|
/>
|
<ProFormText.Password
|
name="password"
|
fieldProps={{
|
size: 'large',
|
prefix: <LockOutlined />,
|
}}
|
placeholder="请输入密码"
|
rules={[
|
{
|
required: true,
|
message: '请输入密码',
|
},
|
]}
|
/>
|
<Space>
|
<ProFormText
|
name="code"
|
fieldProps={{
|
size: 'large',
|
prefix: <SafetyOutlined />,
|
}}
|
placeholder="请输入验证码"
|
rules={[
|
{
|
required: true,
|
message: '请输入验证码',
|
},
|
]}
|
/>
|
<div style={{ marginBottom: '24px' }}>
|
<Captcha onChange={handleClick} ref={captchaRef} bgColor="#fff" />
|
</div>
|
</Space>
|
|
{/* <div
|
style={{ color: '#0086F6', textAlign: 'right', marginBottom: '21px' }}
|
className="login-form-forgot"
|
onClick={() => {
|
handleModalVisible(true);
|
}}
|
>
|
修改密码
|
</div> */}
|
</>
|
)}
|
|
{status === 'error' && loginType === 'mobile' && <LoginMessage content="验证码错误" />}
|
{/* <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="手机号格式错误!"
|
/>
|
),
|
},
|
]}
|
/> */}
|
|
{/* <div
|
style={{
|
marginBottom: 24,
|
}}
|
>
|
<ProFormCheckbox noStyle name="autoLogin">
|
<FormattedMessage id="pages.login.rememberMe" defaultMessage="自动登录" />
|
</ProFormCheckbox>
|
<a
|
style={{
|
float: 'right',
|
}}
|
>
|
<FormattedMessage id="pages.login.forgotPassword" defaultMessage="忘记密码" />
|
</a>
|
</div> */}
|
</LoginForm>
|
</div>
|
<EditPwd
|
visible={modalVisible}
|
onSave={async (fileds: any) => {
|
const success = await sendRequest(updatePwd, fileds);
|
if (success) {
|
handleModalVisible(false);
|
}
|
}}
|
onCancel={() => handleModalVisible(false)}
|
/>
|
{/* <Footer /> */}
|
</div>
|
</div>
|
);
|
};
|
|
export default Login;
|