import { useState } from 'react';
|
import {
|
ApartmentOutlined,
|
CheckCircleFilled,
|
LockOutlined,
|
MobileOutlined,
|
} from '@ant-design/icons';
|
import { App as AntdApp, Button, Form, Input, Tag } from 'antd';
|
import { Navigate, useLocation, useNavigate } from 'react-router-dom';
|
import { useAuthStore } from '@/store/auth';
|
import type { LoginParams } from '@/types/auth';
|
import './Login.scss';
|
|
const Login = () => {
|
const [form] = Form.useForm<LoginParams>();
|
const [loading, setLoading] = useState(false);
|
|
const token = useAuthStore((state) => state.token);
|
const login = useAuthStore((state) => state.login);
|
const navigate = useNavigate();
|
const location = useLocation();
|
const { message } = AntdApp.useApp();
|
|
if (token) {
|
return <Navigate to="/dashboard" replace />;
|
}
|
|
const from = (location.state as { from?: string } | null)?.from;
|
const redirectTo = from && from.startsWith('/') && from !== '/login' ? from : '/dashboard';
|
|
const handleFinish = async (values: LoginParams) => {
|
setLoading(true);
|
try {
|
await login(values);
|
message.success('登录成功,欢迎回来');
|
navigate(redirectTo, { replace: true });
|
} catch (error) {
|
message.error(error instanceof Error ? error.message : '登录失败,请稍后重试');
|
} finally {
|
setLoading(false);
|
}
|
};
|
|
return (
|
<div className="login-page">
|
<div className="login-shell">
|
<section className="login-brand">
|
<div className="login-brand__logo">
|
<span>C</span>
|
CRM Admin
|
</div>
|
|
<div className="login-brand__content">
|
<h1>
|
让团队协作
|
<br />
|
更简单、更高效
|
</h1>
|
<p>一套开箱即用的 CRM 中后台管理系统,覆盖客户、订单与团队协作。</p>
|
<ul>
|
<li>
|
<CheckCircleFilled /> 清晰的多级菜单与信息架构
|
</li>
|
<li>
|
<CheckCircleFilled /> 登录态校验与安全的页面访问
|
</li>
|
<li>
|
<CheckCircleFilled /> 客户、订单、用户一站式管理
|
</li>
|
</ul>
|
</div>
|
|
<div className="login-brand__footer">Vite · React · TypeScript · Ant Design</div>
|
</section>
|
|
<section className="login-panel">
|
<div className="login-panel__inner">
|
<div className="login-panel__header">
|
<Tag color="purple" bordered={false}>
|
CRM 企业管理平台
|
</Tag>
|
<h2>欢迎回来 👋</h2>
|
<p>请登录你的账号以继续访问后台</p>
|
</div>
|
|
<Form
|
form={form}
|
layout="vertical"
|
size="large"
|
requiredMark={false}
|
onFinish={handleFinish}
|
>
|
<Form.Item
|
name="tenant"
|
label="租户"
|
rules={[
|
{ required: true, whitespace: true, message: '请输入租户标识' },
|
]}
|
>
|
<Input
|
prefix={<ApartmentOutlined />}
|
placeholder="请输入租户标识"
|
autoComplete="organization"
|
/>
|
</Form.Item>
|
|
<Form.Item
|
name="phone"
|
label="手机号"
|
rules={[
|
{ required: true, message: '请输入手机号' },
|
{ pattern: /^1\d{10}$/, message: '请输入正确的手机号' },
|
]}
|
>
|
<Input
|
prefix={<MobileOutlined />}
|
placeholder="请输入手机号"
|
autoComplete="tel"
|
maxLength={11}
|
/>
|
</Form.Item>
|
|
<Form.Item
|
name="password"
|
label="密码"
|
rules={[{ required: true, message: '请输入密码' }]}
|
>
|
<Input.Password
|
prefix={<LockOutlined />}
|
placeholder="请输入密码"
|
autoComplete="current-password"
|
/>
|
</Form.Item>
|
|
<div className="login-panel__helper">
|
<span>登录即表示同意平台使用规范</span>
|
<a onClick={() => message.info('请联系系统管理员重置密码')}>忘记密码?</a>
|
</div>
|
|
<Button type="primary" htmlType="submit" block loading={loading}>
|
登 录
|
</Button>
|
</Form>
|
</div>
|
</section>
|
</div>
|
</div>
|
);
|
};
|
|
export default Login;
|