| import Footer from '@/components/Footer'; |
| import { getCaptchaImg, login } from '@/services/system/auth'; |
| import { getFakeCaptcha } from '@/services/ant-design-pro/login'; |
| import { |
| AlipayCircleOutlined, |
| LockOutlined, |
| MobileOutlined, |
| TaobaoCircleOutlined, |
| UserOutlined, |
| WeiboCircleOutlined, |
| } from '@ant-design/icons'; |
| import { |
| LoginForm, |
| 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, Col, message, Row, Tabs, Image } from 'antd'; |
| import Settings from '../../../../config/defaultSettings'; |
| import React, { useEffect, useState } from 'react'; |
| import { flushSync } from 'react-dom'; |
| import { clearSessionToken, setSessionToken } from '@/access'; |
| |
| 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 { |
| 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 = () => { |
| const [userLoginState, setUserLoginState] = useState<API.LoginResult>({code: 200}); |
| const [type, setType] = useState<string>('account'); |
| const { initialState, setInitialState } = useModel('@@initialState'); |
| const [captchaCode, setCaptchaCode] = useState<string>(''); |
| const [uuid, setUuid] = useState<string>(''); |
| |
| 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 getCaptchaCode = async () => { |
| const response = await getCaptchaImg(); |
| const imgdata = `data:image/png;base64,${response.img}`; |
| setCaptchaCode(imgdata); |
| setUuid(response.uuid); |
| }; |
| |
| const fetchUserInfo = async () => { |
| const userInfo = await initialState?.fetchUserInfo?.(); |
| if (userInfo) { |
| flushSync(() => { |
| setInitialState((s) => ({ |
| ...s, |
| currentUser: userInfo, |
| })); |
| }); |
| } |
| }; |
| |
| const handleSubmit = async (values: API.LoginParams) => { |
| try { |
| // 登录 |
| const response = await login({ ...values, uuid }); |
| if (response.code === 200) { |
| const defaultLoginSuccessMessage = intl.formatMessage({ |
| id: 'pages.login.success', |
| defaultMessage: '登录成功!', |
| }); |
| const current = new Date(); |
| const expireTime = current.setTime(current.getTime() + 1000 * 12 * 60 * 60); |
| console.log('login response: ', response); |
| setSessionToken(response?.token, response?.token, expireTime); |
| message.success(defaultLoginSuccessMessage); |
| await fetchUserInfo(); |
| console.log('login ok'); |
| const urlParams = new URL(window.location.href).searchParams; |
| history.push(urlParams.get('redirect') || '/'); |
| return; |
| } else { |
| console.log(response.msg); |
| clearSessionToken(); |
| // 如果失败去设置用户错误信息 |
| setUserLoginState({ ...response, type }); |
| getCaptchaCode(); |
| } |
| } catch (error) { |
| const defaultLoginFailureMessage = intl.formatMessage({ |
| id: 'pages.login.failure', |
| defaultMessage: '登录失败,请重试!', |
| }); |
| console.log(error); |
| message.error(defaultLoginFailureMessage); |
| } |
| }; |
| const { code } = userLoginState; |
| const loginType = type; |
| |
| useEffect(() => { |
| getCaptchaCode(); |
| }, []); |
| |
| return ( |
| <div className={containerClassName}> |
| <Helmet> |
| <title> |
| {intl.formatMessage({ |
| id: 'menu.login', |
| defaultMessage: '登录页', |
| })} |
| - {Settings.title} |
| </title> |
| </Helmet> |
| <Lang /> |
| <div |
| style={{ |
| flex: '1', |
| padding: '32px 0', |
| }} |
| > |
| <LoginForm |
| contentStyle={{ |
| minWidth: 280, |
| maxWidth: '75vw', |
| }} |
| logo={<img alt="logo" src="/logo.svg" />} |
| title="Ant Design" |
| subTitle={intl.formatMessage({ id: 'pages.layouts.userLayout.title' })} |
| initialValues={{ |
| autoLogin: true, |
| }} |
| actions={[ |
| <FormattedMessage |
| key="loginWith" |
| id="pages.login.loginWith" |
| defaultMessage="其他登录方式" |
| />, |
| <ActionIcons key="icons" />, |
| ]} |
| onFinish={async (values) => { |
| await handleSubmit(values as API.LoginParams); |
| }} |
| > |
| <Tabs |
| activeKey={type} |
| onChange={setType} |
| centered |
| items={[ |
| { |
| key: 'account', |
| label: intl.formatMessage({ |
| id: 'pages.login.accountLogin.tab', |
| defaultMessage: '账户密码登录', |
| }), |
| }, |
| { |
| key: 'mobile', |
| label: intl.formatMessage({ |
| id: 'pages.login.phoneLogin.tab', |
| defaultMessage: '手机号登录', |
| }), |
| }, |
| ]} |
| /> |
| |
| {code !== 200 && loginType === 'account' && ( |
| <LoginMessage |
| content={intl.formatMessage({ |
| id: 'pages.login.accountLogin.errorMessage', |
| defaultMessage: '账户或密码错误(admin/admin123)', |
| })} |
| /> |
| )} |
| {type === 'account' && ( |
| <> |
| <ProFormText |
| name="username" |
| initialValue="admin" |
| fieldProps={{ |
| size: 'large', |
| prefix: <UserOutlined />, |
| }} |
| placeholder={intl.formatMessage({ |
| id: 'pages.login.username.placeholder', |
| defaultMessage: '用户名: admin', |
| })} |
| rules={[ |
| { |
| required: true, |
| message: ( |
| <FormattedMessage |
| id="pages.login.username.required" |
| defaultMessage="请输入用户名!" |
| /> |
| ), |
| }, |
| ]} |
| /> |
| <ProFormText.Password |
| name="password" |
| initialValue="admin123" |
| fieldProps={{ |
| size: 'large', |
| prefix: <LockOutlined />, |
| }} |
| placeholder={intl.formatMessage({ |
| id: 'pages.login.password.placeholder', |
| defaultMessage: '密码: admin123', |
| })} |
| rules={[ |
| { |
| required: true, |
| message: ( |
| <FormattedMessage |
| id="pages.login.password.required" |
| defaultMessage="请输入密码!" |
| /> |
| ), |
| }, |
| ]} |
| /> |
| <Row> |
| <Col flex={3}> |
| <ProFormText |
| style={{ |
| float: 'right', |
| }} |
| name="code" |
| placeholder={intl.formatMessage({ |
| id: 'pages.login.captcha.placeholder', |
| defaultMessage: '请输入验证', |
| })} |
| rules={[ |
| { |
| required: true, |
| message: ( |
| <FormattedMessage |
| id="pages.searchTable.updateForm.ruleName.nameRules" |
| defaultMessage="请输入验证啊" |
| /> |
| ), |
| }, |
| ]} |
| /> |
| </Col> |
| <Col flex={2}> |
| <Image |
| src={captchaCode} |
| alt="验证码" |
| style={{ |
| display: 'inline-block', |
| verticalAlign: 'top', |
| cursor: 'pointer', |
| paddingLeft: '10px', |
| width: '100px', |
| }} |
| preview={false} |
| onClick={() => getCaptchaCode()} |
| /> |
| </Col> |
| </Row> |
| </> |
| )} |
| |
| {code !== 200 && 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', |
| }} |
| > |
| <FormattedMessage id="pages.login.forgotPassword" defaultMessage="忘记密码" /> |
| </a> |
| </div> |
| </LoginForm> |
| </div> |
| <Footer /> |
| </div> |
| ); |
| }; |
| |
| export default Login; |