diff --git a/package.json b/package.json index 7214c6e9..1ccaae20 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,6 @@ "tsc": "tsc --noEmit" }, "lint-staged": { - "**/*.less": "stylelint --syntax less", "**/*.{js,jsx,ts,tsx}": "npm run lint-staged:js", "**/*.{js,jsx,tsx,ts,less,md,json}": [ "prettier --write" @@ -84,7 +83,6 @@ "lint-staged": "^10.0.0", "mockjs": "^1.1.0", "prettier": "^2.5.0", - "stylelint": "^13.0.0", "swagger-ui-dist": "^4.12.0", "typescript": "^4.5.0", "umi-presets-pro": "1.0.1", diff --git a/src/pages/User/Login/index.less b/src/pages/User/Login/index.less new file mode 100644 index 00000000..36eb7d63 --- /dev/null +++ b/src/pages/User/Login/index.less @@ -0,0 +1,48 @@ +@import (reference) '~antd/es/style/themes/index'; + +.container { + display: flex; + flex-direction: column; + height: 100vh; + overflow: auto; + background: @layout-body-background; +} + +.lang { + width: 100%; + height: 40px; + line-height: 44px; + text-align: right; + :global(.ant-dropdown-trigger) { + margin-right: 24px; + } +} + +.content { + flex: 1; + padding: 32px 0; +} + +@media (min-width: @screen-md-min) { + .container { + background-image: url('https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/V-_oS6r-i7wAAAAAAAAAAAAAFl94AQBr'); + background-size: cover; + } + + .content { + padding: 32px 0 24px; + } +} + +.icon { + margin-left: 8px; + color: rgba(0, 0, 0, 0.2); + font-size: 24px; + vertical-align: middle; + cursor: pointer; + transition: color 0.3s; + + &:hover { + color: @primary-color; + } +} diff --git a/src/pages/User/Login/index.tsx b/src/pages/User/Login/index.tsx new file mode 100644 index 00000000..080d6faa --- /dev/null +++ b/src/pages/User/Login/index.tsx @@ -0,0 +1,290 @@ +import Footer from '@/components/Footer'; +import { login } from '@/services/ant-design-pro/api'; +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 { FormattedMessage, history, SelectLang, useIntl, useModel } from '@umijs/max'; +import { Alert, message, Tabs } from 'antd'; +import React, { useState } from 'react'; +import styles from './index.less'; + +const LoginMessage: React.FC<{ + content: string; +}> = ({ content }) => { + return ( + + ); +}; + +const Login: React.FC = () => { + const [userLoginState, setUserLoginState] = useState({}); + const [type, setType] = useState('account'); + const { initialState, setInitialState } = useModel('@@initialState'); + + const intl = useIntl(); + + const fetchUserInfo = async () => { + const userInfo = await initialState?.fetchUserInfo?.(); + if (userInfo) { + await setInitialState((s) => ({ + ...s, + currentUser: userInfo, + })); + } + }; + + const handleSubmit = async (values: API.LoginParams) => { + try { + // 登录 + 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; + } + console.log(msg); + // 如果失败去设置用户错误信息 + setUserLoginState(msg); + } catch (error) { + const defaultLoginFailureMessage = intl.formatMessage({ + id: 'pages.login.failure', + defaultMessage: '登录失败,请重试!', + }); + console.log(error); + message.error(defaultLoginFailureMessage); + } + }; + const { status, type: loginType } = userLoginState; + + return ( +
+
+ {SelectLang && } +
+
+ } + title="Ant Design" + subTitle={intl.formatMessage({ id: 'pages.layouts.userLayout.title' })} + initialValues={{ + autoLogin: true, + }} + actions={[ + , + , + , + , + ]} + onFinish={async (values) => { + await handleSubmit(values as API.LoginParams); + }} + > + + + + + + {status === 'error' && loginType === 'account' && ( + + )} + {type === 'account' && ( + <> + , + }} + placeholder={intl.formatMessage({ + id: 'pages.login.username.placeholder', + defaultMessage: '用户名: admin or user', + })} + rules={[ + { + required: true, + message: ( + + ), + }, + ]} + /> + , + }} + placeholder={intl.formatMessage({ + id: 'pages.login.password.placeholder', + defaultMessage: '密码: ant.design', + })} + rules={[ + { + required: true, + message: ( + + ), + }, + ]} + /> + + )} + + {status === 'error' && loginType === 'mobile' && } + {type === 'mobile' && ( + <> + , + }} + name="mobile" + placeholder={intl.formatMessage({ + id: 'pages.login.phoneNumber.placeholder', + defaultMessage: '手机号', + })} + rules={[ + { + required: true, + message: ( + + ), + }, + { + pattern: /^1\d{10}$/, + message: ( + + ), + }, + ]} + /> + , + }} + 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: ( + + ), + }, + ]} + onGetCaptcha={async (phone) => { + const result = await getFakeCaptcha({ + phone, + }); + if (result === false) { + return; + } + message.success('获取验证码成功!验证码为:1234'); + }} + /> + + )} +
+ + + + + + +
+
+
+
+ ); +}; + +export default Login; diff --git a/tsconfig.json b/tsconfig.json index e7a27859..56ba13c6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -33,7 +33,6 @@ "typings/**/*", "config/**/*", ".eslintrc.js", - ".stylelintrc.js", ".prettierrc.js", "jest.config.js", "mock/*"