// ─── Auth screen ─── Real login/register against /api/auth/* function AuthScreen({ setScreen, toast, onAuthed }) { const [tab, setTab] = React.useState('login'); const [email, setEmail] = React.useState(''); const [pwd, setPwd] = React.useState(''); const [code, setCode] = React.useState(''); const [loading, setLoading] = React.useState(false); const [requireInvite, setRequireInvite] = React.useState(false); const [err, setErr] = React.useState(''); React.useEffect(() => { apiFetch('/api/auth/config') .then(r => r.json()) .then(d => setRequireInvite(!!d.require_invite_code)) .catch(() => {}); }, []); async function submit(e) { e.preventDefault(); setErr(''); setLoading(true); const endpoint = tab === 'register' ? '/api/auth/register' : '/api/auth/login'; const payload = { email, password: pwd }; if (tab === 'register' && requireInvite) payload.invite_code = code; try { await apiRequest(endpoint, { method: 'POST', body: JSON.stringify(payload), skipAuth: true, }); toast(tab === 'register' ? '注册成功,欢迎加入' : '登录成功'); onAuthed(); } catch (ex) { setErr(errText(ex.code || ex.message)); } finally { setLoading(false); } } return (
{'>'} OpenClaw 🦞 云托管控制台