From d415592762d85c97ff1a65c40c41a659ce57b511 Mon Sep 17 00:00:00 2001 From: Leo <98382335+gaoziman@users.noreply.github.com> Date: Mon, 7 Jul 2025 09:26:12 +0800 Subject: [PATCH] =?UTF-8?q?feat(login):=20=E5=85=A8=E9=9D=A2=E5=A2=9E?= =?UTF-8?q?=E5=BC=BA=E7=99=BB=E5=BD=95=E7=BB=84=E4=BB=B6=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E4=BD=93=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✨ 新增功能: - 支持回车键登录,在任意输入框按回车即可触发登录 - 登录失败时自动刷新验证码并清空验证码输入框 - 重定向访问时显示优雅的loading状态和身份过期提示 - 智能检测URL重定向参数,提供个性化用户引导 🎨 界面优化: - 新增专业的loading界面,包含旋转器和动态点阵动画 - 优化过渡动画效果,提供平滑的视觉体验 - 使用项目主题色,确保视觉统一性 - 支持暗色模式适配 🔧 技术改进: - 增强错误处理机制,防止重复提交 - 优化验证码刷新逻辑,提升用户操作便利性 - 改进loading时序控制,确保用户看到重要提示信息 --- src/views/login/components/Login/index.vue | 266 ++++++++++++++------- 1 file changed, 178 insertions(+), 88 deletions(-) diff --git a/src/views/login/components/Login/index.vue b/src/views/login/components/Login/index.vue index 678ea02..82b4266 100644 --- a/src/views/login/components/Login/index.vue +++ b/src/views/login/components/Login/index.vue @@ -1,94 +1,119 @@ @@ -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(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') - await authStore.login(account, pwd, captchaKey.value, securityCode, isRemember.value) - isLoading.value = false + 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 {