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