feat: 优化登录页面和认证布局设计

- 重构认证页面布局,优化视觉效果和用户体验
- 更新登录页面UI组件和交互逻辑
- 新增原始认证布局备份文件
- 导出登录插图组件供使用
This commit is contained in:
lzh
2025-12-19 13:51:00 +08:00
parent fc7b405805
commit 8d1c469804
4 changed files with 279 additions and 16 deletions

View File

@@ -0,0 +1,26 @@
<script lang="ts" setup>
import { computed } from 'vue';
import { AuthPageLayout } from '@vben/layouts';
import { preferences } from '@vben/preferences';
import { $t } from '#/locales';
const appName = computed(() => preferences.app.name);
const logo = computed(() => preferences.logo.source);
const logoDark = computed(() => preferences.logo.sourceDark);
</script>
<template>
<AuthPageLayout
:app-name="appName"
:logo="logo"
:logo-dark="logoDark"
:page-description="$t('authentication.pageDesc')"
:page-title="$t('authentication.pageTitle')"
>
<!-- 自定义工具栏 -->
<!-- <template #toolbar></template> -->
</AuthPageLayout>
</template>

View File

@@ -1,25 +1,174 @@
<script lang="ts" setup>
import { computed } from 'vue';
import { AuthPageLayout } from '@vben/layouts';
import { preferences } from '@vben/preferences';
import { $t } from '#/locales';
import {
LanguageToggle,
LoginIllustration,
ThemeToggle,
} from '@vben/layouts';
import { preferences, usePreferences } from '@vben/preferences';
const appName = computed(() => preferences.app.name);
const logo = computed(() => preferences.logo.source);
const logoDark = computed(() => preferences.logo.sourceDark);
const { isDark } = usePreferences();
</script>
<template>
<AuthPageLayout
:app-name="appName"
:logo="logo"
:logo-dark="logoDark"
:page-description="$t('authentication.pageDesc')"
:page-title="$t('authentication.pageTitle')"
<div
:class="[isDark ? 'dark' : '']"
class="relative flex h-screen w-full overflow-hidden font-sans"
>
<!-- 自定义工具栏 -->
<!-- <template #toolbar></template> -->
</AuthPageLayout>
<!-- 橙色渐变背景 + SVG 贴图预留 -->
<div class="absolute inset-0 z-0 size-full">
<!-- 橙色渐变背景 - 从左到右依次变淡 -->
<div
class="absolute inset-0 size-full bg-gradient-to-r from-[rgb(218,125,68)] via-[#FFA00A]/30 to-[#FFA00A]/8 dark:from-[rgb(218,125,68)] dark:via-[#FFA00A]/40 dark:to-[#FFA00A]/12"
>
<!-- 浮动插图 - 左侧区域 -->
<div
class="absolute -left-[5%] top-1/2 hidden h-[48rem] w-[65%] -translate-y-1/2 lg:block"
>
<LoginIllustration :alt="appName" />
</div>
</div>
</div>
<!-- 左上角品牌标识 -->
<div
class="absolute left-4 top-4 z-20 flex items-center gap-3 lg:left-6 lg:top-6"
@click.prevent
>
<div class="flex size-12 items-center justify-center lg:size-14">
<img v-if="logo" :src="logo" :alt="appName" class="size-8 lg:size-10" />
<span v-else class="text-xl text-[#FFA00A] lg:text-2xl">💡</span>
</div>
<span
class="relative top-[1px] text-xl font-semibold tracking-tight text-white drop-shadow-[0_2px_4px_rgba(0,0,0,0.3)] lg:top-[2px] lg:text-2xl"
>
{{ appName }}
</span>
</div>
<!-- 右上角 Toolbar -->
<div
class="bg-accent absolute right-2 top-4 z-20 flex items-center gap-1 rounded-3xl px-3 py-1 lg:right-6 lg:top-6"
>
<LanguageToggle v-if="preferences.widget.languageToggle" />
<ThemeToggle v-if="preferences.widget.themeToggle" />
</div>
<!-- 内容区域 -->
<div
class="relative z-10 flex w-full flex-1 items-center justify-center px-6 py-5 lg:justify-end lg:px-12"
>
<!-- 登录卡片 - 响应式居中/靠右 -->
<div class="w-full md:w-[480px] lg:mr-[10%]">
<div
class="bg-background relative overflow-hidden rounded-[2.5rem] p-8 shadow-[0_30px_60px_-15px_rgba(255,160,10,0.2)] dark:shadow-[0_30px_60px_-15px_rgba(255,160,10,0.3)]"
>
<!-- 登录表单 - RouterView 渲染实际的登录组件 -->
<div class="login-form-container">
<RouterView v-slot="{ Component, route }">
<Transition appear mode="out-in" name="fade">
<KeepAlive :include="['Login']">
<component :is="Component" :key="route.fullPath" />
</KeepAlive>
</Transition>
</RouterView>
</div>
<!-- 遇到问题 -->
<div class="mt-6 text-center">
<span class="text-muted-foreground text-xs">
{{ $t('authentication.contactSupport') }}
<a
href="#"
class="ml-1 font-bold text-[#FFA00A] hover:underline"
@click.prevent
>
{{ $t('authentication.support') }}
</a>
</span>
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
/* 登录表单容器样式覆盖 */
:deep(.login-form-container) {
/* 标题靠左对齐 */
.mb-7,
.mb-7 h2,
.mb-7 p {
text-align: left !important;
}
/* 输入框样式 */
.vben-input,
.vben-input-password input {
@apply rounded-2xl border-slate-100 bg-slate-50 px-6 py-4 text-sm transition-all;
@apply focus:border-[#FFA00A]/30 focus:bg-white focus:ring-4 focus:ring-[#FFA00A]/10;
}
/* 深色模式输入框 */
.dark .vben-input,
.dark .vben-input-password input {
@apply border-slate-700 bg-slate-800;
@apply focus:border-[#FFA00A]/50 focus:bg-slate-900 focus:ring-[#FFA00A]/20;
}
/* 选择框样式 */
.vben-select .vben-input {
@apply rounded-2xl border-slate-100 bg-slate-50 px-6 py-4 text-sm;
}
.dark .vben-select .vben-input {
@apply border-slate-700 bg-slate-800;
}
/* 登录按钮样式 */
.vben-button[aria-label='login'] {
@apply w-full rounded-2xl bg-[#FFA00A] py-4 text-base font-bold tracking-wide text-white shadow-lg shadow-[#FFA00A]/30;
@apply transition-all hover:-translate-y-1 hover:bg-[#ff8c00] active:translate-y-0;
}
.dark .vben-button[aria-label='login'] {
@apply shadow-[#FFA00A]/40;
}
/* 记住我和忘记密码 */
.vben-checkbox label {
@apply text-xs text-slate-400 dark:text-slate-500;
}
.vben-link {
@apply text-xs text-slate-400 transition-colors hover:text-slate-600 dark:text-slate-500 dark:hover:text-slate-400;
}
}
/* 过渡动画 - 快速响应 */
.fade-enter-active {
transition:
opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1),
transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.fade-leave-active {
transition:
opacity 0.15s cubic-bezier(0.4, 0, 1, 1),
transform 0.15s cubic-bezier(0.4, 0, 1, 1);
}
.fade-enter-from {
opacity: 0;
transform: translateY(8px);
}
.fade-leave-to {
opacity: 0;
transform: translateY(-8px);
}
</style>