blob: 0023b71373c3167cbd622f125b9ba7689622563e [file] [log] [blame]
22301014bc4616f2025-06-03 16:59:44 +08001import { useEffect, useState } from 'react';
2import { LockOutlined, MailOutlined, NumberOutlined, UserOutlined } from '@ant-design/icons';
2230101462240ab2025-06-07 09:28:16 +08003import { Button, Checkbox, Form, Input, message, Space } from 'antd';
4import { NavLink, useNavigate } from 'react-router';
5import authApi from "../../api/authApi";
6import type { RejisterRequest } from "../../api/type";
7import type { AxiosResponse } from 'axios';
22301014bc4616f2025-06-03 16:59:44 +08008
2230101462240ab2025-06-07 09:28:16 +08009// 定义表单字段的类型
22301014bc4616f2025-06-03 16:59:44 +080010interface FormValues {
11 name: string;
12 email: string;
13 verifyCode: string;
14 password: string;
15 confirmPassword: string;
16 agreement: boolean;
17}
18
19function Register() {
20 const [countdown, setCountdown] = useState(0);
21 const [form] = Form.useForm<FormValues>();
2230101462240ab2025-06-07 09:28:16 +080022 const emailValue = Form.useWatch('email', form);
23 const [messageApi, contextHolder] = message.useMessage();
24 const nav = useNavigate(); // 用于页面跳转
223010146abadd72025-06-05 14:21:13 +080025
2230101462240ab2025-06-07 09:28:16 +080026 // 校验邮箱格式
223010146abadd72025-06-05 14:21:13 +080027 function isValidEmail(email: string): boolean {
28 const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
223010146abadd72025-06-05 14:21:13 +080029 return emailRegex.test(email);
30 }
22301014bc4616f2025-06-03 16:59:44 +080031
2230101462240ab2025-06-07 09:28:16 +080032 // 发送验证码
22301014bc4616f2025-06-03 16:59:44 +080033 const sendVerificationCode = () => {
223010146abadd72025-06-05 14:21:13 +080034 if (!isValidEmail(emailValue)) {
2230102371ee1c92025-06-05 16:18:32 +080035 form.validateFields(['email']);
223010146abadd72025-06-05 14:21:13 +080036 return;
37 }
2230102371ee1c92025-06-05 16:18:32 +080038
2230101462240ab2025-06-07 09:28:16 +080039 authApi.sendVerificationCode(emailValue).then(() => {
40 setCountdown(60); // 开始倒计时
41 }).catch((error) => {
42 messageApi.error(error?.message || '验证码发送失败');
43 });
2230102371ee1c92025-06-05 16:18:32 +080044 };
22301014bc4616f2025-06-03 16:59:44 +080045
2230101462240ab2025-06-07 09:28:16 +080046 // 倒计时处理
22301014bc4616f2025-06-03 16:59:44 +080047 useEffect(() => {
2230101462240ab2025-06-07 09:28:16 +080048 if (countdown === 0) return;
49 const timer = setInterval(() => {
50 setCountdown(prev => {
51 if (prev === 1) clearInterval(timer); // 倒计时结束
52 return prev - 1;
53 });
54 }, 1000);
22301014bc4616f2025-06-03 16:59:44 +080055
2230101462240ab2025-06-07 09:28:16 +080056 return () => clearInterval(timer);
22301014bc4616f2025-06-03 16:59:44 +080057 }, [countdown]);
58
22301014bc4616f2025-06-03 16:59:44 +080059 // 表单提交
60 const onFinish = (values: FormValues) => {
2230101462240ab2025-06-07 09:28:16 +080061 const registerRequest: RejisterRequest = {
62 username: values.name,
63 email: values.email,
64 verificationCode: values.verifyCode,
65 password: values.password,
66 };
67
68 authApi.register(registerRequest).then((response: AxiosResponse) => {
69 if (response.data.code === 200) {
70 messageApi.success("注册成功");
71 form.resetFields(); // 清空表单
72 setTimeout(() => {
73 nav('/login'); // 注册成功后跳转到登录页面
74 }, 1500);
75 } else {
76 messageApi.error(response.data.message);
77 }
78 }).catch((error) => {
79 messageApi.error(error?.message || '注册失败,请重试');
80 });
22301014bc4616f2025-06-03 16:59:44 +080081 };
82
83 return (
84 <Form
85 form={form}
86 style={{ maxWidth: 360 }}
87 onFinish={onFinish}
88 scrollToFirstError
89 >
90 <h2>注册</h2>
2230101462240ab2025-06-07 09:28:16 +080091 {contextHolder}
22301014bc4616f2025-06-03 16:59:44 +080092
93 <Form.Item
94 name="name"
95 rules={[{ required: true, message: '请输入用户名' }]}
96 >
97 <Input prefix={<UserOutlined />} placeholder="请输入用户名" />
98 </Form.Item>
99
100 <Form.Item
101 name="email"
22301014bc4616f2025-06-03 16:59:44 +0800102 rules={[{ required: true, message: '请输入邮箱' }, { type: 'email', message: '邮箱格式错误' }]}
103 >
104 <Input
105 prefix={<MailOutlined />}
106 placeholder="请输入邮箱"
107 />
108 </Form.Item>
109
110 <Form.Item
111 name="verifyCode"
112 rules={[{ required: true, message: '请填写验证码' }]}
113 >
114 <Space direction="horizontal" size="small">
115 <Input
116 prefix={<NumberOutlined />}
117 placeholder="请输入验证码"
118 style={{ flex: 1 }}
119 />
120 <Button
223010146abadd72025-06-05 14:21:13 +0800121 disabled={countdown > 0}
22301014bc4616f2025-06-03 16:59:44 +0800122 onClick={sendVerificationCode}
223010146abadd72025-06-05 14:21:13 +0800123 color="primary"
22301014bc4616f2025-06-03 16:59:44 +0800124 style={{ width: 120 }}
125 >
126 {countdown > 0 ? `${countdown}s后重试` : '发送验证码'}
127 </Button>
128 </Space>
129 </Form.Item>
130
131 <Form.Item
132 name="password"
133 rules={[
134 { required: true, message: '请输入密码' },
135 { min: 6, message: '密码长度至少为6位' },
136 ]}
137 >
138 <Input.Password
139 prefix={<LockOutlined />}
140 placeholder="请输入密码"
141 />
142 </Form.Item>
143
144 <Form.Item
145 name="confirmPassword"
146 dependencies={['password']}
147 rules={[
148 { required: true, message: '请确认密码' },
149 ({ getFieldValue }) => ({
150 validator(_, value) {
151 if (!value || getFieldValue('password') === value) {
152 return Promise.resolve();
153 }
154 return Promise.reject('两次输入的密码不一致');
155 },
156 }),
157 ]}
158 >
159 <Input.Password
160 prefix={<LockOutlined />}
161 placeholder="请确认密码"
162 />
163 </Form.Item>
164
165 <Form.Item
166 name="agreement"
167 valuePropName="checked"
168 rules={[
169 {
170 validator: (_, value) =>
171 value ? Promise.resolve() : Promise.reject('请阅读并同意用户协议'),
172 },
173 ]}
174 >
175 <Checkbox>我已阅读并同意用户协议:<a>《创驿平台用户协议》</a></Checkbox>
176 </Form.Item>
177
178 <Form.Item>
179 <Button
180 type="primary"
181 htmlType="submit"
182 style={{ width: '100%' }}
183 >
184 注册
185 </Button>
186 <NavLink to='/login'>返回登录</NavLink>
187 </Form.Item>
188 </Form>
189 );
190}
191
2230101462240ab2025-06-07 09:28:16 +0800192export default Register;