LoginForm.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. import React, {useContext, useEffect, useState} from 'react';
  2. import {Link, useNavigate, useSearchParams} from 'react-router-dom';
  3. import {UserContext} from '../context/User';
  4. import {API, getLogo, isMobile, showError, showInfo, showSuccess, showWarning} from '../helpers';
  5. import {onGitHubOAuthClicked} from './utils';
  6. import Turnstile from "react-turnstile";
  7. import {Layout, Card, Image, Form, Button, Divider, Modal} from "@douyinfe/semi-ui";
  8. import Title from "@douyinfe/semi-ui/lib/es/typography/title";
  9. import Text from "@douyinfe/semi-ui/lib/es/typography/text";
  10. import {IconGithubLogo} from '@douyinfe/semi-icons';
  11. const LoginForm = () => {
  12. const [inputs, setInputs] = useState({
  13. username: '',
  14. password: '',
  15. wechat_verification_code: ''
  16. });
  17. const [searchParams, setSearchParams] = useSearchParams();
  18. const [submitted, setSubmitted] = useState(false);
  19. const {username, password} = inputs;
  20. const [userState, userDispatch] = useContext(UserContext);
  21. const [turnstileEnabled, setTurnstileEnabled] = useState(false);
  22. const [turnstileSiteKey, setTurnstileSiteKey] = useState('');
  23. const [turnstileToken, setTurnstileToken] = useState('');
  24. let navigate = useNavigate();
  25. const [status, setStatus] = useState({});
  26. const logo = getLogo();
  27. useEffect(() => {
  28. if (searchParams.get('expired')) {
  29. showError('未登录或登录已过期,请重新登录!');
  30. }
  31. let status = localStorage.getItem('status');
  32. if (status) {
  33. status = JSON.parse(status);
  34. setStatus(status);
  35. if (status.turnstile_check) {
  36. setTurnstileEnabled(true);
  37. setTurnstileSiteKey(status.turnstile_site_key);
  38. }
  39. }
  40. }, []);
  41. const [showWeChatLoginModal, setShowWeChatLoginModal] = useState(false);
  42. const onWeChatLoginClicked = () => {
  43. setShowWeChatLoginModal(true);
  44. };
  45. const onSubmitWeChatVerificationCode = async () => {
  46. if (turnstileEnabled && turnstileToken === '') {
  47. showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
  48. return;
  49. }
  50. const res = await API.get(
  51. `/api/oauth/wechat?code=${inputs.wechat_verification_code}`
  52. );
  53. const {success, message, data} = res.data;
  54. if (success) {
  55. userDispatch({type: 'login', payload: data});
  56. localStorage.setItem('user', JSON.stringify(data));
  57. navigate('/');
  58. showSuccess('登录成功!');
  59. setShowWeChatLoginModal(false);
  60. } else {
  61. showError(message);
  62. }
  63. };
  64. function handleChange(name, value) {
  65. setInputs((inputs) => ({...inputs, [name]: value}));
  66. }
  67. async function handleSubmit(e) {
  68. if (turnstileEnabled && turnstileToken === '') {
  69. showInfo('请稍后几秒重试,Turnstile 正在检查用户环境!');
  70. return;
  71. }
  72. setSubmitted(true);
  73. if (username && password) {
  74. const res = await API.post(`/api/user/login?turnstile=${turnstileToken}`, {
  75. username,
  76. password
  77. });
  78. const {success, message, data} = res.data;
  79. if (success) {
  80. userDispatch({type: 'login', payload: data});
  81. localStorage.setItem('user', JSON.stringify(data));
  82. showSuccess('登录成功!');
  83. if (username === 'root' && password === '123456') {
  84. Modal.error({title: '您正在使用默认密码!', content: '请立刻修改默认密码!', centered: true});
  85. }
  86. navigate('/token');
  87. } else {
  88. showError(message);
  89. }
  90. } else {
  91. showError('请输入用户名和密码!');
  92. }
  93. }
  94. return (
  95. <div>
  96. <Layout>
  97. <Layout.Header>
  98. </Layout.Header>
  99. <Layout.Content>
  100. <div style={{justifyContent: 'center', display: "flex", marginTop: 120}}>
  101. <div style={{width: 500}}>
  102. <Card>
  103. <Title heading={2} style={{textAlign: 'center'}}>
  104. 用户登录
  105. </Title>
  106. <Form>
  107. <Form.Input
  108. field={'username'}
  109. label={'用户名'}
  110. placeholder='用户名'
  111. name='username'
  112. onChange={(value) => handleChange('username', value)}
  113. />
  114. <Form.Input
  115. field={'password'}
  116. label={'密码'}
  117. placeholder='密码'
  118. name='password'
  119. type='password'
  120. onChange={(value) => handleChange('password', value)}
  121. />
  122. <Button theme='solid' style={{width: '100%'}} type={'primary'} size='large'
  123. htmlType={'submit'} onClick={handleSubmit}>
  124. 登录
  125. </Button>
  126. </Form>
  127. <div style={{display: 'flex', justifyContent: 'space-between', marginTop: 20}}>
  128. <Text>
  129. 没有账号请先 <Link to='/register'>注册账号</Link>
  130. </Text>
  131. <Text>
  132. 忘记密码 <Link to='/reset'>点击重置</Link>
  133. </Text>
  134. </div>
  135. {status.github_oauth || status.wechat_login ? (
  136. <>
  137. <Divider margin='12px' align='center'>
  138. 第三方登录
  139. </Divider>
  140. <div style={{display: 'flex', justifyContent: 'center', marginTop: 20}}>
  141. {status.github_oauth ? (
  142. <Button
  143. type='primary'
  144. icon={<IconGithubLogo/>}
  145. onClick={() => onGitHubOAuthClicked(status.github_client_id)}
  146. />
  147. ) : (
  148. <></>
  149. )}
  150. {/*{status.wechat_login ? (*/}
  151. {/* <Button*/}
  152. {/* circular*/}
  153. {/* color='green'*/}
  154. {/* icon='wechat'*/}
  155. {/* onClick={onWeChatLoginClicked}*/}
  156. {/* />*/}
  157. {/*) : (*/}
  158. {/* <></>*/}
  159. {/*)}*/}
  160. </div>
  161. </>
  162. ) : (
  163. <></>
  164. )}
  165. {/*<Modal*/}
  166. {/* onClose={() => setShowWeChatLoginModal(false)}*/}
  167. {/* onOpen={() => setShowWeChatLoginModal(true)}*/}
  168. {/* open={showWeChatLoginModal}*/}
  169. {/* size={'mini'}*/}
  170. {/*>*/}
  171. {/* <Modal.Content>*/}
  172. {/* <Modal.Description>*/}
  173. {/* <Image src={status.wechat_qrcode} fluid/>*/}
  174. {/* <div style={{textAlign: 'center'}}>*/}
  175. {/* <p>*/}
  176. {/* 微信扫码关注公众号,输入「验证码」获取验证码(三分钟内有效)*/}
  177. {/* </p>*/}
  178. {/* </div>*/}
  179. {/* <Form size='large'>*/}
  180. {/* <Form.Input*/}
  181. {/* field={'wechat_verification_code'}*/}
  182. {/* placeholder='验证码'*/}
  183. {/* name='wechat_verification_code'*/}
  184. {/* value={inputs.wechat_verification_code}*/}
  185. {/* onChange={handleChange}*/}
  186. {/* />*/}
  187. {/* <Button*/}
  188. {/* color=''*/}
  189. {/* fluid*/}
  190. {/* size='large'*/}
  191. {/* onClick={onSubmitWeChatVerificationCode}*/}
  192. {/* >*/}
  193. {/* 登录*/}
  194. {/* </Button>*/}
  195. {/* </Form>*/}
  196. {/* </Modal.Description>*/}
  197. {/* </Modal.Content>*/}
  198. {/*</Modal>*/}
  199. </Card>
  200. {turnstileEnabled ? (
  201. <div style={{display: 'flex', justifyContent: 'center', marginTop: 20}}>
  202. <Turnstile
  203. sitekey={turnstileSiteKey}
  204. onVerify={(token) => {
  205. setTurnstileToken(token);
  206. }}
  207. />
  208. </div>
  209. ) : (
  210. <></>
  211. )}
  212. </div>
  213. </div>
  214. </Layout.Content>
  215. </Layout>
  216. </div>
  217. );
  218. };
  219. export default LoginForm;