new change

This commit is contained in:
chenZB666
2025-10-09 23:40:40 +08:00
parent 0645948fcc
commit e1b73b82a2
5 changed files with 352 additions and 30 deletions

View File

@@ -6,6 +6,9 @@ import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { signIn } from 'next-auth/react';
import { register } from '@/lib/api/actions';
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { Eye, EyeOff } from 'lucide-react';
interface AuthFormProps {
type: 'login' | 'register';
@@ -17,6 +20,9 @@ export default function AuthForm({ type }: AuthFormProps) {
const [password, setPassword] = useState('');
const [email, setEmail] = useState('');
const [minecraftUsername, setMinecraftUsername] = useState('');
const [error, setError] = useState<string | null>(null);
const [success, setSuccess] = useState<string | null>(null);
const [showPassword, setShowPassword] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
@@ -24,39 +30,108 @@ export default function AuthForm({ type }: AuthFormProps) {
try {
if (type === 'login') {
// 使用next-auth的signIn功能进行登录
// 基本验证
if (!password) {
setError('请输入密码');
setIsLoading(false);
return;
}
const usernameField = username || email;
if (!usernameField) {
setError('请输入用户名或邮箱');
setIsLoading(false);
return;
}
// 使用next-auth的signIn功能进行登录设置redirect为false以便处理错误
const result = await signIn('credentials', {
username: username || email, // 使用username或email作为用户名字段
username: usernameField, // 使用username或email作为用户名字段
email: email, // 传递email字段
password,
redirect: true, // 登录成功后自动重定向
redirect: false, // 不自动重定向,以便处理错误
callbackUrl: '/user-home' // 指定重定向目标
});
console.log('登录结果:', result);
if (result?.error) {
// 处理登录错误 - 根据错误类型显示不同的错误信息
console.error('登录失败:', result.error);
if (result.error.includes('CredentialsSignin')) {
setError('用户名或密码错误,请重试');
} else if (result.error.includes('Network')) {
setError('网络连接失败,请检查您的网络设置');
} else {
setError('登录失败,请稍后再试');
}
} else if (result?.ok) {
// 登录成功,手动重定向
window.location.href = '/user-home';
} else {
setError('登录过程中发生未知错误');
}
} else {
// 注册逻辑可以在这里实现
console.log('注册信息', { username, password, email, minecraftUsername });
// 模拟注册请求
await new Promise(resolve => setTimeout(resolve, 1000));
// 调用注册API
const result = await register({
username,
password,
email,
minecraftUsername
});
if (result.success) {
setSuccess('注册成功!即将跳转到登录页面...');
// 注册成功后重定向到登录页面
setTimeout(() => {
window.location.href = '/login';
}, 2000);
} else {
setError(result.error || '注册失败,请稍后再试');
}
}
} catch (error) {
console.error('认证失败:', error);
// 这里可以添加错误处理逻辑
setError('网络错误,请检查您的连接');
} finally {
setIsLoading(false);
}
};
// 重置错误和成功消息
const resetMessages = () => {
setError(null);
setSuccess(null);
};
// 监听输入变化,清除错误消息
const handleInputChange = (setter: React.Dispatch<React.SetStateAction<string>>) => {
return (e: React.ChangeEvent<HTMLInputElement>) => {
resetMessages();
setter(e.target.value);
};
};
return (
<form onSubmit={handleSubmit} className="space-y-4">
{error && (
<Alert variant="destructive" className="bg-red-50 border-red-200 text-red-800">
<AlertTitle></AlertTitle>
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
{success && (
<Alert className="bg-green-50 border-green-200 text-green-800">
<AlertTitle></AlertTitle>
<AlertDescription>{success}</AlertDescription>
</Alert>
)}
<div>
<Label htmlFor="username"></Label>
<Input
id="username"
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
onChange={handleInputChange(setUsername)}
placeholder={type === 'login' ? "用户名或邮箱" : "输入用户名"}
/>
</div>
@@ -68,20 +143,29 @@ export default function AuthForm({ type }: AuthFormProps) {
id="email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
onChange={handleInputChange(setEmail)}
placeholder="或直接输入邮箱登录"
/>
</div>
)}
<div>
<Label htmlFor="password"></Label>
<Input
id="password"
type="password"
required
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
<div className="relative">
<Input
id="password"
type={showPassword ? "text" : "password"}
required
value={password}
onChange={handleInputChange(setPassword)}
/>
<button
type="button"
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-500 hover:text-gray-700 focus:outline-none"
onClick={() => setShowPassword(!showPassword)}
>
{showPassword ? <EyeOff size={18} /> : <Eye size={18} />}
</button>
</div>
</div>
{type === 'register' && (
@@ -89,22 +173,23 @@ export default function AuthForm({ type }: AuthFormProps) {
<div>
<Label htmlFor="email"></Label>
<Input
id="email"
type="email"
required
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
id="email"
type="email"
required
value={email}
onChange={handleInputChange(setEmail)}
/>
</div>
<div>
<Label htmlFor="minecraftUsername">Minecraft </Label>
<Input
id="minecraftUsername"
type="text"
required
value={minecraftUsername}
onChange={(e) => setMinecraftUsername(e.target.value)}
/>
id="minecraftUsername"
type="text"
required
value={minecraftUsername}
onChange={handleInputChange(setMinecraftUsername)}
placeholder="您的Minecraft游戏内用户名"
/>
</div>
</>
)}

View File

@@ -0,0 +1,51 @@
// src/components/ui/alert.tsx
import React from 'react';
interface AlertProps {
children: React.ReactNode;
variant?: 'default' | 'destructive';
className?: string;
}
interface AlertTitleProps {
children: React.ReactNode;
className?: string;
}
interface AlertDescriptionProps {
children: React.ReactNode;
className?: string;
}
// 主Alert组件
export function Alert({ children, variant = 'default', className = '' }: AlertProps) {
const baseClasses = 'p-4 rounded-lg border flex items-start space-x-3';
const variantClasses = {
default: 'bg-green-50 border-green-200 text-green-800',
destructive: 'bg-red-50 border-red-200 text-red-800'
};
return (
<div className={`${baseClasses} ${variantClasses[variant]} ${className}`}>
{children}
</div>
);
}
// Alert标题组件
export function AlertTitle({ children, className = '' }: AlertTitleProps) {
return (
<h3 className={`font-medium text-sm ${className}`}>
{children}
</h3>
);
}
// Alert描述组件
export function AlertDescription({ children, className = '' }: AlertDescriptionProps) {
return (
<p className={`text-sm ${className}`}>
{children}
</p>
);
}