feat(login): 全面增强登录组件用户体验

 新增功能:
- 支持回车键登录,在任意输入框按回车即可触发登录
- 登录失败时自动刷新验证码并清空验证码输入框
- 重定向访问时显示优雅的loading状态和身份过期提示
- 智能检测URL重定向参数,提供个性化用户引导

🎨 界面优化:
- 新增专业的loading界面,包含旋转器和动态点阵动画
- 优化过渡动画效果,提供平滑的视觉体验
- 使用项目主题色,确保视觉统一性
- 支持暗色模式适配

🔧 技术改进:
- 增强错误处理机制,防止重复提交
- 优化验证码刷新逻辑,提升用户操作便利性
- 改进loading时序控制,确保用户看到重要提示信息
This commit is contained in:
Leo 2025-07-07 09:26:12 +08:00
parent 92c886346c
commit d415592762

View File

@ -1,5 +1,27 @@
<template>
<div class="space-y-6">
<!-- 重定向Loading状态 -->
<div v-if="isRedirectLoading" class="text-center space-y-6 py-8">
<div class="flex justify-center">
<n-spin size="large" stroke="var(--primary-color)" />
</div>
<div class="space-y-2">
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">
正在检查登录状态...
</h1>
<p class="text-sm text-gray-500 dark:text-gray-400">
请稍候系统正在为您准备登录界面
</p>
</div>
<div class="flex justify-center space-x-1">
<div class="loading-dot" style="animation-delay: 0s;" />
<div class="loading-dot" style="animation-delay: 0.1s;" />
<div class="loading-dot" style="animation-delay: 0.2s;" />
</div>
</div>
<!-- 正常登录状态 -->
<div v-else>
<!-- 头部问候语 -->
<div class="text-center">
<h1 class="text-2xl font-bold text-gray-900 dark:text-white mb-2">
@ -11,7 +33,7 @@
</div>
<!-- 登录表单 -->
<n-form ref="formRef" :rules="rules" :model="formValue" :show-label="false" size="large" class="space-y-4">
<n-form ref="formRef" :rules="rules" :model="formValue" :show-label="false" size="large" class="space-y-4" @keyup.enter="handleLogin">
<!-- 账号输入 -->
<n-form-item path="account">
<n-input
@ -19,6 +41,7 @@
clearable
:placeholder="$t('login.accountPlaceholder')"
class="login-input"
@keyup.enter="handleLogin"
/>
</n-form-item>
@ -31,6 +54,7 @@
clearable
show-password-on="click"
class="login-input"
@keyup.enter="handleLogin"
>
<template #password-invisible-icon>
<icon-park-outline-preview-close-one />
@ -50,6 +74,7 @@
clearable
class="flex-1 login-input"
maxlength="5"
@keyup.enter="handleLogin"
/>
<div
class="w-32 h-12 cursor-pointer rounded-lg border-2 border-gray-200 flex items-center justify-center overflow-hidden bg-white dark:bg-gray-700 dark:border-gray-600 transition-colors duration-200 captcha-button"
@ -99,6 +124,7 @@
<!-- </div> -->
</n-form>
</div>
</div>
</template>
<script setup lang="ts">
@ -106,6 +132,7 @@ import type { FormInst } from 'naive-ui'
import { useAppStore, useAuthStore } from '@/store'
import { fetchCaptchaPng } from '@/service/api/auth'
import { local } from '@/utils'
import { coiMsgWarning } from '@/utils/coi'
const emit = defineEmits(['update:modelValue'])
@ -148,6 +175,7 @@ const formValue = ref({
})
const isRemember = ref(false)
const isLoading = ref(false)
const isRedirectLoading = ref(false)
//
const captchaImage = ref('')
@ -169,6 +197,10 @@ async function getCaptcha() {
const formRef = ref<FormInst | null>(null)
function handleLogin() {
//
if (isLoading.value)
return
formRef.value?.validate(async (errors) => {
if (errors)
return
@ -180,14 +212,38 @@ function handleLogin() {
local.set('loginAccount', { account, pwd })
else local.remove('loginAccount')
try {
await authStore.login(account, pwd, captchaKey.value, securityCode, isRemember.value)
}
catch (error) {
//
await getCaptcha()
formValue.value.securityCode = ''
console.warn('[Login Failed]:', error)
}
finally {
isLoading.value = false
}
})
}
onMounted(() => {
checkUserAccount()
getCaptcha()
// loading
const route = useRoute()
if (route.query.redirect) {
isRedirectLoading.value = true
// loading
setTimeout(() => {
coiMsgWarning('账号身份过期,请你重新登录')
// loading
setTimeout(() => {
isRedirectLoading.value = false
}, 200)
}, 1000)
}
})
function checkUserAccount() {
@ -257,6 +313,40 @@ function checkUserAccount() {
--n-text-color: #f3f4f6;
}
/* 过渡动画 */
.fade-enter-active,
.fade-leave-active {
transition: all 0.3s ease;
}
.fade-enter-from {
opacity: 0;
transform: translateY(10px);
}
.fade-leave-to {
opacity: 0;
transform: translateY(-10px);
}
/* Loading点动画 */
.loading-dot {
width: 8px;
height: 8px;
background: v-bind(primaryColor);
border-radius: 50%;
animation: bounce 1.4s ease-in-out infinite both;
}
@keyframes bounce {
0%, 80%, 100% {
transform: scale(0);
}
40% {
transform: scale(1);
}
}
/* 响应式设计 */
@media (max-width: 640px) {
.login-input {