index.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. import {
  2. LockOutlined,
  3. MobileOutlined,
  4. UserOutlined,
  5. } from '@ant-design/icons';
  6. import {
  7. LoginForm,
  8. ProFormCaptcha,
  9. ProFormText,
  10. } from '@ant-design/pro-components';
  11. import { FormattedMessage, history, useIntl, useModel, Helmet } from '@umijs/max';
  12. import { Alert, message, Tabs } from 'antd';
  13. import Settings from '../../../../config/defaultSettings';
  14. import React, { useState } from 'react';
  15. import { flushSync } from 'react-dom';
  16. import { createStyles } from 'antd-style';
  17. import { useAjax } from '@/Hook/useAjax';
  18. import { getPCode, loginByPCode, loginByPwd } from '@/services/login';
  19. const useStyles = createStyles(({ token }) => {
  20. return {
  21. action: {
  22. marginLeft: '8px',
  23. color: 'rgba(0, 0, 0, 0.2)',
  24. fontSize: '24px',
  25. verticalAlign: 'middle',
  26. cursor: 'pointer',
  27. transition: 'color 0.3s',
  28. '&:hover': {
  29. color: token.colorPrimaryActive,
  30. },
  31. },
  32. lang: {
  33. width: 42,
  34. height: 42,
  35. lineHeight: '42px',
  36. position: 'fixed',
  37. right: 16,
  38. borderRadius: token.borderRadius,
  39. ':hover': {
  40. backgroundColor: token.colorBgTextHover,
  41. },
  42. },
  43. container: {
  44. display: 'flex',
  45. flexDirection: 'column',
  46. height: '100vh',
  47. overflow: 'auto',
  48. backgroundImage:
  49. "url('https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/V-_oS6r-i7wAAAAAAAAAAAAAFl94AQBr')",
  50. backgroundSize: '100% 100%',
  51. },
  52. };
  53. });
  54. const LoginMessage: React.FC<{
  55. content: string;
  56. }> = ({ content }) => {
  57. return (
  58. <Alert
  59. style={{
  60. marginBottom: 24,
  61. }}
  62. message={content}
  63. type="error"
  64. showIcon
  65. />
  66. );
  67. };
  68. const Login: React.FC = () => {
  69. const [userLoginState, setUserLoginState] = useState<any>({});
  70. const [type, setType] = useState<string>('account');
  71. const { initialState, setInitialState } = useModel('@@initialState');
  72. const { styles } = useStyles();
  73. const intl = useIntl();
  74. const loginByPwdFn = useAjax((data) => loginByPwd(data))//账号密码登录
  75. const loginByPCodeFn = useAjax((data) => loginByPCode(data))//手机登录
  76. const fetchUserInfo = async (data: any) => {
  77. // const userInfo = await initialState?.fetchUserInfo?.();
  78. if (data) {
  79. flushSync(() => {
  80. setInitialState((s) => ({
  81. ...s,
  82. currentUser: data.userInfo,
  83. token: data.token,
  84. menuType: 'distributor'
  85. }));
  86. });
  87. }
  88. };
  89. const handleSubmit = async (values: any) => {
  90. try {
  91. // 登录
  92. console.log(type, values)
  93. const urlParams = new URL(window.location.href).searchParams;
  94. let api = type === 'account' ? loginByPwdFn : loginByPCodeFn;
  95. let newValues = type === 'account' ? values : { phoneNum: values.mobile, code: values.captcha }
  96. api.run(newValues).then(async res => {
  97. if (res.data) {
  98. console.log(res.data.userInfo)
  99. await fetchUserInfo({ userInfo: res.data.userInfo, token: res.data.token });
  100. console.log(res.data.token)
  101. localStorage.setItem("Token", res.data.token)
  102. localStorage.setItem("manageAccount",res.data.userInfo.manageAccount)
  103. // 管理员跳转
  104. if(res.data.userInfo?.manageAccount){
  105. history.push(urlParams.get('redirect') || '/');
  106. }else{//非管理员跳转
  107. history.push('/distributor/appList')
  108. }
  109. }
  110. })
  111. return
  112. } catch (error) {
  113. const defaultLoginFailureMessage = intl.formatMessage({
  114. id: 'pages.login.failure',
  115. defaultMessage: '登录失败,请重试!',
  116. });
  117. console.log(error);
  118. message.error(defaultLoginFailureMessage);
  119. }
  120. };
  121. const { status, type: loginType } = userLoginState;
  122. return (
  123. <div className={styles.container}>
  124. <Helmet>
  125. <title>
  126. {intl.formatMessage({
  127. id: 'menu.login',
  128. defaultMessage: '登录页',
  129. })}
  130. - {Settings.title}
  131. </title>
  132. </Helmet>
  133. <div
  134. style={{
  135. flex: '1',
  136. padding: '32px 0',
  137. display: 'flex',
  138. alignItems: 'center',
  139. justifyContent: 'center'
  140. }}
  141. >
  142. <div style={{ height: 'auto', overflow: 'hidden', marginTop: '-10%' }}>
  143. <LoginForm
  144. contentStyle={{
  145. minWidth: 280,
  146. maxWidth: '75vw',
  147. }}
  148. // logo={<img alt="logo" src="/logo.svg" />}
  149. title="分销商平台"
  150. // subTitle={intl.formatMessage({ id: 'pages.layouts.userLayout.title' })}
  151. // actions={[
  152. // <FormattedMessage
  153. // key="loginWith"
  154. // id="pages.login.loginWith"
  155. // defaultMessage="其他登录方式"
  156. // />,
  157. // <ActionIcons key="icons" />,
  158. // ]}
  159. loading={loginByPwdFn?.loading || loginByPCodeFn?.loading}
  160. onFinish={async (values) => {
  161. await handleSubmit(values as any);
  162. }}
  163. >
  164. <Tabs
  165. activeKey={type}
  166. onChange={setType}
  167. centered
  168. items={[
  169. {
  170. key: 'account',
  171. label: intl.formatMessage({
  172. id: 'pages.login.accountLogin.tab',
  173. defaultMessage: '账户密码登录',
  174. }),
  175. },
  176. {
  177. key: 'mobile',
  178. label: intl.formatMessage({
  179. id: 'pages.login.phoneLogin.tab',
  180. defaultMessage: '手机号登录',
  181. }),
  182. },
  183. ]}
  184. />
  185. {status === 'error' && loginType === 'account' && (
  186. <LoginMessage
  187. content={intl.formatMessage({
  188. id: 'pages.login.accountLogin.errorMessage',
  189. defaultMessage: '账户或密码错误(admin/ant.design)',
  190. })}
  191. />
  192. )}
  193. {type === 'account' && (
  194. <>
  195. <ProFormText
  196. name="username"
  197. fieldProps={{
  198. size: 'large',
  199. prefix: <UserOutlined />,
  200. }}
  201. placeholder={intl.formatMessage({
  202. id: 'pages.login.username.placeholder',
  203. defaultMessage: '用户名: admin or user',
  204. })}
  205. rules={[
  206. {
  207. required: true,
  208. message: (
  209. <FormattedMessage
  210. id="pages.login.username.required"
  211. defaultMessage="请输入用户名!"
  212. />
  213. ),
  214. },
  215. ]}
  216. />
  217. <ProFormText.Password
  218. name="password"
  219. fieldProps={{
  220. size: 'large',
  221. prefix: <LockOutlined />,
  222. }}
  223. placeholder={intl.formatMessage({
  224. id: 'pages.login.password.placeholder',
  225. defaultMessage: '密码: ant.design',
  226. })}
  227. rules={[
  228. {
  229. required: true,
  230. message: (
  231. <FormattedMessage
  232. id="pages.login.password.required"
  233. defaultMessage="请输入密码!"
  234. />
  235. ),
  236. },
  237. ]}
  238. />
  239. </>
  240. )}
  241. {status === 'error' && loginType === 'mobile' && <LoginMessage content="验证码错误" />}
  242. {type === 'mobile' && (
  243. <>
  244. <ProFormText
  245. fieldProps={{
  246. size: 'large',
  247. prefix: <MobileOutlined />,
  248. }}
  249. name="mobile"
  250. placeholder={intl.formatMessage({
  251. id: 'pages.login.phoneNumber.placeholder',
  252. defaultMessage: '手机号',
  253. })}
  254. rules={[
  255. {
  256. required: true,
  257. message: (
  258. <FormattedMessage
  259. id="pages.login.phoneNumber.required"
  260. defaultMessage="请输入手机号!"
  261. />
  262. ),
  263. },
  264. {
  265. pattern: /^1\d{10}$/,
  266. message: (
  267. <FormattedMessage
  268. id="pages.login.phoneNumber.invalid"
  269. defaultMessage="手机号格式错误!"
  270. />
  271. ),
  272. },
  273. ]}
  274. />
  275. <ProFormCaptcha
  276. fieldProps={{
  277. size: 'large',
  278. prefix: <LockOutlined />,
  279. }}
  280. phoneName='mobile'
  281. captchaProps={{
  282. size: 'large',
  283. }}
  284. placeholder={intl.formatMessage({
  285. id: 'pages.login.captcha.placeholder',
  286. defaultMessage: '请输入验证码',
  287. })}
  288. captchaTextRender={(timing, count) => {
  289. if (timing) {
  290. return `${count} ${intl.formatMessage({
  291. id: 'pages.getCaptchaSecondText',
  292. defaultMessage: '获取验证码',
  293. })}`;
  294. }
  295. return intl.formatMessage({
  296. id: 'pages.login.phoneLogin.getVerificationCode',
  297. defaultMessage: '获取验证码',
  298. });
  299. }}
  300. name="captcha"
  301. rules={[
  302. {
  303. required: true,
  304. message: (
  305. <FormattedMessage
  306. id="pages.login.captcha.required"
  307. defaultMessage="请输入验证码!"
  308. />
  309. ),
  310. },
  311. ]}
  312. onGetCaptcha={async (mobile) => {
  313. const result = await getPCode(mobile);
  314. if (!result) {
  315. return;
  316. }
  317. message.success('获取验证码成功!请查看手机短信!');
  318. }}
  319. />
  320. </>
  321. )}
  322. </LoginForm>
  323. </div>
  324. </div>
  325. </div>
  326. );
  327. };
  328. export default Login;