index.tsx 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. import { Button, message } from 'antd';
  2. import { useEffect, useMemo, useRef, useState } from 'react';
  3. import { useIntl } from 'umi';
  4. import './index.less';
  5. import { createForm } from '@formily/core';
  6. import { createSchemaField } from '@formily/react';
  7. import { Form, FormItem, Input, Password, Submit } from '@formily/antd';
  8. import { catchError, filter, mergeMap } from 'rxjs/operators';
  9. import Service from '@/pages/user/Login/service';
  10. import * as ICONS from '@ant-design/icons';
  11. import React from 'react';
  12. const Oauth = () => {
  13. const intl = useIntl();
  14. const logo = require('/public/logo.svg');
  15. const bindPage = require('/public/images/bind/bindPage.png');
  16. const headerImg = require('/public/logo.png');
  17. const [isLogin, setIsLogin] = useState<boolean>(true);
  18. const [captcha, setCaptcha] = useState<{ key?: string; base64?: string }>({});
  19. const [userName, setUerName] = useState<string>('');
  20. const [appName, setAppName] = useState<string>('');
  21. const [params, setParams] = useState<any>({});
  22. const [internal, setLinternal] = useState<any>();
  23. const loginRef = useRef<Partial<LoginParam>>({});
  24. const loginForm = useMemo(
  25. () =>
  26. createForm({
  27. validateFirst: true,
  28. initialValues: loginRef.current,
  29. }),
  30. [captcha],
  31. );
  32. const SchemaField = createSchemaField({
  33. components: {
  34. FormItem,
  35. Input,
  36. Password,
  37. // Checkbox,
  38. },
  39. scope: {
  40. icon(name: any) {
  41. return React.createElement(ICONS[name]);
  42. },
  43. },
  44. });
  45. const getCode = () => {
  46. delete loginForm.values?.verifyCode;
  47. loginRef.current = loginForm.values;
  48. // setLoading(false);
  49. Service.captchaConfig()
  50. .pipe(
  51. filter((r) => {
  52. if (!r.enabled) {
  53. // setLoading(false);
  54. }
  55. return r.enabled;
  56. }),
  57. mergeMap(Service.getCaptcha),
  58. catchError(() => message.error('系统开小差,请稍后重试')),
  59. )
  60. .subscribe((res) => {
  61. setCaptcha(res);
  62. // setLoading(false);
  63. });
  64. };
  65. const goOAuth2 = async (data?: any) => {
  66. const res = await Service.getOAuth2(data || params);
  67. if (res.status === 200) {
  68. window.location.href = res.result;
  69. } else {
  70. getCode();
  71. }
  72. };
  73. const schema = {
  74. type: 'object',
  75. properties: {
  76. username: {
  77. type: 'string',
  78. 'x-decorator': 'FormItem',
  79. 'x-validator': { required: true, message: '请输入用户名!' },
  80. 'x-component': 'Input',
  81. 'x-component-props': {
  82. placeholder: intl.formatMessage({
  83. id: 'pages.login.username.placeholder',
  84. defaultMessage: '用户名',
  85. }),
  86. prefix: "{{icon('UserOutlined')}}",
  87. },
  88. },
  89. password: {
  90. type: 'string',
  91. 'x-validator': { required: true, message: '请输入密码!' },
  92. 'x-decorator': 'FormItem',
  93. 'x-component': 'Password',
  94. 'x-component-props': {
  95. prefix: "{{icon('LockOutlined')}}",
  96. placeholder: intl.formatMessage({
  97. id: 'pages.login.password.placeholder',
  98. defaultMessage: '密码',
  99. }),
  100. },
  101. },
  102. verifyCode: {
  103. type: 'string',
  104. 'x-visible': !!captcha.key,
  105. 'x-decorator': 'FormItem',
  106. 'x-component': 'Input',
  107. 'x-component-props': {
  108. addonAfter: <img src={captcha.base64} alt="验证码" onClick={getCode} />,
  109. placeholder: intl.formatMessage({
  110. id: 'pages.login.captcha.placeholder',
  111. defaultMessage: '请输入验证码',
  112. }),
  113. },
  114. },
  115. },
  116. };
  117. const initApplication = async (cilentId: string) => {
  118. const res: any = await Service.initApplication(cilentId);
  119. if (res.status === 200) {
  120. setAppName(res.result?.name);
  121. }
  122. };
  123. const getLoginUser = async (data?: any) => {
  124. const res = await Service.queryCurrent();
  125. if (res && res.status === 200) {
  126. setUerName(res.result.user.name);
  127. setIsLogin(true);
  128. initApplication(data.client_id || params.client_id);
  129. if (data.internal === 'true' || internal === 'true') {
  130. goOAuth2(data);
  131. }
  132. } else if (res.status === 401) {
  133. setIsLogin(false);
  134. getCode();
  135. initApplication(data.client_id || params.client_id);
  136. } else {
  137. setIsLogin(false);
  138. }
  139. };
  140. const getQueryVariable = (variable: any) => {
  141. // console.log(window.location.search)
  142. const query = window.location.search.substring(1);
  143. const vars = query.split('&');
  144. for (let i = 0; i < vars.length; i++) {
  145. const pair = vars[i].split('=');
  146. if (pair[0] === variable) {
  147. return pair[1];
  148. }
  149. }
  150. return '';
  151. };
  152. const doLogin = async (data: LoginParam) => {
  153. // setIsLogin(true)
  154. const res = await Service.login2({
  155. expires: loginRef.current.expires,
  156. verifyKey: captcha.key,
  157. ...data,
  158. });
  159. if (res.status === 200) {
  160. getLoginUser();
  161. const token = res.result.token;
  162. localStorage.setItem('X-Access-Token', token);
  163. goOAuth2();
  164. } else {
  165. getCode();
  166. }
  167. };
  168. useEffect(() => {
  169. document.title = 'OAuth授权-jetlinks';
  170. getCode();
  171. }, []);
  172. useEffect(() => {
  173. let redirectUrl;
  174. const items = {
  175. // code: getQueryVariable('code'),
  176. client_id: getQueryVariable('client_id'),
  177. state: getQueryVariable('state'),
  178. redirect_uri: decodeURIComponent(getQueryVariable('redirect_uri')),
  179. response_type: getQueryVariable('response_type'),
  180. scope: getQueryVariable('scope'),
  181. };
  182. const item = getQueryVariable('internal');
  183. if (items.redirect_uri) {
  184. // console.log(items.redirect_uri,'params')
  185. const orgin = items.redirect_uri.split('/').slice(0, 3);
  186. // console.log(orgin)
  187. const url = `${orgin.join('/')}/%23/${items.redirect_uri?.split('redirect=')[1]}`;
  188. redirectUrl = `${items.redirect_uri?.split('redirect=')[0]}redirect=${url}`;
  189. }
  190. getLoginUser({
  191. ...items,
  192. internal: getQueryVariable('internal'),
  193. redirect_uri: redirectUrl,
  194. });
  195. setLinternal(item);
  196. setParams({
  197. ...items,
  198. redirect_uri: redirectUrl,
  199. });
  200. // console.log(items, '11111111111')
  201. }, [window.location]);
  202. //未登录状态
  203. const loginPage = () => {
  204. return (
  205. <>
  206. <div className="oauth-content-header">
  207. <img src={headerImg} />
  208. </div>
  209. <div className="oauth-content-login">
  210. <Form form={loginForm} layout="horizontal" size="large" onAutoSubmit={doLogin}>
  211. <SchemaField schema={schema} />
  212. <Submit block size="large">
  213. {intl.formatMessage({
  214. id: 'pages.login.submit',
  215. defaultMessage: '登录',
  216. })}
  217. </Submit>
  218. </Form>
  219. </div>
  220. </>
  221. );
  222. };
  223. return (
  224. <div
  225. className="oauth"
  226. style={{
  227. width: '100%',
  228. height: '100vh',
  229. background: `url(${bindPage}) no-repeat`,
  230. backgroundSize: '100% 100%',
  231. }}
  232. >
  233. <div className="oauth-header">
  234. <div className="oauth-header-left">
  235. <img src={logo} />
  236. </div>
  237. {/* <div className="oauth-header-right">
  238. <a style={{ color: 'rgb(0 0 0 / 70%)' }}>{userName || '-'}</a>
  239. <div className="oauth-header-right-connect">|</div>
  240. <a
  241. style={{ color: 'rgb(0 0 0 / 70%)' }}
  242. onClick={(() => {
  243. setIsLogin(false)
  244. })}
  245. >切换账号</a>
  246. </div> */}
  247. </div>
  248. <div className="oauth-content">
  249. {isLogin ? (
  250. <>
  251. <div className="oauth-content-header">
  252. <img src={headerImg} />
  253. </div>
  254. <div className="oauth-content-content">
  255. <div className="oauth-content-content-text">
  256. {`您正在授权登录,${appName || '-'}将获得以下权限:`}
  257. </div>
  258. <ul>
  259. <li>{`关联${userName}账号`}</li>
  260. <li>获取您的个人信息 </li>
  261. </ul>
  262. </div>
  263. <div className="oauth-content-button">
  264. <Button
  265. type="primary"
  266. onClick={() => {
  267. goOAuth2();
  268. }}
  269. >
  270. 同意授权
  271. </Button>
  272. <Button
  273. onClick={() => {
  274. localStorage.removeItem('X-Access-Token');
  275. setIsLogin(false);
  276. }}
  277. >
  278. 切换账号
  279. </Button>
  280. </div>
  281. </>
  282. ) : (
  283. loginPage()
  284. )}
  285. </div>
  286. </div>
  287. );
  288. };
  289. export default Oauth;