feat(login): add 3-second delay and cancel option for auto-login on desktop

This commit is contained in:
Dawn
2026-01-18 03:37:39 +08:00
parent cd42271274
commit 1f661eaaec
3 changed files with 125 additions and 14 deletions

View File

@@ -5,7 +5,8 @@
"network_error": "Network Error"
},
"qr_code": "QR Code",
"remove_account": "Remove Account"
"cancel_login": "Cancel",
"remove_account": "Remove"
},
"input": {
"account": {

View File

@@ -5,6 +5,7 @@
"network_error": "网络异常"
},
"qr_code": "扫码登录",
"cancel_login": "取消登录",
"remove_account": "移除账号"
},
"input": {

View File

@@ -139,19 +139,37 @@
tertiary
style="color: #fff"
class="gradient-button w-200px mt-12px mb-40px"
@click="normalLogin('PC', true, true)">
@click="triggerAutoLogin">
<span>{{ loginText }}</span>
</n-button>
</n-flex>
</n-flex>
<!-- 第三方登录 -->
<div class="w-full pb-22px pt-3px">
<div v-if="uiState !== 'auto'" class="w-full pb-22px pt-3px">
<ThirdPartyLogin :login-context="loginContext" />
</div>
<!-- 底部操作栏 -->
<div class="text-14px grid grid-cols-[1fr_auto_1fr] items-center gap-x-12px w-full" id="bottomBar">
<div
v-if="uiState === 'auto'"
class="text-14px grid grid-cols-[1fr_auto_1fr] items-center gap-x-12px w-full"
id="bottomBar">
<div
class="color-#13987f cursor-pointer justify-self-end text-right"
:title="cancelLoginTitle"
@click="cancelAutoLoginAndShowManual">
{{ cancelLoginLabel }}
</div>
<div class="w-1px h-14px bg-#ccc dark:bg-#707070 justify-self-center"></div>
<div
class="color-#13987f cursor-pointer justify-self-start text-left"
:title="removeAccountTitle"
@click="removeStoredAccount">
{{ removeAccountLabel }}
</div>
</div>
<div v-else class="text-14px grid grid-cols-[1fr_auto_1fr] items-center gap-x-12px w-full" id="bottomBar">
<div
class="color-#13987f cursor-pointer justify-self-end text-right"
:title="qrCodeTitle"
@@ -159,14 +177,7 @@
{{ qrCodeLabel }}
</div>
<div class="w-1px h-14px bg-#ccc dark:bg-#707070 justify-self-center"></div>
<div
v-if="uiState === 'auto'"
class="color-#13987f cursor-pointer justify-self-start text-left"
:title="removeAccountTitle"
@click="removeToken">
{{ removeAccountLabel }}
</div>
<div v-else class="justify-self-start text-left">
<div class="justify-self-start text-left">
<n-popover
trigger="click"
id="moreShow"
@@ -257,6 +268,57 @@ const loginContext: ThirdPartyLoginContext = {
loading,
loginDisabled
}
const isDesktopClient = isDesktop()
const AUTO_LOGIN_DELAY_MS = 3000
const autoLoginPending = ref(false)
let autoLoginTimer: number | null = null
const clearAutoLoginTimer = () => {
if (autoLoginTimer !== null) {
window.clearTimeout(autoLoginTimer)
autoLoginTimer = null
}
autoLoginPending.value = false
}
const startAutoLoginCountdown = () => {
if (!isDesktopClient) {
normalLogin('PC', true, true)
return
}
clearAutoLoginTimer()
autoLoginPending.value = true
autoLoginTimer = window.setTimeout(() => {
autoLoginPending.value = false
autoLoginTimer = null
normalLogin('PC', true, true)
}, AUTO_LOGIN_DELAY_MS)
}
const cancelAutoLogin = () => {
if (!autoLoginPending.value) {
return
}
clearAutoLoginTimer()
}
const handleAutoLoginActivity = () => {
if (uiState.value !== 'auto' || !autoLoginPending.value) {
return
}
cancelAutoLogin()
}
const triggerAutoLogin = () => {
cancelAutoLogin()
normalLogin('PC', true, true)
}
const cancelAutoLoginAndShowManual = () => {
cancelAutoLogin()
uiState.value = 'manual'
loginHistories.length > 0 && giveAccount(loginHistories[0])
}
const driverSteps = computed<DriverStepConfig[]>(() => [
{
@@ -324,14 +386,19 @@ const MAX_BOTTOM_TEXT_LEN = 6
const qrCodeText = computed(() => t('login.button.qr_code'))
const moreText = computed(() => t('login.option.more'))
const removeAccountText = computed(() => t('login.button.remove_account'))
const cancelLoginText = computed(() => t('login.button.cancel_login'))
const qrCodeLabel = computed(() => formatBottomText(qrCodeText.value, MAX_BOTTOM_TEXT_LEN))
const moreLabel = computed(() => formatBottomText(moreText.value, MAX_BOTTOM_TEXT_LEN))
const removeAccountLabel = computed(() => formatBottomText(removeAccountText.value, MAX_BOTTOM_TEXT_LEN))
const cancelLoginLabel = computed(() => formatBottomText(cancelLoginText.value, MAX_BOTTOM_TEXT_LEN))
const qrCodeTitle = computed(() => (qrCodeLabel.value !== qrCodeText.value ? qrCodeText.value : undefined))
const moreTitle = computed(() => (moreLabel.value !== moreText.value ? moreText.value : undefined))
const removeAccountTitle = computed(() =>
removeAccountLabel.value !== removeAccountText.value ? removeAccountText.value : undefined
)
const cancelLoginTitle = computed(() =>
cancelLoginLabel.value !== cancelLoginText.value ? cancelLoginText.value : undefined
)
/** 是否直接跳转 */
const isJumpDirectly = ref(false)
@@ -353,9 +420,31 @@ timerWorker.onmessage = (e) => {
}
watchEffect(() => {
if (uiState.value === 'auto') {
loginDisabled.value = !isOnline.value || !userStore.userInfo?.account
return
}
loginDisabled.value = !(info.value.account && info.value.password && protocol.value && isOnline.value)
})
watch(
() => uiState.value,
(state) => {
if (state !== 'auto') {
clearAutoLoginTimer()
}
}
)
watch(
() => login.value.autoLogin,
(isAuto) => {
if (!isAuto) {
clearAutoLoginTimer()
}
}
)
watch(isOnline, (v) => {
loginDisabled.value = !v
loginText.value = v ? t('login.button.login.default') : t('login.button.login.network_error')
@@ -446,10 +535,21 @@ const giveAccount = (item: UserInfoType) => {
}
/** 移除已登录账号 */
const removeToken = () => {
const removeStoredAccount = () => {
const storedUserInfo = userStore.userInfo
if (storedUserInfo) {
const matchedHistory = loginHistories.find(
(item) => item.uid === storedUserInfo.uid || item.account === storedUserInfo.account
)
if (matchedHistory) {
loginHistoriesStore.removeLoginHistory(matchedHistory)
}
}
localStorage.removeItem('TOKEN')
localStorage.removeItem('REFRESH_TOKEN')
userStore.userInfo = undefined
settingStore.setAutoLogin(false)
cancelAutoLoginAndShowManual()
}
/** 打开服务协议窗口 */
@@ -514,7 +614,7 @@ onMounted(async () => {
// 自动登录时显示自动登录界面并触发登录
if (login.value.autoLogin) {
uiState.value = 'auto'
normalLogin('PC', true, true)
startAutoLoginCountdown()
} else {
// 手动登录模式,自动填充第一个历史账号
uiState.value = 'manual'
@@ -523,6 +623,10 @@ onMounted(async () => {
window.addEventListener('click', closeMenu, true)
window.addEventListener('keyup', enterKey)
if (isDesktopClient) {
window.addEventListener('pointerdown', handleAutoLoginActivity, true)
window.addEventListener('keydown', handleAutoLoginActivity, true)
}
await checkUpdate('login', true)
timerWorker.postMessage({
type: 'startTimer',
@@ -534,6 +638,11 @@ onMounted(async () => {
onUnmounted(() => {
window.removeEventListener('click', closeMenu, true)
window.removeEventListener('keyup', enterKey)
if (isDesktopClient) {
window.removeEventListener('pointerdown', handleAutoLoginActivity, true)
window.removeEventListener('keydown', handleAutoLoginActivity, true)
}
clearAutoLoginTimer()
// 清除Web Worker计时器
timerWorker.postMessage({
type: 'clearTimer',