wsj
5 days ago be8c526a454aa9081000d15f26bebdef8c183aea
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
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;