feat(login): 优化登录表单组件样式和用户体验
- 重新设计表单布局,添加欢迎语和用户选择区域 - 优化输入框样式,采用更现代化的圆角和边框设计 - 实现动态主题色系统,所有交互元素跟随系统主题色 - 改进按钮样式,使用渐变背景和悬停效果 - 优化验证码输入区域的视觉效果 - 完善暗色主题适配和响应式设计
This commit is contained in:
parent
2e69b2e9a0
commit
c292ed9454
@ -1,12 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import type { FormInst } from 'naive-ui'
|
||||
import { useAuthStore } from '@/store'
|
||||
import { useAppStore, useAuthStore } from '@/store'
|
||||
import { fetchCaptchaPng } from '@/service/api/auth'
|
||||
import { local } from '@/utils'
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const authStore = useAuthStore()
|
||||
const appStore = useAppStore()
|
||||
|
||||
// 获取主题色
|
||||
const primaryColor = computed(() => appStore.primaryColor)
|
||||
const primaryColorHover = computed(() => appStore.theme.common.primaryColorHover)
|
||||
const primaryColorPressed = computed(() => appStore.theme.common.primaryColorPressed)
|
||||
|
||||
function toOtherForm(type: any) {
|
||||
emit('update:modelValue', type)
|
||||
@ -92,16 +98,39 @@ function checkUserAccount() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<n-h2 depth="3" class="text-center">
|
||||
{{ $t('login.signInTitle') }}
|
||||
</n-h2>
|
||||
<n-form ref="formRef" :rules="rules" :model="formValue" :show-label="false" size="large">
|
||||
<div class="space-y-6">
|
||||
<!-- 头部问候语 -->
|
||||
<div class="text-center">
|
||||
<h1 class="text-2xl font-bold text-gray-900 dark:text-white mb-2">
|
||||
欢迎回来 👋
|
||||
</h1>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">
|
||||
请输入您的详细信息以开始管理您的帐户
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 登录表单 -->
|
||||
<n-form ref="formRef" :rules="rules" :model="formValue" :show-label="false" size="large" class="space-y-4">
|
||||
<!-- 账号输入 -->
|
||||
<n-form-item path="account">
|
||||
<n-input v-model:value="formValue.account" clearable :placeholder="$t('login.accountPlaceholder')" />
|
||||
<n-input
|
||||
v-model:value="formValue.account"
|
||||
clearable
|
||||
:placeholder="$t('login.accountPlaceholder')"
|
||||
class="login-input"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<!-- 密码输入 -->
|
||||
<n-form-item path="pwd">
|
||||
<n-input v-model:value="formValue.pwd" type="password" :placeholder="$t('login.passwordPlaceholder')" clearable show-password-on="click">
|
||||
<n-input
|
||||
v-model:value="formValue.pwd"
|
||||
type="password"
|
||||
:placeholder="$t('login.passwordPlaceholder')"
|
||||
clearable
|
||||
show-password-on="click"
|
||||
class="login-input"
|
||||
>
|
||||
<template #password-invisible-icon>
|
||||
<icon-park-outline-preview-close-one />
|
||||
</template>
|
||||
@ -110,17 +139,19 @@ function checkUserAccount() {
|
||||
</template>
|
||||
</n-input>
|
||||
</n-form-item>
|
||||
|
||||
<!-- 验证码输入 -->
|
||||
<n-form-item path="securityCode">
|
||||
<div class="flex w-full gap-3">
|
||||
<n-input
|
||||
v-model:value="formValue.securityCode"
|
||||
placeholder="请输入验证码"
|
||||
clearable
|
||||
class="flex-1"
|
||||
class="flex-1 login-input"
|
||||
maxlength="5"
|
||||
/>
|
||||
<div
|
||||
class="w-32 h-12 cursor-pointer rounded border-2 border-gray-300 hover:border-blue-400 flex items-center justify-center overflow-hidden bg-white transition-colors duration-200"
|
||||
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"
|
||||
title="点击刷新验证码"
|
||||
@click="getCaptcha"
|
||||
>
|
||||
@ -130,51 +161,111 @@ function checkUserAccount() {
|
||||
alt="验证码"
|
||||
class="w-full h-full object-contain"
|
||||
>
|
||||
<span v-else class="text-sm text-gray-500">点击获取验证码</span>
|
||||
<span v-else class="text-sm text-gray-500 dark:text-gray-400">点击获取验证码</span>
|
||||
</div>
|
||||
</div>
|
||||
</n-form-item>
|
||||
<n-space vertical :size="20">
|
||||
<div class="flex-y-center justify-between">
|
||||
<n-checkbox v-model:checked="isRemember">
|
||||
{{ $t('login.rememberMe') }}
|
||||
</n-checkbox>
|
||||
<n-button type="primary" text @click="toOtherForm('resetPwd')">
|
||||
{{ $t('login.forgotPassword') }}
|
||||
</n-button>
|
||||
</div>
|
||||
<n-button block type="primary" size="large" :loading="isLoading" :disabled="isLoading" @click="handleLogin">
|
||||
{{ $t('login.signIn') }}
|
||||
|
||||
<!-- 记住密码和忘记密码 -->
|
||||
<div class="flex items-center justify-between">
|
||||
<n-checkbox v-model:checked="isRemember" class="text-sm">
|
||||
{{ $t('login.rememberMe') }}
|
||||
</n-checkbox>
|
||||
<n-button type="primary" text class="text-sm" @click="toOtherForm('resetPwd')">
|
||||
{{ $t('login.forgotPassword') }}
|
||||
</n-button>
|
||||
<n-flex>
|
||||
<n-text>{{ $t('login.noAccountText') }}</n-text>
|
||||
<n-button type="primary" text @click="toOtherForm('register')">
|
||||
{{ $t('login.signUp') }}
|
||||
</n-button>
|
||||
</n-flex>
|
||||
</n-space>
|
||||
</div>
|
||||
|
||||
<!-- 登录按钮 -->
|
||||
<n-button
|
||||
block
|
||||
type="primary"
|
||||
size="large"
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
class="login-button"
|
||||
@click="handleLogin"
|
||||
>
|
||||
{{ $t('login.signIn') }}
|
||||
</n-button>
|
||||
|
||||
<!-- 注册链接 -->
|
||||
<!-- <div class="text-center"> -->
|
||||
<!-- <span class="text-sm text-gray-600 dark:text-gray-400">{{ $t('login.noAccountText') }}</span> -->
|
||||
<!-- <n-button type="primary" text @click="toOtherForm('register')" class="text-sm ml-1"> -->
|
||||
<!-- {{ $t('login.signUp') }} -->
|
||||
<!-- </n-button> -->
|
||||
<!-- </div> -->
|
||||
</n-form>
|
||||
<n-divider>
|
||||
<span op-80>{{ $t('login.or') }}</span>
|
||||
</n-divider>
|
||||
<n-space justify="center">
|
||||
<n-button circle>
|
||||
<template #icon>
|
||||
<n-icon><icon-park-outline-wechat /></n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
<n-button circle>
|
||||
<template #icon>
|
||||
<n-icon><icon-park-outline-tencent-qq /></n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
<n-button circle>
|
||||
<template #icon>
|
||||
<n-icon><icon-park-outline-github-one /></n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped>
|
||||
.login-input {
|
||||
--n-border-radius: 8px;
|
||||
--n-border: 1px solid #e5e7eb;
|
||||
--n-border-hover: 1px solid v-bind(primaryColor);
|
||||
--n-border-focus: 1px solid v-bind(primaryColor);
|
||||
--n-box-shadow-focus: 0 0 0 3px v-bind(`${primaryColor}19`);
|
||||
--n-padding-left: 16px;
|
||||
--n-padding-right: 16px;
|
||||
--n-font-size: 14px;
|
||||
--n-height: 48px;
|
||||
}
|
||||
|
||||
.login-button {
|
||||
--n-border-radius: 8px;
|
||||
--n-height: 48px;
|
||||
--n-font-size: 16px;
|
||||
--n-font-weight: 600;
|
||||
background: linear-gradient(135deg, v-bind(primaryColor) 0%, v-bind(primaryColorPressed) 100%);
|
||||
border: none;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.login-button:hover {
|
||||
background: linear-gradient(135deg, v-bind(primaryColorHover) 0%, v-bind(primaryColorPressed) 100%);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px v-bind(`${primaryColor}4D`);
|
||||
}
|
||||
|
||||
.social-login-btn {
|
||||
@apply w-12 h-12 rounded-full border-2 border-gray-200 dark:border-gray-600 flex items-center justify-center transition-all duration-200 text-gray-600 dark:text-gray-400;
|
||||
|
||||
&:hover {
|
||||
border-color: v-bind(primaryColor);
|
||||
background: v-bind(`${primaryColor}0D`);
|
||||
color: v-bind(primaryColor);
|
||||
}
|
||||
}
|
||||
|
||||
.social-login-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.captcha-button:hover {
|
||||
border-color: v-bind(primaryColor);
|
||||
}
|
||||
|
||||
/* 暗色主题适配 */
|
||||
.dark .login-input {
|
||||
--n-color: #374151;
|
||||
--n-border: 1px solid #4b5563;
|
||||
--n-border-hover: 1px solid v-bind(primaryColor);
|
||||
--n-color-focus: #374151;
|
||||
--n-text-color: #f3f4f6;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 640px) {
|
||||
.login-input {
|
||||
--n-height: 44px;
|
||||
}
|
||||
|
||||
.login-button {
|
||||
--n-height: 44px;
|
||||
--n-font-size: 14px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user