40 lines
2.0 KiB
TypeScript
40 lines
2.0 KiB
TypeScript
import { FormEvent, useState } from "react";
|
||
import { api, type Session, tokenStore } from "./api";
|
||
import { Brand, Icon, navigate } from "./ui";
|
||
|
||
export function LoginPage({ onLogin }: { onLogin: (session: Session) => void }) {
|
||
const [username, setUsername] = useState("");
|
||
const [password, setPassword] = useState("");
|
||
const [error, setError] = useState("");
|
||
const [loading, setLoading] = useState(false);
|
||
|
||
async function submit(event: FormEvent) {
|
||
event.preventDefault();
|
||
setError(""); setLoading(true);
|
||
try {
|
||
const response = await api.login(username.trim(), password);
|
||
tokenStore.set(response.accessToken);
|
||
onLogin(response.session);
|
||
} catch (reason) {
|
||
setError(reason instanceof Error ? reason.message : "登录失败");
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
}
|
||
|
||
return <main className="login-page">
|
||
<button className="login-back" onClick={() => navigate("home")}><Icon name="arrow" size={16} />返回开放平台</button>
|
||
<section className="login-panel">
|
||
<Brand />
|
||
<div className="login-heading"><h1>登录开放平台</h1><p>使用平台管理员账号,或由管理员创建的合作伙伴账号。</p></div>
|
||
<form onSubmit={submit}>
|
||
<label>登录账号<input autoFocus autoComplete="username" value={username} onChange={(event) => setUsername(event.target.value)} placeholder="请输入账号" /></label>
|
||
<label>密码<input type="password" autoComplete="current-password" value={password} onChange={(event) => setPassword(event.target.value)} placeholder="请输入密码" /></label>
|
||
{error && <div className="form-error" role="alert">{error}</div>}
|
||
<button className="button primary large full" disabled={loading || !username.trim() || !password}>{loading ? "正在登录…" : "登录控制台"}</button>
|
||
</form>
|
||
<div className="login-help"><Icon name="shield" size={17} /><p><b>两类账号,同一入口</b><span>管理员使用内部车辆平台身份;合作伙伴使用独立开放平台账号。</span></p></div>
|
||
</section>
|
||
</main>;
|
||
}
|