import React, { useEffect, useState } from 'react'; import { Link, useNavigate } from 'react-router-dom'; import * as authApi from '../api/auth.js'; import * as emailApi from '../api/email.js'; import { required as captchaRequired } from '../api/captcha.js'; import { showCaptcha } from '../components/CaptchaModal.jsx'; import { getToken } from '../api/client.js'; import { showSnackbar } from '../lib/utils.js'; /** * 注册页(迁移自 register.html): * 注册 → 后端返回 requires_verification 时进入邮箱验证步骤(8 位验证码 → /api/email/complete-register), * 支持重新发送验证码(/api/email/send-verify);验证码 proof 流转与登录一致。 */ export default function Register() { const navigate = useNavigate(); const [username, setUsername] = useState(''); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [confirm, setConfirm] = useState(''); const [error, setError] = useState(''); const [busy, setBusy] = useState(false); const [verifyMode, setVerifyMode] = useState(false); const [code, setCode] = useState(''); const [capRequired, setCapRequired] = useState(false); const [capDone, setCapDone] = useState(false); const [capResult, setCapResult] = useState(null); useEffect(() => { if (getToken()) { navigate('/', { replace: true }); return; } captchaRequired('register') .then((r) => { if (r && r.required) setCapRequired(true); }) .catch(() => {}); }, [navigate]); const doCaptcha = async () => { const result = await showCaptcha('register'); if (result) { setCapResult(result); setCapDone(true); } }; const handleRegister = async () => { if (!username.trim() || !email.trim() || !password) { setError('请填写所有必填项'); return; } if (password.length < 6) { setError('密码至少6位'); return; } if (password !== confirm) { setError('两次密码不一致'); return; } if (capRequired && !capDone) { setError('请先点击验证按钮完成验证'); return; } setError(''); setBusy(true); try { const data = await authApi.register({ username: username.trim(), password, email: email.trim(), captcha: capResult || undefined, }); if (data.requires_verification) { setVerifyMode(true); // 进入邮箱验证步骤 } else { showSnackbar('注册成功,请登录'); setTimeout(() => navigate('/login.html'), 1000); } } catch (e) { setError(e.message || '注册失败'); } setBusy(false); }; const handleVerify = async () => { if (!code || code.length !== 8) { setError('请输入完整的 8 位验证码'); return; } setError(''); try { await emailApi.completeRegister(code.trim(), username.trim(), password); showSnackbar('注册成功,请登录'); setTimeout(() => navigate('/login.html'), 1000); } catch (e) { setError(e.message); } }; const resendCode = async () => { try { await emailApi.sendVerify(email.trim(), username.trim()); showSnackbar('验证码已重新发送'); } catch (e) { showSnackbar(e.message); } }; return (
{verifyMode ? '请输入邮箱中的验证码' : '加入 RainWeb'}
{!verifyMode && ( <>验证码已发送到您的邮箱,请输入 8 位数字验证码
setCode(e.target.value)} placeholder="输入 8 位验证码" maxLength={8} inputMode="numeric" style={{ textAlign: 'center', fontSize: 24, letterSpacing: 8 }} onKeyDown={(e) => { if (e.key === 'Enter') handleVerify(); }} />