128 lines
3.8 KiB
TypeScript
128 lines
3.8 KiB
TypeScript
/**
|
|
* 重置密码页面
|
|
*/
|
|
import React from 'react';
|
|
import { Form, Input, Button, Card, message, Result } from 'antd';
|
|
import { LockOutlined } from '@ant-design/icons';
|
|
import { Link, useSearchParams, useNavigate } from 'react-router-dom';
|
|
import { useMutation } from '@tanstack/react-query';
|
|
import { resetPassword } from '@/api/auth';
|
|
import './ResetPassword.css';
|
|
|
|
const ResetPassword: React.FC = () => {
|
|
const [form] = Form.useForm();
|
|
const [searchParams] = useSearchParams();
|
|
const navigate = useNavigate();
|
|
const token = searchParams.get('token');
|
|
|
|
const resetMutation = useMutation({
|
|
mutationFn: (password: string) => resetPassword(token!, password),
|
|
onSuccess: () => {
|
|
message.success('密码重置成功!');
|
|
setTimeout(() => navigate('/login'), 2000);
|
|
},
|
|
onError: (error: any) => {
|
|
message.error(error.response?.data?.message || '重置失败,请重试');
|
|
},
|
|
});
|
|
|
|
const onFinish = (values: { password: string }) => {
|
|
resetMutation.mutate(values.password);
|
|
};
|
|
|
|
if (!token) {
|
|
return (
|
|
<div className="reset-password-container">
|
|
<Card className="reset-password-card">
|
|
<Result
|
|
status="error"
|
|
title="无效的重置链接"
|
|
subTitle="该链接无效或已过期,请重新申请密码重置。"
|
|
extra={[
|
|
<Link to="/forgot-password" key="forgot">
|
|
<Button type="primary">重新申请</Button>
|
|
</Link>,
|
|
]}
|
|
/>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (resetMutation.isSuccess) {
|
|
return (
|
|
<div className="reset-password-container">
|
|
<Card className="reset-password-card">
|
|
<Result
|
|
status="success"
|
|
title="密码重置成功"
|
|
subTitle="您的密码已成功重置,即将跳转到登录页面..."
|
|
extra={[
|
|
<Link to="/login" key="login">
|
|
<Button type="primary">立即登录</Button>
|
|
</Link>,
|
|
]}
|
|
/>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="reset-password-container">
|
|
<Card className="reset-password-card" title="设置新密码">
|
|
<Form form={form} name="reset-password" onFinish={onFinish} size="large">
|
|
<Form.Item
|
|
name="password"
|
|
rules={[
|
|
{ required: true, message: '请输入新密码' },
|
|
{ min: 8, message: '密码至少 8 个字符' },
|
|
{
|
|
pattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/,
|
|
message: '密码必须包含大小写字母和数字',
|
|
},
|
|
]}
|
|
>
|
|
<Input.Password prefix={<LockOutlined />} placeholder="新密码" />
|
|
</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>
|
|
<Button
|
|
type="primary"
|
|
htmlType="submit"
|
|
loading={resetMutation.isPending}
|
|
block
|
|
>
|
|
重置密码
|
|
</Button>
|
|
</Form.Item>
|
|
|
|
<div style={{ textAlign: 'center' }}>
|
|
<Link to="/login">返回登录</Link>
|
|
</div>
|
|
</Form>
|
|
</Card>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default ResetPassword;
|