fix: 获取验证码有问题
This commit is contained in:
parent
8fc4f0c7e6
commit
8f88302624
103
app/auth.tsx
103
app/auth.tsx
|
|
@ -1,13 +1,13 @@
|
|||
import { Ionicons } from '@expo/vector-icons'
|
||||
import { Block, Text, Toast } from '@share/components'
|
||||
import { router } from 'expo-router'
|
||||
import React, { useCallback, useMemo, useState } from 'react'
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { TextInput } from 'react-native'
|
||||
import { KeyboardAwareScrollView } from 'react-native-keyboard-controller'
|
||||
|
||||
import { APP_VERSION } from '@/app.config'
|
||||
import BannerSection from '@/components/BannerSection'
|
||||
import { phoneNumber, setAuthToken } from '@/lib/auth'
|
||||
import { phoneNumber } from '@/lib/auth'
|
||||
import { isValidPhone } from '@/utils'
|
||||
import { openUrl } from '@/utils/webview-helper'
|
||||
|
||||
|
|
@ -19,30 +19,49 @@ export default function Auth() {
|
|||
const [loading, setLoading] = useState(false)
|
||||
const [countdown, setCountdown] = useState(0)
|
||||
const [agreed, setAgreed] = useState(false)
|
||||
const countdownTimerRef = useRef<ReturnType<typeof setInterval> | null>(null)
|
||||
|
||||
const canSendCode = useMemo(() => {
|
||||
return isValidPhone(phone)
|
||||
}, [phone])
|
||||
return isValidPhone(phone) && countdown === 0
|
||||
}, [phone, countdown])
|
||||
|
||||
// TODO: 获取验证码接口还未实现,需要后端提供手机号验证码发送接口
|
||||
// 清理倒计时定时器
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (countdownTimerRef.current) {
|
||||
clearInterval(countdownTimerRef.current)
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
// 获取验证码
|
||||
const handleSendCode = useCallback(async () => {
|
||||
if (!canSendCode) {
|
||||
if (!isValidPhone(phone)) {
|
||||
Toast.show({ title: '请输入有效的手机号' })
|
||||
return
|
||||
}
|
||||
|
||||
Toast.showLoading({ title: '正在发送验证码...' })
|
||||
if (countdown > 0) {
|
||||
return
|
||||
}
|
||||
|
||||
Toast.showLoading({ title: '正在获取验证码...' })
|
||||
setLoading(true)
|
||||
try {
|
||||
// TODO: 调用获取验证码接口
|
||||
// 当前使用 better-auth 的 phoneNumber.sendOtp,但后端可能还未实现
|
||||
// 如果后端未实现,这里会报错,需要后端提供手机号验证码发送接口
|
||||
const result = await phoneNumber.sendOtp({
|
||||
phoneNumber: phone,
|
||||
})
|
||||
|
||||
if (result.error) {
|
||||
Toast.show({ title: result.error.message || '验证码发送失败,请检查后端接口是否已实现' })
|
||||
// 处理不同类型的错误
|
||||
const errorMessage = result.error.message || '验证码发送失败'
|
||||
|
||||
// 如果是 403 错误,可能是请求过于频繁
|
||||
if (result.error.status === 403) {
|
||||
Toast.show({ title: '请求过于频繁,请稍后再试' })
|
||||
} else {
|
||||
Toast.show({ title: errorMessage })
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -50,23 +69,31 @@ export default function Auth() {
|
|||
setCountdown(60) // 开始倒计时
|
||||
|
||||
// 倒计时逻辑
|
||||
const timer = setInterval(() => {
|
||||
if (countdownTimerRef.current) {
|
||||
clearInterval(countdownTimerRef.current)
|
||||
}
|
||||
countdownTimerRef.current = setInterval(() => {
|
||||
setCountdown((prev) => {
|
||||
if (prev <= 1) {
|
||||
clearInterval(timer)
|
||||
if (countdownTimerRef.current) {
|
||||
clearInterval(countdownTimerRef.current)
|
||||
countdownTimerRef.current = null
|
||||
}
|
||||
return 0
|
||||
}
|
||||
return prev - 1
|
||||
})
|
||||
}, 1000)
|
||||
} catch (error: any) {
|
||||
Toast.show({ title: error.message || '验证码发送失败' })
|
||||
console.error('获取验证码失败:', error)
|
||||
Toast.show({ title: error.message || '验证码发送失败,请稍后重试' })
|
||||
} finally {
|
||||
Toast.hideLoading()
|
||||
setLoading(false)
|
||||
}
|
||||
}, [phone, canSendCode])
|
||||
}, [phone, countdown])
|
||||
|
||||
// 验证码登录/注册
|
||||
const handleLogin = useCallback(async () => {
|
||||
if (!phone || !code) {
|
||||
Toast.show({ title: '请填写手机号和验证码' })
|
||||
|
|
@ -78,15 +105,19 @@ export default function Auth() {
|
|||
return
|
||||
}
|
||||
|
||||
if (code.length !== 6) {
|
||||
Toast.show({ title: '请输入6位验证码' })
|
||||
return
|
||||
}
|
||||
|
||||
if (!agreed) {
|
||||
Toast.show({ title: '请先阅读并同意服务条款和隐私协议' })
|
||||
return
|
||||
}
|
||||
|
||||
setLoading(true)
|
||||
Toast.showLoading({ title: '正在验证...' })
|
||||
try {
|
||||
// 使用 better-auth 的 phoneNumber.verify 进行验证和登录
|
||||
// verify 方法会自动创建会话,如果用户不存在会自动注册
|
||||
const result = await phoneNumber.verify({
|
||||
phoneNumber: phone,
|
||||
code,
|
||||
|
|
@ -94,21 +125,35 @@ export default function Auth() {
|
|||
})
|
||||
|
||||
if (result.error) {
|
||||
Toast.show({ title: result.error.message || '验证码错误或已过期' })
|
||||
const errorStatus = result.error.status
|
||||
const errorMessage = result.error.message || '验证失败'
|
||||
|
||||
if (errorStatus === 403) {
|
||||
Toast.show({ title: '验证码尝试次数过多,请重新获取验证码' })
|
||||
setCode('') // 清空验证码
|
||||
setCountdown(0) // 重置倒计时,允许重新发送
|
||||
if (countdownTimerRef.current) {
|
||||
clearInterval(countdownTimerRef.current)
|
||||
countdownTimerRef.current = null
|
||||
}
|
||||
} else if (errorStatus === 401) {
|
||||
Toast.show({ title: '手机号未验证,请先验证手机号' })
|
||||
} else {
|
||||
Toast.show({ title: errorMessage })
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 获取认证 token(如果后端返回)
|
||||
// better-auth 会自动处理 session,但如果有自定义 token,需要手动设置
|
||||
if (result.data && 'token' in result.data && result.data.token) {
|
||||
await setAuthToken(result.data.token)
|
||||
}
|
||||
|
||||
Toast.show({ title: '登录成功!' })
|
||||
router.replace('/(tabs)')
|
||||
|
||||
// 延迟跳转,确保 toast 显示
|
||||
setTimeout(() => {
|
||||
router.replace('/(tabs)')
|
||||
}, 500)
|
||||
} catch (error: any) {
|
||||
Toast.show({ title: error.message || '登录失败' })
|
||||
console.error('登录失败:', error)
|
||||
Toast.show({ title: error.message || '登录失败,请稍后重试' })
|
||||
} finally {
|
||||
Toast.hideLoading()
|
||||
setLoading(false)
|
||||
}
|
||||
}, [phone, code, agreed])
|
||||
|
|
@ -160,7 +205,7 @@ export default function Auth() {
|
|||
className={`border-2 border-black px-[6px] py-[4px] ${canSendCode && countdown === 0 ? 'bg-black' : 'bg-gray-200'}`}
|
||||
>
|
||||
<Text className={`text-[10px] font-[900] ${canSendCode && countdown === 0 ? 'text-accent' : 'text-gray-500'}`}>
|
||||
{countdown > 0 ? `${countdown}秒` : '发送验证码'}
|
||||
{countdown > 0 ? `${countdown}秒` : '获取验证码'}
|
||||
</Text>
|
||||
</Block>
|
||||
</Block>
|
||||
|
|
@ -225,7 +270,7 @@ export default function Auth() {
|
|||
) : (
|
||||
<Ionicons color="black" name="flash" size={20} />
|
||||
)}
|
||||
<Text className="font-900 text-[16px] text-black">{loading ? '处理中...' : '登录'}</Text>
|
||||
<Text className="font-900 text-[16px] text-black">{loading ? '验证中...' : '登录/注册'}</Text>
|
||||
</Block>
|
||||
</Block>
|
||||
</Block>
|
||||
|
|
|
|||
|
|
@ -127,9 +127,5 @@ export const {
|
|||
phoneNumber,
|
||||
} = authClient
|
||||
|
||||
// TODO: 手机号验证码发送接口还未实现
|
||||
// 需要后端提供手机号验证码发送接口,类似于 emailOtp.sendVerificationOtp
|
||||
// 预期接口:phoneOtp.sendVerificationOtp({ phone, type: 'phone-verification' })
|
||||
// 当前在 app/auth.tsx 中的 handleSendCode 函数中使用了临时模拟代码,需要替换为真实 API 调用
|
||||
|
||||
export const subscription: ISubscription = Reflect.get(authClient, 'subscription')
|
||||
|
|
|
|||
Loading…
Reference in New Issue