index.tsx 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  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. try{
  79. message.loading({content:'登录中...',key:'handleSubmit'})
  80. const msg = await fakeAccountLogin({ ...values, type });
  81. if(msg.error.length === 0){
  82. message.success({content:'登录成功',key:'handleSubmit',duration:2.5});
  83. await fetchUserInfo();
  84. goto();
  85. }else{
  86. message.error({content:msg.error[0].message,key:'handleSubmit',duration:2.5});
  87. setUserLoginState({
  88. status: 'error',
  89. type: msg.error[0].message,
  90. });
  91. }
  92. setSubmitting(false);
  93. }catch (_){
  94. setSubmitting(false);
  95. }
  96. };
  97. const { status, type: loginType } = userLoginState;
  98. return (
  99. <div className={styles.container}>
  100. <div className={styles.lang}>{SelectLang && <SelectLang />}</div>
  101. <div className={styles.content}>
  102. <div className={styles.top}>
  103. <div className={styles.header}>
  104. <Link to="/">
  105. <img alt="logo" className={styles.logo} src="http://ss.jishutao.com/portal/1.2.10/img/ico_logo.png" />
  106. <span className={styles.title}>科德管理系统</span>
  107. </Link>
  108. </div>
  109. <div className={styles.desc}>科德管理系统 是岳麓区最具影响力的管理系统</div>
  110. </div>
  111. <div className={styles.main}>
  112. <ProForm
  113. initialValues={{
  114. remeber: true,
  115. }}
  116. submitter={{
  117. searchConfig: {
  118. submitText: intl.formatMessage({
  119. id: 'pages.login.submit',
  120. defaultMessage: '登录',
  121. }),
  122. },
  123. render: (_, dom) => dom.pop(),
  124. submitButtonProps: {
  125. loading: submitting,
  126. size: 'large',
  127. style: {
  128. width: '100%',
  129. },
  130. },
  131. }}
  132. onFinish={async (values) => {
  133. handleSubmit(values);
  134. }}
  135. >
  136. <Tabs activeKey={type} onChange={setType}>
  137. <Tabs.TabPane
  138. key="account"
  139. tab={intl.formatMessage({
  140. id: 'pages.login.accountLogin.tab',
  141. defaultMessage: '账户密码登录',
  142. })}
  143. />
  144. <Tabs.TabPane
  145. key="mobile"
  146. tab={intl.formatMessage({
  147. id: 'pages.login.phoneLogin.tab',
  148. defaultMessage: '手机号登录',
  149. })}
  150. />
  151. </Tabs>
  152. {status === 'error' && (
  153. <LoginMessage
  154. content={intl.formatMessage({
  155. id: 'pages.login.accountLogin.errorMessage',
  156. defaultMessage: loginType,
  157. })}
  158. />
  159. )}
  160. {type === 'account' && (
  161. <>
  162. <ProFormText
  163. name="mobile"
  164. fieldProps={{
  165. size: 'large',
  166. prefix: <UserOutlined className={styles.prefixIcon} />,
  167. }}
  168. placeholder={intl.formatMessage({
  169. id: 'pages.login.username.placeholder',
  170. defaultMessage: '用户名: admin or user',
  171. })}
  172. rules={[
  173. {
  174. required: true,
  175. message: '用户名是必填项!',
  176. },
  177. ]}
  178. />
  179. <ProFormText.Password
  180. name="password"
  181. fieldProps={{
  182. size: 'large',
  183. prefix: <LockTwoTone className={styles.prefixIcon} />,
  184. }}
  185. placeholder={intl.formatMessage({
  186. id: 'pages.login.password.placeholder',
  187. defaultMessage: '密码: ant.design',
  188. })}
  189. rules={[
  190. {
  191. required: true,
  192. message: '密码是必填项!',
  193. },
  194. ]}
  195. />
  196. </>
  197. )}
  198. {status === 'error' && loginType === 'mobile' && <LoginMessage content="验证码错误" />}
  199. {type === 'mobile' && (
  200. <>
  201. <ProFormText
  202. fieldProps={{
  203. size: 'large',
  204. prefix: <MobileTwoTone className={styles.prefixIcon} />,
  205. }}
  206. name="mobile"
  207. placeholder={intl.formatMessage({
  208. id: 'pages.login.phoneNumber.placeholder',
  209. defaultMessage: '手机号',
  210. })}
  211. rules={[
  212. {
  213. required: true,
  214. message: '手机号是必填项!',
  215. },
  216. {
  217. pattern: /^1\d{10}$/,
  218. message: '不合法的手机号!',
  219. },
  220. ]}
  221. />
  222. <ProFormCaptcha
  223. fieldProps={{
  224. size: 'large',
  225. prefix: <MailTwoTone className={styles.prefixIcon} />,
  226. }}
  227. captchaProps={{
  228. size: 'large',
  229. }}
  230. placeholder={intl.formatMessage({
  231. id: 'pages.login.captcha.placeholder',
  232. defaultMessage: '请输入验证码',
  233. })}
  234. captchaTextRender={(timing, count) =>
  235. timing
  236. ? `${count} ${intl.formatMessage({
  237. id: 'pages.getCaptchaSecondText',
  238. defaultMessage: '获取验证码',
  239. })}`
  240. : intl.formatMessage({
  241. id: 'pages.login.phoneLogin.getVerificationCode',
  242. defaultMessage: '获取验证码',
  243. })
  244. }
  245. name="captcha"
  246. rules={[
  247. {
  248. required: true,
  249. message: '验证码是必填项!',
  250. },
  251. ]}
  252. onGetCaptcha={async (mobile) => {
  253. const result = await getFakeCaptcha(mobile);
  254. if (result === false) {
  255. return;
  256. }
  257. message.success('获取验证码成功!验证码为:1234');
  258. }}
  259. />
  260. </>
  261. )}
  262. <div
  263. style={{
  264. marginBottom: 24,
  265. }}
  266. >
  267. <ProFormCheckbox noStyle name="remeber">
  268. 自动登录
  269. </ProFormCheckbox>
  270. {/*<a*/}
  271. {/* style={{*/}
  272. {/* float: 'right',*/}
  273. {/* }}*/}
  274. {/*>*/}
  275. {/* 忘记密码 ?*/}
  276. {/*</a>*/}
  277. </div>
  278. </ProForm>
  279. {/*<Space className={styles.other}>*/}
  280. {/* 其他登录方式 :*/}
  281. {/* <AlipayCircleOutlined className={styles.icon} />*/}
  282. {/* <TaobaoCircleOutlined className={styles.icon} />*/}
  283. {/* <WeiboCircleOutlined className={styles.icon} />*/}
  284. {/*</Space>*/}
  285. </div>
  286. </div>
  287. <Footer />
  288. </div>
  289. );
  290. };
  291. export default Login;