index.tsx 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. import {
  2. AlipayCircleOutlined,
  3. LockTwoTone,
  4. MailTwoTone,
  5. MobileTwoTone,
  6. TaobaoCircleOutlined,
  7. UserOutlined,
  8. WeiboCircleOutlined,
  9. } from '@ant-design/icons';
  10. import { Alert, Space, message, Tabs } from 'antd';
  11. import React, { useState } from 'react';
  12. import ProForm, { ProFormCaptcha, ProFormCheckbox, ProFormText } from '@ant-design/pro-form';
  13. import { useIntl, Link, history, FormattedMessage, SelectLang, useModel } from 'umi';
  14. import Footer from '@/components/Footer';
  15. import { fakeAccountLogin, getFakeCaptcha, LoginParamsType } from '@/services/login';
  16. import styles from './index.less';
  17. import { selectNavList } from '@/services/user';
  18. const LoginMessage: React.FC<{
  19. content: string;
  20. }> = ({ content }) => (
  21. <Alert
  22. style={{
  23. marginBottom: 24,
  24. }}
  25. message={content}
  26. type="error"
  27. showIcon
  28. />
  29. );
  30. /**
  31. * 此方法会跳转到 redirect 参数所在的位置
  32. */
  33. const goto = () => {
  34. if (!history) return;
  35. setTimeout(() => {
  36. const { query } = history.location;
  37. const { redirect } = query as {
  38. redirect: string;
  39. };
  40. history.push(redirect || '/');
  41. }, 10);
  42. };
  43. const Login: React.FC<{}> = () => {
  44. const [submitting, setSubmitting] = useState(false);
  45. const [userLoginState, setUserLoginState] = useState<API.LoginStateType>({});
  46. const [type, setType] = useState<string>('account');
  47. const { initialState, setInitialState } = useModel('@@initialState');
  48. const intl = useIntl();
  49. const fetchUserInfo = async () => {
  50. const userInfo = await initialState?.fetchUserInfo?.();
  51. if (userInfo) {
  52. setInitialState({
  53. ...initialState,
  54. settings: {
  55. menu: {
  56. loading: true,
  57. locale: false,// 关闭国际化
  58. },
  59. },
  60. currentUser: userInfo,
  61. });
  62. const menuData = await selectNavList();
  63. setInitialState({
  64. ...initialState,
  65. currentUser: userInfo,
  66. settings: {
  67. menu: {
  68. loading: false,
  69. locale: false,// 关闭国际化
  70. },
  71. },
  72. menuData: menuData.data,
  73. });
  74. }
  75. };
  76. const handleSubmit = async (values: LoginParamsType) => {
  77. setSubmitting(true);
  78. message.loading({content:'登录中...',key:'handleSubmit'})
  79. const msg = await fakeAccountLogin({ ...values, type });
  80. if(msg.error.length === 0){
  81. message.success({content:'登录成功',key:'handleSubmit',duration:2.5});
  82. await fetchUserInfo();
  83. goto();
  84. }else{
  85. message.error({content:msg.error[0].message,key:'handleSubmit',duration:2.5});
  86. setUserLoginState({
  87. status: 'error',
  88. type: msg.error[0].message,
  89. });
  90. }
  91. setSubmitting(false);
  92. };
  93. const { status, type: loginType } = userLoginState;
  94. return (
  95. <div className={styles.container}>
  96. <div className={styles.lang}>{SelectLang && <SelectLang />}</div>
  97. <div className={styles.content}>
  98. <div className={styles.top}>
  99. <div className={styles.header}>
  100. <Link to="/">
  101. <img alt="logo" className={styles.logo} src="http://ss.jishutao.com/portal/1.2.10/img/ico_logo.png" />
  102. <span className={styles.title}>科德管理系统</span>
  103. </Link>
  104. </div>
  105. <div className={styles.desc}>科德管理系统 是岳麓区最具影响力的管理系统</div>
  106. </div>
  107. <div className={styles.main}>
  108. <ProForm
  109. initialValues={{
  110. remeber: true,
  111. }}
  112. submitter={{
  113. searchConfig: {
  114. submitText: intl.formatMessage({
  115. id: 'pages.login.submit',
  116. defaultMessage: '登录',
  117. }),
  118. },
  119. render: (_, dom) => dom.pop(),
  120. submitButtonProps: {
  121. loading: submitting,
  122. size: 'large',
  123. style: {
  124. width: '100%',
  125. },
  126. },
  127. }}
  128. onFinish={async (values) => {
  129. handleSubmit(values);
  130. }}
  131. >
  132. <Tabs activeKey={type} onChange={setType}>
  133. <Tabs.TabPane
  134. key="account"
  135. tab={intl.formatMessage({
  136. id: 'pages.login.accountLogin.tab',
  137. defaultMessage: '账户密码登录',
  138. })}
  139. />
  140. <Tabs.TabPane
  141. key="mobile"
  142. tab={intl.formatMessage({
  143. id: 'pages.login.phoneLogin.tab',
  144. defaultMessage: '手机号登录',
  145. })}
  146. />
  147. </Tabs>
  148. {status === 'error' && (
  149. <LoginMessage
  150. content={intl.formatMessage({
  151. id: 'pages.login.accountLogin.errorMessage',
  152. defaultMessage: loginType,
  153. })}
  154. />
  155. )}
  156. {type === 'account' && (
  157. <>
  158. <ProFormText
  159. name="mobile"
  160. fieldProps={{
  161. size: 'large',
  162. prefix: <UserOutlined className={styles.prefixIcon} />,
  163. }}
  164. placeholder={intl.formatMessage({
  165. id: 'pages.login.username.placeholder',
  166. defaultMessage: '用户名: admin or user',
  167. })}
  168. rules={[
  169. {
  170. required: true,
  171. message: '用户名是必填项!',
  172. },
  173. ]}
  174. />
  175. <ProFormText.Password
  176. name="password"
  177. fieldProps={{
  178. size: 'large',
  179. prefix: <LockTwoTone className={styles.prefixIcon} />,
  180. }}
  181. placeholder={intl.formatMessage({
  182. id: 'pages.login.password.placeholder',
  183. defaultMessage: '密码: ant.design',
  184. })}
  185. rules={[
  186. {
  187. required: true,
  188. message: '密码是必填项!',
  189. },
  190. ]}
  191. />
  192. </>
  193. )}
  194. {status === 'error' && loginType === 'mobile' && <LoginMessage content="验证码错误" />}
  195. {type === 'mobile' && (
  196. <>
  197. <ProFormText
  198. fieldProps={{
  199. size: 'large',
  200. prefix: <MobileTwoTone className={styles.prefixIcon} />,
  201. }}
  202. name="mobile"
  203. placeholder={intl.formatMessage({
  204. id: 'pages.login.phoneNumber.placeholder',
  205. defaultMessage: '手机号',
  206. })}
  207. rules={[
  208. {
  209. required: true,
  210. message: '手机号是必填项!',
  211. },
  212. {
  213. pattern: /^1\d{10}$/,
  214. message: '不合法的手机号!',
  215. },
  216. ]}
  217. />
  218. <ProFormCaptcha
  219. fieldProps={{
  220. size: 'large',
  221. prefix: <MailTwoTone className={styles.prefixIcon} />,
  222. }}
  223. captchaProps={{
  224. size: 'large',
  225. }}
  226. placeholder={intl.formatMessage({
  227. id: 'pages.login.captcha.placeholder',
  228. defaultMessage: '请输入验证码',
  229. })}
  230. captchaTextRender={(timing, count) =>
  231. timing
  232. ? `${count} ${intl.formatMessage({
  233. id: 'pages.getCaptchaSecondText',
  234. defaultMessage: '获取验证码',
  235. })}`
  236. : intl.formatMessage({
  237. id: 'pages.login.phoneLogin.getVerificationCode',
  238. defaultMessage: '获取验证码',
  239. })
  240. }
  241. name="captcha"
  242. rules={[
  243. {
  244. required: true,
  245. message: '验证码是必填项!',
  246. },
  247. ]}
  248. onGetCaptcha={async (mobile) => {
  249. const result = await getFakeCaptcha(mobile);
  250. if (result === false) {
  251. return;
  252. }
  253. message.success('获取验证码成功!验证码为:1234');
  254. }}
  255. />
  256. </>
  257. )}
  258. <div
  259. style={{
  260. marginBottom: 24,
  261. }}
  262. >
  263. <ProFormCheckbox noStyle name="remeber">
  264. 自动登录
  265. </ProFormCheckbox>
  266. {/*<a*/}
  267. {/* style={{*/}
  268. {/* float: 'right',*/}
  269. {/* }}*/}
  270. {/*>*/}
  271. {/* 忘记密码 ?*/}
  272. {/*</a>*/}
  273. </div>
  274. </ProForm>
  275. {/*<Space className={styles.other}>*/}
  276. {/* 其他登录方式 :*/}
  277. {/* <AlipayCircleOutlined className={styles.icon} />*/}
  278. {/* <TaobaoCircleOutlined className={styles.icon} />*/}
  279. {/* <WeiboCircleOutlined className={styles.icon} />*/}
  280. {/*</Space>*/}
  281. </div>
  282. </div>
  283. <Footer />
  284. </div>
  285. );
  286. };
  287. export default Login;