imeeting/frontend/src/pages/Login.tsx

154 lines
4.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import { Button, Checkbox, Form, Input, message, Typography } from "antd";
import { useEffect, useState } from "react";
import { fetchCaptcha, login, type CaptchaResponse } from "../api/auth";
import { getCurrentUser } from "../api";
import "./Login.css";
const { Title, Text, Link } = Typography;
export default function Login() {
const [captcha, setCaptcha] = useState<CaptchaResponse | null>(null);
const [loading, setLoading] = useState(false);
const [form] = Form.useForm();
const loadCaptcha = async () => {
try {
const data = await fetchCaptcha();
setCaptcha(data);
} catch (e) {
message.error("加载验证码失败");
}
};
useEffect(() => {
loadCaptcha();
}, []);
const onFinish = async (values: any) => {
setLoading(true);
try {
const data = await login({
username: values.username,
password: values.password,
captchaId: captcha?.captchaId || "",
captchaCode: values.captchaCode
});
localStorage.setItem("accessToken", data.accessToken);
localStorage.setItem("refreshToken", data.refreshToken);
localStorage.setItem("username", values.username);
try {
const profile = await getCurrentUser();
sessionStorage.setItem("userProfile", JSON.stringify(profile));
} catch (e) {
sessionStorage.removeItem("userProfile");
}
message.success("登录成功");
window.location.href = "/";
} catch (e: any) {
message.error(e.message || "登录失败");
loadCaptcha();
} finally {
setLoading(false);
}
};
return (
<div className="login-page">
<div className="login-left">
<div className="login-brand">
<img src="/logo.svg" alt="logo" className="brand-logo-img" />
<span className="brand-name">MeetingAI</span>
</div>
<div className="login-hero">
<h1 className="hero-title">
<br />
<span className="hero-accent"></span><br />
</h1>
<p className="hero-desc">
<br />
</p>
</div>
<div className="login-left-footer">
<div className="footer-item"></div>
<div className="footer-divider" />
<div className="footer-item"></div>
</div>
</div>
<div className="login-right">
<div className="login-container">
<div className="login-header">
<Title level={2}></Title>
<Text type="secondary"></Text>
</div>
<Form
form={form}
layout="vertical"
onFinish={onFinish}
className="login-form"
requiredMark={false}
>
<Form.Item
label="用户名"
name="username"
rules={[{ required: true, message: "请输入用户名" }]}
>
<Input size="large" placeholder="请输入用户名" />
</Form.Item>
<Form.Item
label="密码"
name="password"
rules={[{ required: true, message: "请输入密码" }]}
>
<Input.Password size="large" placeholder="请输入密码" />
</Form.Item>
<Form.Item
label="验证码"
name="captchaCode"
rules={[{ required: true, message: "请输入验证码" }]}
>
<div className="captcha-wrapper">
<Input size="large" placeholder="验证码" />
<div className="captcha-image-container" onClick={loadCaptcha}>
{captcha ? (
<img src={captcha.imageBase64} alt="captcha" />
) : (
<div className="captcha-placeholder" />
)}
</div>
</div>
</Form.Item>
<div className="login-extra">
<Form.Item name="remember" valuePropName="checked" noStyle>
<Checkbox></Checkbox>
</Form.Item>
<Link className="forgot-password"></Link>
</div>
<Form.Item>
<Button type="primary" htmlType="submit" loading={loading} block size="large">
</Button>
</Form.Item>
</Form>
<div className="login-footer">
<Text type="secondary">
<Text strong>admin</Text> / <Text strong>123456</Text>
</Text>
</div>
</div>
</div>
</div>
);
}