imeeting/frontend/src/pages/Login.tsx

175 lines
5.4 KiB
TypeScript
Raw Normal View History

import { Button, Checkbox, Form, Input, message, Typography } from "antd";
import { useEffect, useState } from "react";
import { fetchCaptcha, login, type CaptchaResponse } from "../api/auth";
import { getCurrentUser, getSystemParamValue } from "../api";
import "./Login.css";
const { Title, Text, Link } = Typography;
export default function Login() {
const [captcha, setCaptcha] = useState<CaptchaResponse | null>(null);
const [captchaEnabled, setCaptchaEnabled] = useState(true);
const [loading, setLoading] = useState(false);
const [form] = Form.useForm();
const loadCaptcha = async () => {
if (!captchaEnabled) {
return;
}
try {
const data = await fetchCaptcha();
setCaptcha(data);
} catch (e) {
message.error("加载验证码失败");
}
};
useEffect(() => {
const init = async () => {
try {
const value = await getSystemParamValue("security.captcha.enabled", "true");
const enabled = value !== "false";
setCaptchaEnabled(enabled);
if (enabled) {
loadCaptcha();
}
} catch (e) {
setCaptchaEnabled(true);
loadCaptcha();
}
};
init();
}, []);
const onFinish = async (values: any) => {
setLoading(true);
try {
const data = await login({
username: values.username,
password: values.password,
captchaId: captchaEnabled ? captcha?.captchaId : undefined,
captchaCode: captchaEnabled ? values.captchaCode : undefined
});
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 || "登录失败");
if (captchaEnabled) {
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>
{captchaEnabled && (
<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>
);
}