Files
chengshishouce/frontend/src/components/auth/RegisterPage.js
maoshen 6b3fdce1d3 完善 React 前端项目
主要改进:
- 新增 HomePage 组件,包含统计数据和内容展示
- 新增 ArticlesPage 和 ServicesPage 列表页,支持搜索和筛选
- 新增 UserProfilePage 个人中心页面
- 新增 NotFoundPage 404 页面
- 改进 Layout 组件,添加用户登录状态和动态导航
- 完善所有 Stores (AuthStore, UserStore, ArticleStore, ServiceStore)
- 优化全局样式和响应式设计
- 添加环境变量配置
- 修复构建警告

技术栈:
- React 18 + MobX + React Router v6 + Styled Components
2026-04-15 05:16:32 +00:00

175 lines
3.8 KiB
JavaScript
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 styled from 'styled-components';
import { observer } from 'mobx-react-lite';
import { useAuthStore } from '../../stores/AuthStore';
import { useNavigate } from 'react-router-dom';
const Container = styled.div`
max-width: 400px;
margin: 50px auto;
padding: 30px;
background: white;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
`;
const Title = styled.h2`
text-align: center;
margin-bottom: 30px;
color: #333;
`;
const Form = styled.form`
display: flex;
flex-direction: column;
gap: 15px;
`;
const InputGroup = styled.div`
display: flex;
flex-direction: column;
gap: 5px;
`;
const Label = styled.label`
font-weight: 500;
color: #555;
`;
const Input = styled.input`
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
&:focus {
outline: none;
border-color: #667eea;
}
`;
const Button = styled.button`
padding: 12px;
background: #667eea;
color: white;
border: none;
border-radius: 4px;
font-size: 16px;
font-weight: 500;
cursor: pointer;
transition: background 0.2s;
&:hover {
background: #5568d3;
}
&:disabled {
background: #ccc;
cursor: not-allowed;
}
`;
const ErrorMessage = styled.div`
color: #dc3545;
font-size: 14px;
text-align: center;
background: #f8d7da;
padding: 10px;
border-radius: 4px;
`;
const Link = styled.a`
text-align: center;
color: #667eea;
text-decoration: none;
font-size: 14px;
display: block;
margin-top: 15px;
&:hover {
text-decoration: underline;
}
`;
const RegisterPage = observer(() => {
const navigate = useNavigate();
const authStore = useAuthStore();
const [username, setUsername] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [confirmPassword, setConfirmPassword] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
const result = await authStore.register(username, email, password, confirmPassword);
if (result.success) {
navigate('/');
}
};
return (
<Container>
<Title>注册账号</Title>
<Form onSubmit={handleSubmit}>
{authStore.error && <ErrorMessage>{authStore.error}</ErrorMessage>}
<InputGroup>
<Label>用户名</Label>
<Input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder="请输入用户名"
required
disabled={authStore.loading}
/>
</InputGroup>
<InputGroup>
<Label>邮箱</Label>
<Input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="请输入邮箱"
required
disabled={authStore.loading}
/>
</InputGroup>
<InputGroup>
<Label>密码</Label>
<Input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="请输入密码"
required
disabled={authStore.loading}
/>
</InputGroup>
<InputGroup>
<Label>确认密码</Label>
<Input
type="password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
placeholder="请再次输入密码"
required
disabled={authStore.loading}
/>
</InputGroup>
<Button type="submit" disabled={authStore.loading}>
{authStore.loading ? '注册中...' : '注册'}
</Button>
</Form>
<Link href="/login">已有账号立即登录</Link>
</Container>
);
});
export default RegisterPage;