| | |
| | | import { Footer } from '@/components'; |
| | | import { login } from '@/services/ant-design-pro/api'; |
| | | import { getFakeCaptcha } from '@/services/ant-design-pro/login'; |
| | | import { |
| | | LockOutlined, |
| | | MobileOutlined, |
| | | UserOutlined, |
| | | } from '@ant-design/icons'; |
| | | import { |
| | | LoginForm, |
| | | ProFormCaptcha, |
| | | ProFormCheckbox, |
| | | ProFormText, |
| | | } from '@ant-design/pro-components'; |
| | | import { FormattedMessage, history, SelectLang, useIntl, useModel, Helmet } from '@umijs/max'; |
| | | import { Alert, message, Tabs } from 'antd'; |
| | | import Settings from '../../../../config/defaultSettings'; |
| | | import React, { useState } from 'react'; |
| | | import { flushSync } from 'react-dom'; |
| | | import { createStyles } from 'antd-style'; |
| | | import { request } from '@umijs/max'; |
| | | import { setToken } from '@/utils/token-util' |
| | | |
| | | const useStyles = createStyles(({ token }) => { |
| | | return { |
| | | action: { |
| | | marginLeft: '8px', |
| | | color: 'rgba(0, 0, 0, 0.2)', |
| | | fontSize: '24px', |
| | | verticalAlign: 'middle', |
| | | cursor: 'pointer', |
| | | transition: 'color 0.3s', |
| | | '&:hover': { |
| | | color: token.colorPrimaryActive, |
| | | }, |
| | | }, |
| | | lang: { |
| | | width: 42, |
| | | height: 42, |
| | | lineHeight: '42px', |
| | | position: 'fixed', |
| | | right: 16, |
| | | borderRadius: token.borderRadius, |
| | | ':hover': { |
| | | backgroundColor: token.colorBgTextHover, |
| | | }, |
| | | }, |
| | | container: { |
| | | 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 Lang = () => { |
| | | const { styles } = useStyles(); |
| | | |
| | | return ( |
| | | <div className={styles.lang} data-lang> |
| | | {SelectLang && <SelectLang />} |
| | | </div> |
| | | ); |
| | | }; |
| | | |
| | | const LoginMessage = ({ content }) => { |
| | | return ( |
| | | <Alert |
| | | style={{ |
| | | marginBottom: 24, |
| | | }} |
| | | message={content} |
| | | type="error" |
| | | showIcon |
| | | /> |
| | | ); |
| | | }; |
| | | |
| | | const Login = () => { |
| | | const [userLoginState, setUserLoginState] = useState({}); |
| | | const [type, setType] = useState('account'); |
| | | const { initialState, setInitialState } = useModel('@@initialState'); |
| | | const { styles } = useStyles(); |
| | | const intl = useIntl(); |
| | | |
| | | console.log(initialState.memo); |
| | | |
| | | const fetchUserInfo = async () => { |
| | | const userInfo = await initialState?.fetchUserInfo?.(); |
| | | if (userInfo) { |
| | | flushSync(() => { |
| | | setInitialState((s) => ({ |
| | | ...s, |
| | | currentUser: userInfo, |
| | | })); |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | const handleSubmit = async (values) => { |
| | | try { |
| | | const r = await request('/api/login', { |
| | | method: 'POST', |
| | | headers: { |
| | | 'Content-Type': 'application/json' |
| | | }, |
| | | data: values |
| | | }) |
| | | |
| | | if (r.code === 200) { |
| | | message.success(intl.formatMessage({ |
| | | id: 'pages.login.success', |
| | | defaultMessage: '登录成功!', |
| | | })); |
| | | setToken(r.data.accessToken, values.autoLogin); |
| | | await fetchUserInfo(); |
| | | const urlParams = new URL(window.location.href).searchParams; |
| | | history.push(urlParams.get('redirect') || '/'); |
| | | return; |
| | | } |
| | | setUserLoginState({ |
| | | status: r.code, |
| | | type: type, |
| | | }) |
| | | |
| | | // 登录 |
| | | // const msg = await login({ ...values, type }); |
| | | // if (msg.status === 'ok') { |
| | | // const defaultLoginSuccessMessage = intl.formatMessage({ |
| | | // id: 'pages.login.success', |
| | | // defaultMessage: '登录成功!', |
| | | // }); |
| | | // message.success(defaultLoginSuccessMessage); |
| | | // await fetchUserInfo(); |
| | | // const urlParams = new URL(window.location.href).searchParams; |
| | | // history.push(urlParams.get('redirect') || '/'); |
| | | // return; |
| | | // } |
| | | // // 如果失败去设置用户错误信息 |
| | | // setUserLoginState(msg); |
| | | } catch (error) { |
| | | console.log(error); |
| | | message.error(intl.formatMessage({ |
| | | id: 'pages.login.failure', |
| | | defaultMessage: '登录失败,请重试!', |
| | | })); |
| | | } |
| | | }; |
| | | const { status, type: loginType } = userLoginState; |
| | | |
| | | return ( |
| | | <div className={styles.container}> |
| | | <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, |
| | | }} |
| | | onFinish={async (values) => { |
| | | await handleSubmit(values); |
| | | }} |
| | | > |
| | | <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: '手机号登录', |
| | | }), |
| | | }, |
| | | ]} |
| | | /> |
| | | |
| | | {status !== 200 && loginType === 'account' && ( |
| | | <LoginMessage |
| | | content={intl.formatMessage({ |
| | | id: 'pages.login.accountLogin.errorMessage', |
| | | defaultMessage: '账户或密码错误', |
| | | })} |
| | | /> |
| | | )} |
| | | {type === 'account' && ( |
| | | <> |
| | | <ProFormText |
| | | name="username" |
| | | fieldProps={{ |
| | | size: 'large', |
| | | prefix: <UserOutlined />, |
| | | }} |
| | | placeholder={intl.formatMessage({ |
| | | id: 'pages.login.username.placeholder', |
| | | defaultMessage: '用户名:', |
| | | })} |
| | | rules={[ |
| | | { |
| | | required: true, |
| | | message: ( |
| | | <FormattedMessage |
| | | id="pages.login.username.required" |
| | | defaultMessage="请输入用户名!" |
| | | /> |
| | | ), |
| | | }, |
| | | ]} |
| | | /> |
| | | <ProFormText.Password |
| | | name="password" |
| | | fieldProps={{ |
| | | size: 'large', |
| | | prefix: <LockOutlined />, |
| | | }} |
| | | placeholder={intl.formatMessage({ |
| | | id: 'pages.login.password.placeholder', |
| | | defaultMessage: '密码:', |
| | | })} |
| | | rules={[ |
| | | { |
| | | required: true, |
| | | message: ( |
| | | <FormattedMessage |
| | | id="pages.login.password.required" |
| | | defaultMessage="请输入密码!" |
| | | /> |
| | | ), |
| | | }, |
| | | ]} |
| | | /> |
| | | </> |
| | | )} |
| | | |
| | | {status !== 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> |
| | | </div> |
| | | </LoginForm> |
| | | </div> |
| | | <Footer /> |
| | | </div> |
| | | ); |
| | | }; |
| | | |
| | | export default Login; |
| | | import {
|
| | | LockOutlined,
|
| | | MobileOutlined,
|
| | | UserOutlined,
|
| | | } from '@ant-design/icons';
|
| | | import {
|
| | | LoginFormPage,
|
| | | ProConfigProvider,
|
| | | ProFormCaptcha,
|
| | | ProFormCheckbox,
|
| | | ProFormText,
|
| | | ProFormSelect
|
| | | } from '@ant-design/pro-components';
|
| | | import { Button, Divider, Alert, Tabs, message, theme, Form } from 'antd';
|
| | | import { useState, useEffect } from 'react';
|
| | | import { FormattedMessage, history, SelectLang, useIntl, useModel, request } from '@umijs/max';
|
| | | import { flushSync } from 'react-dom';
|
| | | import { createStyles } from 'antd-style';
|
| | | import { setToken } from '@/utils/token-util'
|
| | | import { PROJECT_NAME } from '@/config/setting'
|
| | | import Http from '@/utils/http';
|
| | |
|
| | | import logo from '/public/img/logo.png'
|
| | | import logoBg from '/public/login-bg.mp4'
|
| | |
|
| | | const useStyles = createStyles(({ token }) => {
|
| | | return {
|
| | | lang: {
|
| | |
|
| | | }
|
| | | }
|
| | | })
|
| | |
|
| | | const LoginMessage = ({ content }) => {
|
| | | return (
|
| | | <Alert
|
| | | style={{
|
| | | marginBottom: 24,
|
| | | }}
|
| | | message={content}
|
| | | type="error"
|
| | | showIcon
|
| | | />
|
| | | );
|
| | | };
|
| | |
|
| | | const Lang = () => {
|
| | | const { styles } = useStyles();
|
| | | return (
|
| | | <div className={styles.lang} data-lang>
|
| | | {SelectLang && <SelectLang />}
|
| | | </div>
|
| | | );
|
| | | };
|
| | |
|
| | | const Page = () => {
|
| | | const intl = useIntl();
|
| | | const { initialState, setInitialState } = useModel('@@initialState');
|
| | | const { token } = theme.useToken();
|
| | |
|
| | | const [form] = Form.useForm();
|
| | | const [loginType, setLoginType] = useState('account');
|
| | | const [status, setStatus] = useState(200);
|
| | | const [errDesc, setErrDesc] = useState('');
|
| | | const [rememberMe, setRememberMe] = useState(() => {
|
| | | const storedValue = localStorage.getItem('rememberMe');
|
| | | return storedValue !== null ? JSON.parse(storedValue) : true;
|
| | | });
|
| | | const [rememberData, setRememberData] = useState(() => {
|
| | | const storedValue = localStorage.getItem('rememberData');
|
| | | return storedValue !== null ? JSON.parse(storedValue) : true;
|
| | | });
|
| | | const [hostList, setHostList] = useState([]);
|
| | |
|
| | | useEffect(() => {
|
| | | form.setFieldsValue({
|
| | | autoLogin: rememberMe
|
| | | });
|
| | | localStorage.setItem('rememberMe', JSON.stringify(rememberMe));
|
| | | }, [rememberMe])
|
| | |
|
| | | useEffect(() => {
|
| | | form.setFieldsValue({
|
| | | username: rememberData.username,
|
| | | password: rememberData.password
|
| | | });
|
| | | localStorage.setItem('rememberData', JSON.stringify(rememberData));
|
| | | }, [rememberData])
|
| | |
|
| | | useEffect(() => {
|
| | | const fetchHostList = async () => {
|
| | | const resp = await Http.doGet('api/auth/host');
|
| | | const list = resp.data.map(item => ({
|
| | | label: item.name,
|
| | | value: item.id
|
| | | }));
|
| | | setHostList(list);
|
| | | if (list && list.length > 0) {
|
| | | form.setFieldsValue({
|
| | | hostId: list[0].value
|
| | | });
|
| | | }
|
| | | }
|
| | | fetchHostList();
|
| | | }, []);
|
| | |
|
| | | const fetchUserInfo = async () => {
|
| | | const userInfo = await initialState?.fetchUserInfo?.();
|
| | | if (userInfo) {
|
| | | flushSync(() => {
|
| | | setInitialState((s) => ({
|
| | | ...s,
|
| | | currentUser: userInfo,
|
| | | }));
|
| | | });
|
| | | }
|
| | | };
|
| | |
|
| | | const handleSubmit = async (values) => {
|
| | | try {
|
| | | const r = await request('/api/login', {
|
| | | method: 'POST',
|
| | | headers: {
|
| | | 'Content-Type': 'application/json'
|
| | | },
|
| | | data: values
|
| | | })
|
| | |
|
| | | if (r.code === 200) {
|
| | | localStorage.removeItem("rememberData");
|
| | | if (rememberMe) {
|
| | | setRememberData({
|
| | | username: values.username,
|
| | | password: values.password
|
| | | })
|
| | | }
|
| | | message.success(intl.formatMessage({
|
| | | id: 'login.success',
|
| | | defaultMessage: '登录成功!',
|
| | | }));
|
| | | setToken(r.data.accessToken, values.autoLogin);
|
| | | await fetchUserInfo();
|
| | | const urlParams = new URL(window.location.href).searchParams;
|
| | | history.push(urlParams.get('redirect') || '/');
|
| | | return;
|
| | | }
|
| | | setStatus(r.code);
|
| | | setErrDesc(r.msg);
|
| | | } catch (error) {
|
| | | console.log(error);
|
| | | message.error(intl.formatMessage({
|
| | | id: 'login.failure',
|
| | | defaultMessage: '登录失败,请重试!',
|
| | | }));
|
| | | }
|
| | | }
|
| | |
|
| | | return (
|
| | | <div
|
| | | style={{
|
| | | backgroundColor: 'white',
|
| | | height: '100vh',
|
| | | }}
|
| | | >
|
| | | <LoginFormPage
|
| | | form={form}
|
| | | logo={logo}
|
| | | backgroundVideoUrl={logoBg}
|
| | | // title="陆晓涛"
|
| | | // subTitle="陆晓涛..."
|
| | | containerStyle={{
|
| | | backgroundColor: 'rgba(0, 0, 0,0.65)',
|
| | | backdropFilter: 'blur(4px)',
|
| | | }}
|
| | | onFinish={async (values) => {
|
| | | await handleSubmit(values);
|
| | | }}
|
| | | initialValue={{
|
| | | }}
|
| | | >
|
| | | <Tabs
|
| | | centered
|
| | | activeKey={loginType}
|
| | | onChange={(activeKey) => setLoginType(activeKey)}
|
| | | >
|
| | | <Tabs.TabPane key={'account'} tab={intl.formatMessage({
|
| | | id: 'login.accountLogin.tab',
|
| | | defaultMessage: '账户密码登录',
|
| | | })} />
|
| | | <Tabs.TabPane key={'phone'} tab={intl.formatMessage({
|
| | | id: 'login.phoneLogin.tab',
|
| | | defaultMessage: '手机号登录',
|
| | | })} />
|
| | | </Tabs>
|
| | | {loginType === 'account' && (
|
| | | <>
|
| | | <ProFormSelect
|
| | | className="centered-select"
|
| | | name="hostId"
|
| | | placeholder={intl.formatMessage({
|
| | | id: 'login.host',
|
| | | defaultMessage: '机构:',
|
| | | })}
|
| | | rules={[
|
| | | {
|
| | | required: true,
|
| | | message: intl.formatMessage({
|
| | | id: 'login.rule.host',
|
| | | defaultMessage: '请选择机构!',
|
| | | }),
|
| | | },
|
| | | ]}
|
| | | options={hostList}
|
| | | />
|
| | | <ProFormText
|
| | | name="username"
|
| | | fieldProps={{
|
| | | size: 'large',
|
| | | prefix: (
|
| | | <UserOutlined
|
| | | style={{
|
| | | color: token.colorText,
|
| | | }}
|
| | | className={'prefixIcon'}
|
| | | />
|
| | | ),
|
| | | }}
|
| | | placeholder={intl.formatMessage({
|
| | | id: 'login.username',
|
| | | defaultMessage: '用户名: ',
|
| | | })}
|
| | | rules={[
|
| | | {
|
| | | required: true,
|
| | | message: intl.formatMessage({
|
| | | id: 'login.rule.username',
|
| | | defaultMessage: '请输入用户名!',
|
| | | }),
|
| | | },
|
| | | ]}
|
| | | />
|
| | | <ProFormText.Password
|
| | | name="password"
|
| | | fieldProps={{
|
| | | size: 'large',
|
| | | prefix: (
|
| | | <LockOutlined
|
| | | style={{
|
| | | color: token.colorText,
|
| | | }}
|
| | | className={'prefixIcon'}
|
| | | />
|
| | | ),
|
| | | }}
|
| | | placeholder={intl.formatMessage({
|
| | | id: 'login.password',
|
| | | defaultMessage: '密码: ',
|
| | | })}
|
| | | rules={[
|
| | | {
|
| | | required: true,
|
| | | message: intl.formatMessage({
|
| | | id: 'login.rule.password',
|
| | | defaultMessage: '请输入密码!!',
|
| | | }),
|
| | | },
|
| | | ]}
|
| | | />
|
| | | </>
|
| | | )}
|
| | | {status !== 200 && loginType === 'account' && (
|
| | | <LoginMessage
|
| | | content={intl.formatMessage({
|
| | | id: 'login.accountLogin.errorMessage',
|
| | | defaultMessage: '账户或密码错误',
|
| | | })}
|
| | | />
|
| | | )}
|
| | | {loginType === 'phone' && (
|
| | | <>
|
| | | <ProFormSelect
|
| | | className="centered-select"
|
| | | name="hostId"
|
| | | placeholder={intl.formatMessage({
|
| | | id: 'login.host',
|
| | | defaultMessage: '机构:',
|
| | | })}
|
| | | rules={[
|
| | | {
|
| | | required: true,
|
| | | message: intl.formatMessage({
|
| | | id: 'login.rule.host',
|
| | | defaultMessage: '请选择机构!',
|
| | | }),
|
| | | },
|
| | | ]}
|
| | | options={hostList}
|
| | | />
|
| | | <ProFormText
|
| | | fieldProps={{
|
| | | size: 'large',
|
| | | prefix: (
|
| | | <MobileOutlined
|
| | | style={{
|
| | | color: token.colorText,
|
| | | }}
|
| | | className={'prefixIcon'}
|
| | | />
|
| | | ),
|
| | | }}
|
| | | name="mobile"
|
| | | placeholder={intl.formatMessage({
|
| | | id: 'login.phoneNumber.placeholder',
|
| | | defaultMessage: '手机号',
|
| | | })}
|
| | | rules={[
|
| | | {
|
| | | required: true,
|
| | | message:
|
| | | <FormattedMessage
|
| | | id="login.phoneNumber.required"
|
| | | defaultMessage="请输入手机号!"
|
| | | />,
|
| | | },
|
| | | {
|
| | | pattern: /^1\d{10}$/,
|
| | | message:
|
| | | <FormattedMessage
|
| | | id="login.phoneNumber.invalid"
|
| | | defaultMessage="手机号格式错误!"
|
| | | />,
|
| | | },
|
| | | ]}
|
| | | />
|
| | | <ProFormCaptcha
|
| | | fieldProps={{
|
| | | size: 'large',
|
| | | prefix: (
|
| | | <LockOutlined
|
| | | style={{
|
| | | color: token.colorText,
|
| | | }}
|
| | | className={'prefixIcon'}
|
| | | />
|
| | | ),
|
| | | }}
|
| | | captchaProps={{
|
| | | size: 'large',
|
| | | }}
|
| | | placeholder={intl.formatMessage({
|
| | | id: 'login.captcha.placeholder',
|
| | | defaultMessage: '请输入验证码',
|
| | | })}
|
| | | captchaTextRender={(timing, count) => {
|
| | | if (timing) {
|
| | | return `${count} ${intl.formatMessage({
|
| | | id: 'pages.getCaptchaSecondText',
|
| | | defaultMessage: 'sec(秒)',
|
| | | })}`;
|
| | | }
|
| | | return intl.formatMessage({
|
| | | id: 'login.phoneLogin.getVerificationCode',
|
| | | defaultMessage: '获取验证码',
|
| | | });
|
| | | }}
|
| | | name="captcha"
|
| | | rules={[
|
| | | {
|
| | | required: true,
|
| | | message:
|
| | | <FormattedMessage
|
| | | id="login.captcha.required"
|
| | | defaultMessage="请输入验证码!"
|
| | | />,
|
| | | },
|
| | | ]}
|
| | | onGetCaptcha={async () => {
|
| | | message.warning(intl.formatMessage({
|
| | | id: 'login.phoneLogin.none',
|
| | | defaultMessage: '未开启手机号登录',
|
| | | }));
|
| | | }}
|
| | | />
|
| | | </>
|
| | | )}
|
| | | <div
|
| | | style={{
|
| | | display: 'flex',
|
| | | justifyContent: 'space-between',
|
| | | alignItems: 'center',
|
| | | marginBlockEnd: 24,
|
| | | }}
|
| | | >
|
| | | <ProFormCheckbox
|
| | | noStyle
|
| | | name="autoLogin"
|
| | | onChange={(e) => {
|
| | | setRememberMe(e.target.checked);
|
| | | }}
|
| | | >
|
| | | {intl.formatMessage({
|
| | | id: 'login.rememberMe',
|
| | | defaultMessage: '自动登录',
|
| | | })}
|
| | | </ProFormCheckbox>
|
| | | <Lang />
|
| | | </div>
|
| | | </LoginFormPage>
|
| | | </div>
|
| | | );
|
| | | };
|
| | |
|
| | | export default () => {
|
| | | return (
|
| | | <ProConfigProvider dark>
|
| | | <Page />
|
| | | </ProConfigProvider>
|
| | | );
|
| | | };
|