mirror of
https://github.com/stackblitz/bolt.new
synced 2025-06-26 18:17:50 +00:00
feat: 修改登录功能以支持手机号登录
This commit is contained in:
parent
3955a13050
commit
2cd653bbdc
@ -1,33 +1,40 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useNavigate } from '@remix-run/react';
|
||||
import { useAuth } from '~/hooks/useAuth';
|
||||
import type { LoginResponse } from '~/routes/api.auth.login';
|
||||
|
||||
export function Login() {
|
||||
const [phone, setPhone] = useState('');
|
||||
const [password, setPassword] = useState('');
|
||||
const navigate = useNavigate();
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const { login } = useAuth();
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/auth/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ phone, password }),
|
||||
});
|
||||
if (response.ok) {
|
||||
const data = (await response.json()) as { token: string };
|
||||
localStorage.setItem('token', data.token);
|
||||
navigate('/dashboard');
|
||||
const data = (await response.json()) as LoginResponse;
|
||||
if (response.ok && data.token && data.user) {
|
||||
login(data.token, data.user);
|
||||
// 登录成功后的处理,例如重定向或显示成功消息
|
||||
} else {
|
||||
// 处理错误
|
||||
setError(data.error || '登录失败,请检查您的手机号和密码');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Login failed:', error);
|
||||
setError('登录失败,请稍后再试');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div>
|
||||
<label htmlFor="phone" className="block text-sm font-medium text-bolt-elements-textPrimary">
|
||||
手机号
|
||||
@ -54,6 +61,7 @@ export function Login() {
|
||||
className="mt-1 block w-full px-3 py-2 bg-bolt-elements-background-depth-1 border border-bolt-elements-borderColor rounded-md shadow-sm focus:outline-none focus:ring-bolt-elements-button-primary-background focus:border-bolt-elements-button-primary-background"
|
||||
/>
|
||||
</div>
|
||||
{error && <div className="text-red-500 text-sm mt-2">{error}</div>}
|
||||
<div>
|
||||
<button
|
||||
type="submit"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useNavigate } from '@remix-run/react';
|
||||
|
||||
interface User {
|
||||
export interface User {
|
||||
id: number;
|
||||
phone: string;
|
||||
nickname: string;
|
||||
|
||||
@ -3,6 +3,18 @@ import type { ActionFunction } from '@remix-run/node';
|
||||
import { validatePhoneNumber } from '~/utils/validation';
|
||||
import { verifyLogin, createToken } from '~/utils/auth.server';
|
||||
|
||||
export interface LoginResponse {
|
||||
success: boolean;
|
||||
token?: string;
|
||||
user?: {
|
||||
id: number;
|
||||
phone: string;
|
||||
nickname: string;
|
||||
avatarUrl: string;
|
||||
};
|
||||
error?: string;
|
||||
}
|
||||
|
||||
export const action: ActionFunction = async ({ request }) => {
|
||||
const { phone, password } = await request.json() as { phone: string, password: string };
|
||||
|
||||
|
||||
@ -8,8 +8,8 @@ export async function hashPassword(password: string) {
|
||||
return bcrypt.hash(password, 10);
|
||||
}
|
||||
|
||||
export async function verifyLogin(email: string, password: string) {
|
||||
const user = await db('users').where({ email }).first();
|
||||
export async function verifyLogin(phone: string, password: string) {
|
||||
const user = await db('users').where({ phone }).first();
|
||||
if (!user) return null;
|
||||
|
||||
const isValid = await bcrypt.compare(password, user.password);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user