feat: complete login and user management flow
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { ShieldCheck } from 'lucide-react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { adminApi, clientApi, type CaptchaResponse } from '@/api/adminApi';
|
||||
import { writeSession, type Portal } from '@/api/session';
|
||||
import { Button, Input } from '@/components/ui';
|
||||
|
||||
type LoginPageProps = {
|
||||
portal: Portal;
|
||||
};
|
||||
|
||||
export function LoginPage({ portal }: LoginPageProps) {
|
||||
const navigate = useNavigate();
|
||||
const [login, setLogin] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const [captchaText, setCaptchaText] = useState('');
|
||||
const [captcha, setCaptcha] = useState<CaptchaResponse | null>(null);
|
||||
const [error, setError] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const isAdmin = portal === 'admin';
|
||||
|
||||
async function refreshCaptcha() {
|
||||
setError('');
|
||||
setCaptchaText('');
|
||||
setCaptcha(await (isAdmin ? adminApi.getCaptcha() : clientApi.getCaptcha()));
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
void refreshCaptcha();
|
||||
}, [portal]);
|
||||
|
||||
async function submit() {
|
||||
if (!captcha) return;
|
||||
setLoading(true);
|
||||
setError('');
|
||||
try {
|
||||
const session = await (isAdmin ? adminApi.login : clientApi.login)({
|
||||
login,
|
||||
password,
|
||||
captchaId: captcha.captchaId,
|
||||
captchaText,
|
||||
});
|
||||
writeSession(session);
|
||||
navigate(isAdmin ? '/admin' : '/client', { replace: true });
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : '登录失败');
|
||||
await refreshCaptcha();
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="login-page">
|
||||
<section className="login-panel">
|
||||
<div className="login-brand">
|
||||
<span><ShieldCheck size={28} /></span>
|
||||
<div>
|
||||
<h1>{isAdmin ? 'CMPP 运营端' : 'CMPP 客户端'}</h1>
|
||||
<p>{isAdmin ? '平台管理员登录' : '企业管理员登录'}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="login-form">
|
||||
<Input label="邮箱或手机号" onChange={(event) => setLogin(event.target.value)} placeholder="请输入邮箱或手机号" value={login} />
|
||||
<Input label="密码" onChange={(event) => setPassword(event.target.value)} placeholder="请输入密码" type="password" value={password} />
|
||||
<div className="login-captcha-row">
|
||||
<Input label="图形验证码" onChange={(event) => setCaptchaText(event.target.value)} placeholder="请输入计算结果" value={captchaText} />
|
||||
<button className="login-captcha" onClick={() => void refreshCaptcha()} type="button">
|
||||
{captcha?.challenge ?? '刷新'}
|
||||
</button>
|
||||
</div>
|
||||
{error ? <p className="login-error">{error}</p> : null}
|
||||
<Button disabled={loading} onClick={submit}>{loading ? '登录中...' : '登录'}</Button>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user