LoginForm.js 11 KB

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