Files
Wardrobe/src/pages/Login.tsx
T

107 lines
4.2 KiB
TypeScript

import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { sendCode, register, login } from "../api";
import { useAppStore } from "../stores/app";
import { useAuthStore } from "../stores/auth";
export default function Login() {
const navigate = useNavigate();
const { account, code, nickname, isRegister, loading, setAccount, setCode, setNickname, setMode, setLoading } = useAuthStore();
const setUser = useAppStore((s) => s.setUser);
const [status, setStatus] = useState("");
const isEmail = account.includes("@");
const canSendCode = account.length >= 6;
const handleSendCode = async () => {
setLoading(true);
setStatus("");
try {
const result = await sendCode(account);
setStatus(result);
} catch (e) {
setStatus(String(e));
} finally {
setLoading(false);
}
};
const handleSubmit = async () => {
setLoading(true);
setStatus("");
try {
const email = isEmail ? account : null;
const phone = isEmail ? null : account;
const result = isRegister
? await register(email, phone, code, nickname || "时尚达人")
: await login(email, phone, code);
if (result.success && result.user) {
setUser(result.user, result.token);
navigate("/home", { replace: true });
} else {
setStatus(result.message);
}
} catch (e) {
setStatus(String(e));
} finally {
setLoading(false);
}
};
return (
// 登录页: 上边框相对此前 0 下移一个行高 (20px), 同时避开状态栏/刘海
<div style={{ height: "100%", display: "flex", flexDirection: "column", justifyContent: "center", padding: "calc(env(safe-area-inset-top) + 20px) 28px 0", maxWidth: 420, margin: "0 auto" }}>
<div style={{ textAlign: "center", marginBottom: 40 }}>
<div style={{ fontSize: 56, marginBottom: 8 }}>👕</div>
<h1 style={{ fontSize: 32, letterSpacing: -0.5 }}>Wardrobe</h1>
<p style={{ color: "var(--text-secondary)", fontSize: 14, marginTop: 4 }}>你的 AI 穿搭私人管家</p>
</div>
<div className="card" style={{ padding: 24 }}>
<div style={{ display: "flex", gap: 8, marginBottom: 20 }}>
<button
style={{ flex: 1, padding: "10px 0", borderRadius: "var(--radius-sm)", fontWeight: 600, fontSize: 14, background: isRegister ? "transparent" : "var(--text-primary)", color: isRegister ? "var(--text-secondary)" : "#fff" }}
onClick={() => setMode("login")}
>
登录
</button>
<button
style={{ flex: 1, padding: "10px 0", borderRadius: "var(--radius-sm)", fontWeight: 600, fontSize: 14, background: isRegister ? "var(--text-primary)" : "transparent", color: isRegister ? "#fff" : "var(--text-secondary)" }}
onClick={() => setMode("register")}
>
注册
</button>
</div>
<div className="input-group">
<label>{isEmail ? "邮箱" : "手机号"}</label>
<input className="input" placeholder={isEmail ? "you@example.com" : "13800001234"} value={account} onChange={(e) => setAccount(e.target.value.trim())} />
</div>
{isRegister && (
<div className="input-group">
<label>昵称</label>
<input className="input" placeholder="你的昵称" value={nickname} onChange={(e) => setNickname(e.target.value)} />
</div>
)}
<div className="input-group">
<label>验证码</label>
<div className="code-row">
<input className="input" placeholder="验证码" maxLength={4} inputMode="numeric" value={code} onChange={(e) => setCode(e.target.value)} />
<button className="code-btn" disabled={!canSendCode || loading} onClick={handleSendCode}>
获取验证码
</button>
</div>
</div>
{status && <p style={{ fontSize: 13, color: status.includes("成功") ? "var(--success)" : "var(--danger)", marginBottom: 12 }}>{status}</p>}
<button className="btn btn-primary" disabled={loading || !account || code.length < 4} onClick={handleSubmit}>
{loading ? "处理中..." : isRegister ? "注册" : "登录"}
</button>
</div>
</div>
);
}