// ─── 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 (
{/* Left: shrimp tank hero */}
TANK_01 · 水族缸
24.0°C · PH 7.2
{/* Right: auth card */}
xiaoxia.login
v4.2.0

欢迎回到 小虾

{'>'} OpenClaw 🦞 云托管控制台

setEmail(e.target.value)} placeholder="you@example.com" required autoComplete="email"/>
setPwd(e.target.value)} placeholder="至少 6 位" required minLength={6} autoComplete="current-password"/>
{tab === 'register' && requireInvite && (
setCode(e.target.value)} placeholder="happy-panda-1234" required autoComplete="off"/>
{'// 注册需要邀请码,可向已注册用户索取'}
)} {err && (
⚠ {err}
)}
提交   TAB 切换
CONN: ● OK
); } window.AuthScreen = AuthScreen;