feat(passport): 优化手机号授权流程及超时处理机制
- 新增手机号授权等待状态及定时器,防止重复触发授权操作 - 增加手机号授权超时弹窗提示,支持切换短信验证码登录 - 修改手机号授权冷却时间由3000ms调整为8000ms,减少频繁操作 - 控制手机号授权按钮状态,确保用户协议同意且无冷却或等待中才能操作 - 清理手机号授权等待定时器,防止内存泄露 - 调整加载状态时按钮UI表现,提高用户交互体验
This commit is contained in:
@@ -105,14 +105,17 @@ async function fetchUserInfo(token: string) {
|
||||
const Login = () => {
|
||||
const [isAgree, setIsAgree] = useState(false)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [phoneAuthPending, setPhoneAuthPending] = useState(false)
|
||||
const [phoneAuthCooling, setPhoneAuthCooling] = useState(isPhoneAuthCoolingDown())
|
||||
const [showContent, setShowContent] = useState(false)
|
||||
const phoneAuthInFlightRef = useRef(false)
|
||||
const phoneAuthPendingRef = useRef(false)
|
||||
const phoneAuthTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||
const phoneAuthPendingTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||
|
||||
const router = Taro.getCurrentInstance().router
|
||||
const isWeapp = IS_WEAPP
|
||||
const canUsePhoneAuth = isAgree && !loading && !phoneAuthCooling
|
||||
const canUsePhoneAuth = isAgree && !loading && !phoneAuthPending && !phoneAuthCooling
|
||||
|
||||
/** 页面加载动画 */
|
||||
useEffect(() => {
|
||||
@@ -125,6 +128,10 @@ const Login = () => {
|
||||
clearTimeout(phoneAuthTimerRef.current)
|
||||
phoneAuthTimerRef.current = null
|
||||
}
|
||||
if (phoneAuthPendingTimerRef.current) {
|
||||
clearTimeout(phoneAuthPendingTimerRef.current)
|
||||
phoneAuthPendingTimerRef.current = null
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
|
||||
@@ -138,6 +145,49 @@ const Login = () => {
|
||||
}, remaining)
|
||||
}
|
||||
|
||||
const clearPhoneAuthPending = () => {
|
||||
phoneAuthPendingRef.current = false
|
||||
setPhoneAuthPending(false)
|
||||
if (phoneAuthPendingTimerRef.current) {
|
||||
clearTimeout(phoneAuthPendingTimerRef.current)
|
||||
phoneAuthPendingTimerRef.current = null
|
||||
}
|
||||
}
|
||||
|
||||
const startPhoneAuthPending = () => {
|
||||
phoneAuthPendingRef.current = true
|
||||
setPhoneAuthPending(true)
|
||||
markPhoneAuthCalled()
|
||||
startPhoneAuthCooldown()
|
||||
if (phoneAuthPendingTimerRef.current) clearTimeout(phoneAuthPendingTimerRef.current)
|
||||
phoneAuthPendingTimerRef.current = setTimeout(() => {
|
||||
clearPhoneAuthPending()
|
||||
Taro.showModal({
|
||||
title: '手机号授权超时',
|
||||
content: '微信手机号授权暂时无响应,请稍后重试或改用短信验证码登录。',
|
||||
confirmText: '短信登录',
|
||||
cancelText: '稍后重试',
|
||||
confirmColor: '#07c160',
|
||||
success: (res) => {
|
||||
if (res.confirm) goSmsLogin()
|
||||
},
|
||||
})
|
||||
}, 12000)
|
||||
}
|
||||
|
||||
const handlePhoneAuthTap = () => {
|
||||
if (!isAgree) {
|
||||
Taro.showToast({ title: '请先勾选同意协议', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (loading || phoneAuthInFlightRef.current || phoneAuthPendingRef.current || isPhoneAuthCoolingDown()) {
|
||||
startPhoneAuthCooldown()
|
||||
Taro.showToast({ title: '请稍后再试', icon: 'none' })
|
||||
return
|
||||
}
|
||||
startPhoneAuthPending()
|
||||
}
|
||||
|
||||
/** 解析 redirect 参数 */
|
||||
const redirectUrl = (() => {
|
||||
const raw = (router?.params as Record<string, string> | undefined)?.redirect
|
||||
@@ -226,18 +276,19 @@ const Login = () => {
|
||||
|
||||
/** 手机号快捷登录 */
|
||||
const handleGetPhoneNumber = async ({ detail }: GetPhoneNumberEvent) => {
|
||||
clearPhoneAuthPending()
|
||||
|
||||
if (!isAgree) {
|
||||
Taro.showToast({ title: '请先勾选同意协议', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (loading || phoneAuthInFlightRef.current || isPhoneAuthCoolingDown()) {
|
||||
if (loading || phoneAuthInFlightRef.current) {
|
||||
startPhoneAuthCooldown()
|
||||
Taro.showToast({ title: '请稍后再试', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
phoneAuthInFlightRef.current = true
|
||||
markPhoneAuthCalled()
|
||||
startPhoneAuthCooldown()
|
||||
|
||||
const { code: phoneCode, encryptedData, iv, errMsg } = detail || {}
|
||||
@@ -312,6 +363,7 @@ const Login = () => {
|
||||
Taro.showToast({ title: e?.message || '登录失败', icon: 'none' })
|
||||
} finally {
|
||||
phoneAuthInFlightRef.current = false
|
||||
clearPhoneAuthPending()
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
@@ -351,14 +403,15 @@ const Login = () => {
|
||||
color: '#ffffff',
|
||||
fontWeight: '600',
|
||||
textAlign: 'center',
|
||||
opacity: (!isAgree || loading) ? 0.5 : 1,
|
||||
opacity: canUsePhoneAuth ? 1 : 0.5,
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
}}
|
||||
openType={canUsePhoneAuth ? 'getPhoneNumber' : undefined}
|
||||
onClick={handlePhoneAuthTap}
|
||||
onGetPhoneNumber={handleGetPhoneNumber}
|
||||
disabled={!canUsePhoneAuth}
|
||||
loading={loading}
|
||||
loading={loading || phoneAuthPending}
|
||||
>
|
||||
手机号快捷登录
|
||||
</Button>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
let lastPhoneAuthTime = 0
|
||||
|
||||
/** 冷却期(ms),在此期间不允许再次触发 getPhoneNumber */
|
||||
const PHONE_AUTH_COOLDOWN = 3000
|
||||
const PHONE_AUTH_COOLDOWN = 8000
|
||||
|
||||
/**
|
||||
* 检查当前是否在冷却期内。
|
||||
|
||||
Reference in New Issue
Block a user