完善验证页面和后端接口的链接
> 1. 配置了开发环境的端口转发 -> localhost:8080\
> 2. 完成了注册,登录,忘记密码页的功能
> 3. 为项目配置了vitest测试框架
> 4. 对这三个页面进行了测试
> 重写了/test/setup.ts
Change-Id: I46c600ce06d698dae6953b2e1e3ff4a98b0f3de4
diff --git a/src/feature/auth/Forget.tsx b/src/feature/auth/Forget.tsx
index 25bf6dc..a98ffcf 100644
--- a/src/feature/auth/Forget.tsx
+++ b/src/feature/auth/Forget.tsx
@@ -1,16 +1,74 @@
import { MailOutlined, LockOutlined } from '@ant-design/icons';
-import { Button, Form, Input, message, Row, Col } from 'antd';
-import { NavLink } from 'react-router';
+import { Button, Form, Input, message, Row, Col, Modal } from 'antd';
+import { NavLink, useNavigate } from 'react-router';
import { useState, useEffect } from 'react';
+import { useForm } from 'antd/es/form/Form';
+import authApi from '../../api/authApi';
+
+// 定义表单值的类型
+interface FormValues {
+ email: string;
+ code: string;
+ password: string;
+ confirmPassword: string;
+}
+
function Forget() {
const [countdown, setCountdown] = useState(0);
- const [emailSent,] = useState(false);
+ const [emailSent, setEmailSent] = useState(false); // 是否已发送验证码
+ const [form] = useForm<FormValues>();
+ const emailValue = Form.useWatch('email', form);
+ const [messageApi, contextHolder] = message.useMessage();
+ const nav = useNavigate(); // 页面跳转
- const onFinish = async () => {
+ // 校验邮箱格式
+ function isValidEmail(email: string): boolean {
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
+ console.log(emailRegex.test(email))
+ console.log(email)
+ return emailRegex.test(email);
+ }
+ // 发送验证码
+ const sendResetCode = async () => {
+ if (!isValidEmail(emailValue)) {
+ form.validateFields(['email']);
+ return;
+ }
+
+ await authApi.sendResetCode(emailValue).then(() => {
+ setEmailSent(true);
+ setCountdown(60);
+ }).catch((error) => {
+ messageApi.error(error?.message || '验证码发送失败');
+ });
};
+ const [modal, modalContext] = Modal.useModal();
+
+ const countDownNav = (onOk: () => void) => {
+ let secondsToGo = 5;
+ const instance = modal.success({
+ title: '重置成功',
+ content: `系统将在 ${secondsToGo} 后跳转到登陆页面.`,
+ okText: "立即跳转",
+ onOk
+ });
+
+ const timer = setInterval(() => {
+ secondsToGo -= 1;
+ instance.update({
+ content: `将在 ${secondsToGo} 后回到登陆页面.`,
+ });
+ }, 1000);
+
+ setTimeout(() => {
+ clearInterval(timer);
+ instance.destroy();
+ }, secondsToGo * 1000);
+ };
+ // 倒计时发送
useEffect(() => {
let countdownTimer = null;
@@ -27,92 +85,117 @@
};
}, [countdown]);
+ // 重新发送验证码
const resendCode = () => {
if (countdown > 0) return;
setCountdown(60);
- message.info('验证码已重新发送');
+ sendResetCode(); // 重新发送验证码
+ };
+
+ // 表单提交处理
+ const onFinish = (values: FormValues) => {
+ if (!emailSent) {
+ sendResetCode();
+ } else {
+ console.log(values);
+ authApi.resetPassword({
+ email: values.email,
+ code: values.code,
+ newPassword: values.password,
+ }).then((response) => {
+ if (response.data.code == 0) {
+ countDownNav(() => nav('/login'))
+ } else {
+ messageApi.error(response.data.message);
+ }
+ })
+ }
};
return (
- <Form
- name="forget"
- initialValues={{ remember: true }}
- style={{ maxWidth: 360 }}
- onFinish={onFinish}
- >
- <h2>重置密码</h2>
- <p>请输入您注册时使用的邮箱地址</p>
-
- <Form.Item
- name="email"
- rules={[
- { required: true, message: '请输入您的邮箱!' },
- { type: 'email', message: '请输入正确的邮箱格式' }
- ]}
+ <>
+ <Form
+ form={form}
+ name="forget"
+ initialValues={{ remember: false }}
+ onFinish={onFinish}
>
- <Input prefix={<MailOutlined />} placeholder="注册邮箱" />
- </Form.Item>
+ {contextHolder}
+ <h2>重置密码</h2>
+ <p>请输入您注册时使用的邮箱地址</p>
- {emailSent && (
- <>
- <Form.Item
- name="code"
- rules={[{ required: true, message: '请输入验证码!' }]}
- >
- <Row gutter={8}>
- <Col span={16}>
- <Input placeholder="验证码" />
- </Col>
- <Col span={8}>
- <Button
- disabled={countdown > 0}
- onClick={resendCode}
- style={{ width: '100%' }}
- >
- {countdown > 0 ? `${countdown}s后重试` : '重新发送'}
- </Button>
- </Col>
- </Row>
- </Form.Item>
+ <Form.Item
+ name="email"
+ rules={[
+ { required: true, message: '请输入您的邮箱!' },
+ { type: 'email', message: '请输入正确的邮箱格式' }
+ ]}
+ >
+ <Input prefix={<MailOutlined />} placeholder="注册邮箱" />
+ </Form.Item>
- <Form.Item
- name="password"
- rules={[
- { required: true, message: '请设置新密码!' },
- { min: 6, message: '密码长度至少为6位' }
- ]}
- >
- <Input.Password prefix={<LockOutlined />} placeholder="新密码" />
- </Form.Item>
+ {emailSent && (
+ <>
+ <Form.Item
+ name="code"
+ rules={[{ required: true, message: '请输入验证码!' }]}
+ >
+ <Row gutter={8}>
+ <Col span={16}>
+ <Input placeholder="验证码" />
+ </Col>
+ <Col span={8}>
+ <Button
+ disabled={countdown > 0}
+ onClick={resendCode}
+ style={{ width: '100%' }}
+ >
+ {countdown > 0 ? `${countdown}s后重试` : '重新发送'}
+ </Button>
+ </Col>
+ </Row>
+ </Form.Item>
- <Form.Item
- name="confirmPassword"
- dependencies={['password']}
- rules={[
- { required: true, message: '请确认新密码!' },
- ({ getFieldValue }) => ({
- validator(_, value) {
- if (!value || getFieldValue('password') === value) {
- return Promise.resolve();
- }
- return Promise.reject(new Error('两次输入的密码不一致!'));
- },
- }),
- ]}
- >
- <Input.Password prefix={<LockOutlined />} placeholder="确认新密码" />
- </Form.Item>
- </>
- )}
+ <Form.Item
+ name="password"
+ rules={[
+ { required: true, message: '请设置新密码!' },
+ { min: 6, message: '密码长度至少为6位' }
+ ]}
+ >
+ <Input.Password prefix={<LockOutlined />} placeholder="新密码" />
+ </Form.Item>
- <Form.Item>
- <Button block type="primary" htmlType="submit">
- {emailSent ? '确认重置' : '获取验证码'}
- </Button>
- 或 <NavLink to='/login'>返回登录</NavLink>
- </Form.Item>
- </Form>
+ <Form.Item
+ name="confirmPassword"
+ dependencies={['password']}
+ rules={[
+ { required: true, message: '请确认新密码!' },
+ ({ getFieldValue }) => ({
+ validator(_, value) {
+ if (!value || getFieldValue('password') === value) {
+ return Promise.resolve();
+ }
+ return Promise.reject(new Error('两次输入的密码不一致!'));
+ },
+ }),
+ ]}
+ >
+ <Input.Password prefix={<LockOutlined />} placeholder="确认新密码" />
+ </Form.Item>
+ </>
+ )}
+
+ <Form.Item>
+ <Button block type="primary" htmlType="submit">
+ {emailSent ? '确认重置' : '获取验证码'}
+ </Button>
+ 或 <NavLink to='/login'>返回登录</NavLink>
+ </Form.Item>
+ </Form>
+ {modalContext}
+ </>
);
}
-export default Forget;
\ No newline at end of file
+export default Forget;