full-stack/client/src/pages/Register.tsx
2025-06-17 18:23:58 +08:00

143 lines
4.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Form, Input, Button, Card, Space, Typography, Alert } from 'antd';
import { UserOutlined, LockOutlined, CheckSquareOutlined, MailOutlined } from '@ant-design/icons';
import { api } from '../api/axios';
const { Title, Text, Link } = Typography;
function Register() {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const navigate = useNavigate();
const onFinish = async (values: any) => {
setLoading(true);
setError(null);
try {
await api.post('/auth/register', {
username: values.username,
email: values.email,
password: values.password,
});
navigate('/login');
} catch (err: any) {
const errorMessage = err.response?.data?.message || '注册失败,用户名可能已被占用或服务器错误。';
setError(errorMessage);
} finally {
setLoading(false);
}
};
return (
<div className="flex items-center justify-center min-h-screen bg-gray-100" style={{ background: '#f0f2f5',height: '100vh',display: 'flex',alignItems: 'center',justifyContent: 'center' }}>
<Card
className="w-full max-w-sm"
variant="borderless"
style={{
boxShadow: '0 4px 8px rgba(0, 0, 0, 0.1)',
padding: '40px 24px 24px',
textAlign: 'center',
width: '500px',
margin: '0 auto 200px',
}}
>
<Space direction="vertical" size="large" style={{ width: '100%' }}>
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', marginBottom: 24 }}>
<CheckSquareOutlined style={{ fontSize: '48px', color: '#1890ff' }} />
<Title level={2} style={{ margin: '8px 0 0' }}>Todo List</Title>
<Text type="secondary"></Text>
</div>
{error && (
<Alert
message="注册失败"
description={error}
type="error"
showIcon
closable
onClose={() => setError(null)}
style={{ marginBottom: 24 }}
/>
)}
<Form
name="register"
initialValues={{ remember: true }}
onFinish={onFinish}
autoComplete="off"
layout="vertical"
style={{ width: '100%' }}
>
<Form.Item
name="username"
rules={[{ required: true, message: '请输入用户名!' }]}
>
<Input
prefix={<UserOutlined className="site-form-item-icon" />}
placeholder="用户名"
size="large"
/>
</Form.Item>
<Form.Item
name="email"
rules={[{ required: true, message: '请输入邮箱!' }, { type: 'email', message: '请输入有效的邮箱地址!' }]}
>
<Input
prefix={<MailOutlined className="site-form-item-icon" />}
placeholder="邮箱"
size="large"
/>
</Form.Item>
<Form.Item
name="password"
rules={[{ required: true, message: '请输入密码!' }]}
>
<Input.Password
prefix={<LockOutlined className="site-form-item-icon" />}
placeholder="密码"
size="large"
/>
</Form.Item>
<Form.Item
name="confirm"
dependencies={['password']}
hasFeedback
rules={[
{ required: true, message: '请确认您的密码!' },
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue('password') === value) {
return Promise.resolve();
}
return Promise.reject(new Error('两次输入的密码不一致!'));
},
}),
]}
>
<Input.Password
prefix={<LockOutlined className="site-form-item-icon" />}
placeholder="确认密码"
size="large"
/>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" className="w-full" size="large" style={{width: '100%',}} loading={loading}>
</Button>
</Form.Item>
<div style={{ textAlign: 'right' }}>
<Link href="/login"></Link>
</div>
</Form>
</Space>
</Card>
</div>
);
}
export default Register;