Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 

85 строки
2.5 KiB

  1. import React, { useState } from 'react';
  2. export default function LoginForm({ apiUrl, onSuccess, onError }) {
  3. const [username, setUsername] = useState('');
  4. const [password, setPassword] = useState('');
  5. const [loading, setLoading] = useState(false);
  6. const [error, setError] = useState('');
  7. const handleSubmit = async (e) => {
  8. e.preventDefault();
  9. setError('');
  10. if (!username.trim() || !password.trim()) {
  11. const msg = '请输入用户名和密码';
  12. setError(msg);
  13. onError?.({ message: msg });
  14. return;
  15. }
  16. setLoading(true);
  17. try {
  18. const res = await fetch(`${apiUrl}/api/user/login`, {
  19. method: 'POST',
  20. headers: { 'Content-Type': 'application/json' },
  21. body: JSON.stringify({ username: username.trim(), password }),
  22. credentials: 'include',
  23. });
  24. const data = await res.json();
  25. if (data.success) {
  26. if (data.data?.require_2fa) {
  27. const msg = '此账户启用了两步验证,暂不支持通过 Widget 登录';
  28. setError(msg);
  29. onError?.({ message: msg });
  30. return;
  31. }
  32. onSuccess?.(data.data);
  33. } else {
  34. const msg = data.message || '登录失败';
  35. setError(msg);
  36. onError?.({ message: msg });
  37. }
  38. } catch (err) {
  39. const msg = '网络错误,请检查网络连接';
  40. setError(msg);
  41. onError?.({ message: msg });
  42. } finally {
  43. setLoading(false);
  44. }
  45. };
  46. return (
  47. <form className="naw-form" onSubmit={handleSubmit}>
  48. <div className="naw-field">
  49. <label className="naw-label">用户名或邮箱</label>
  50. <input
  51. className="naw-input"
  52. type="text"
  53. placeholder="请输入用户名或邮箱地址"
  54. value={username}
  55. onChange={(e) => setUsername(e.target.value)}
  56. autoComplete="username"
  57. disabled={loading}
  58. />
  59. </div>
  60. <div className="naw-field">
  61. <label className="naw-label">密码</label>
  62. <input
  63. className="naw-input"
  64. type="password"
  65. placeholder="请输入密码"
  66. value={password}
  67. onChange={(e) => setPassword(e.target.value)}
  68. autoComplete="current-password"
  69. disabled={loading}
  70. />
  71. </div>
  72. <p className="naw-error-msg">{error}</p>
  73. <button className="naw-button" type="submit" disabled={loading}>
  74. {loading ? '登录中...' : '登录'}
  75. </button>
  76. </form>
  77. );
  78. }