From e627e3f57940ab0acb6cda0948c0d37fddd34bec Mon Sep 17 00:00:00 2001 From: mashen Date: Thu, 9 Apr 2026 13:49:10 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E8=AE=A4=E8=AF=81=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - LoginPage(登录页) - RegisterPage(注册页) - 更新 App.js 路由配置 - 集成 AuthStore --- frontend/src/App.js | 4 + frontend/src/components/auth/LoginPage.js | 143 ++++++++++++++++ frontend/src/components/auth/RegisterPage.js | 161 +++++++++++++++++++ 3 files changed, 308 insertions(+) create mode 100644 frontend/src/components/auth/LoginPage.js create mode 100644 frontend/src/components/auth/RegisterPage.js diff --git a/frontend/src/App.js b/frontend/src/App.js index 6bec285..4f6b890 100644 --- a/frontend/src/App.js +++ b/frontend/src/App.js @@ -10,6 +10,8 @@ import CitiesPage from './components/region/CitiesPage'; import CityDetailPage from './components/region/CityDetailPage'; import ArticleDetailPage from './components/article/ArticleDetailPage'; import ServiceDetailPage from './components/service/ServiceDetailPage'; +import LoginPage from './components/auth/LoginPage'; +import RegisterPage from './components/auth/RegisterPage'; const Container = styled.div` max-width: 1200px; @@ -46,6 +48,8 @@ function App() { } /> } /> } /> + } /> + } /> } /> } /> diff --git a/frontend/src/components/auth/LoginPage.js b/frontend/src/components/auth/LoginPage.js new file mode 100644 index 0000000..f112340 --- /dev/null +++ b/frontend/src/components/auth/LoginPage.js @@ -0,0 +1,143 @@ +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; +`; + +const Link = styled.a` + text-align: center; + color: #667eea; + text-decoration: none; + font-size: 14px; + + &:hover { + text-decoration: underline; + } +`; + +const LoginPage = observer(() => { + const authStore = useAuthStore(); + const navigate = useNavigate(); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + + const handleSubmit = async (e) => { + e.preventDefault(); + const result = await authStore.login(email, password); + if (result.success) { + navigate('/'); + } + }; + + return ( + + 登录 +
+ {authStore.error && ( + {authStore.error} + )} + + + + setEmail(e.target.value)} + placeholder="请输入邮箱" + required + /> + + + + + setPassword(e.target.value)} + placeholder="请输入密码" + required + /> + + + +
+ + 没有账号?立即注册 +
+ ); +}); + +export default LoginPage; \ No newline at end of file diff --git a/frontend/src/components/auth/RegisterPage.js b/frontend/src/components/auth/RegisterPage.js new file mode 100644 index 0000000..3640a4a --- /dev/null +++ b/frontend/src/components/auth/RegisterPage.js @@ -0,0 +1,161 @@ +import React, { useState } from 'react'; +import styled from 'styled-components'; +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; + } +`; + +const Link = styled.a` + text-align: center; + color: #667eea; + text-decoration: none; + font-size: 14px; + + &:hover { + text-decoration: underline; + } +`; + +const RegisterPage = () => { + const navigate = useNavigate(); + const [username, setUsername] = useState(''); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [confirmPassword, setConfirmPassword] = useState(''); + const [error, setError] = useState(''); + + const handleSubmit = async (e) => { + e.preventDefault(); + setError(''); + + if (password !== confirmPassword) { + setError('两次输入的密码不一致'); + return; + } + + // TODO: 调用注册 API + console.log('Register:', { username, email, password }); + + navigate('/login'); + }; + + return ( + + 注册 +
+ {error && ( +
+ {error} +
+ )} + + + + setUsername(e.target.value)} + placeholder="请输入用户名" + required + /> + + + + + setEmail(e.target.value)} + placeholder="请输入邮箱" + required + /> + + + + + setPassword(e.target.value)} + placeholder="请输入密码" + required + /> + + + + + setConfirmPassword(e.target.value)} + placeholder="请再次输入密码" + required + /> + + + +
+ + 已有账号?立即登录 +
+ ); +}; + +export default RegisterPage; \ No newline at end of file