页面优化
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { UserOutlined, LockOutlined } from '@ant-design/icons-vue'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import AOS from 'aos'
|
||||
import 'aos/dist/aos.css'
|
||||
|
||||
const visible = ref(false)
|
||||
const loading = ref(false)
|
||||
@@ -11,86 +12,255 @@ const formState = ref({
|
||||
remember: true
|
||||
})
|
||||
|
||||
const show = () => visible.value = true
|
||||
const userStore = useUserStore() // Initialize the store outside the handleSubmit function
|
||||
|
||||
onMounted(() => {
|
||||
AOS.init({
|
||||
duration: 800,
|
||||
offset: 100,
|
||||
easing: 'ease-out-cubic',
|
||||
once: false
|
||||
})
|
||||
})
|
||||
|
||||
const show = () => {
|
||||
visible.value = true
|
||||
// 在下一个渲染周期触发AOS动画
|
||||
setTimeout(() => {
|
||||
document.querySelectorAll('[data-aos]').forEach(el => {
|
||||
el.classList.add('aos-animate')
|
||||
})
|
||||
}, 10)
|
||||
}
|
||||
|
||||
const close = () => visible.value = false
|
||||
|
||||
const handleSubmit = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
await useUserStore().login(formState.value)
|
||||
await userStore.login(formState.value)
|
||||
close()
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
defineExpose({
|
||||
show,
|
||||
close
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a-modal
|
||||
:visible="visible"
|
||||
title="欢迎登录"
|
||||
:footer="null"
|
||||
:width="400"
|
||||
:maskClosable="false"
|
||||
@cancel="close"
|
||||
:wrapClassName="'auth-modal'"
|
||||
<!-- 模态框背景遮罩 -->
|
||||
<div
|
||||
v-if="visible"
|
||||
class="fixed inset-0 z-50 overflow-y-auto"
|
||||
aria-labelledby="modal-title"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<a-form
|
||||
layout="vertical"
|
||||
:model="formState"
|
||||
@finish="handleSubmit"
|
||||
class="px-8 pb-6"
|
||||
>
|
||||
<a-form-item name="username">
|
||||
<a-input
|
||||
v-model:value="formState.username"
|
||||
placeholder="用户名"
|
||||
size="large"
|
||||
autocomplete="username"
|
||||
class="rounded-lg hover:border-primary focus:border-primary"
|
||||
>
|
||||
<template #prefix><UserOutlined class="text-gray-400" /></template>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<div class="flex items-center justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
|
||||
<!-- 毛玻璃背景遮罩 (80% 模糊) -->
|
||||
<div
|
||||
class="fixed inset-0 transition-opacity backdrop-blur-xl bg-gray-500/80 dark:bg-gray-900/80"
|
||||
aria-hidden="true"
|
||||
@click="close"
|
||||
></div>
|
||||
|
||||
<a-form-item name="password">
|
||||
<a-input-password
|
||||
v-model:value="formState.password"
|
||||
placeholder="密码"
|
||||
size="large"
|
||||
autocomplete="current-password"
|
||||
class="rounded-lg hover:border-primary"
|
||||
>
|
||||
<template #prefix><LockOutlined class="text-gray-400" /></template>
|
||||
</a-input-password>
|
||||
</a-form-item>
|
||||
<!-- 使模态框居中 -->
|
||||
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">​</span>
|
||||
|
||||
<a-form-item>
|
||||
<a-button
|
||||
type="primary"
|
||||
html-type="submit"
|
||||
:loading="loading"
|
||||
block
|
||||
size="large"
|
||||
class="rounded-lg transition-all hover:shadow-md"
|
||||
>
|
||||
立即登录
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
<!-- 模态框内容 -->
|
||||
<div
|
||||
data-aos="zoom-in"
|
||||
data-aos-duration="600"
|
||||
class="inline-block align-bottom bg-white/90 dark:bg-gray-800/90 backdrop-blur-md rounded-2xl text-left overflow-hidden shadow-2xl transform transition-all sm:my-8 sm:align-middle sm:max-w-md sm:w-full"
|
||||
>
|
||||
<div class="absolute top-0 right-0 pt-4 pr-4">
|
||||
<button
|
||||
type="button"
|
||||
class="bg-transparent rounded-md text-gray-400 dark:text-gray-500 hover:text-gray-500 dark:hover:text-gray-400 focus:outline-none cursor-pointer"
|
||||
@click="close"
|
||||
>
|
||||
<span class="sr-only">关闭</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="px-8 pt-12 pb-8">
|
||||
<div class="text-center mb-8" data-aos="fade-down" data-aos-delay="100">
|
||||
<h3 class="text-2xl font-bold text-gray-900 dark:text-white" id="modal-title">
|
||||
欢迎登录
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<form @submit.prevent="handleSubmit" class="space-y-6">
|
||||
<!-- 用户名 -->
|
||||
<div data-aos="fade-up" data-aos-delay="200">
|
||||
<label for="username" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
用户名
|
||||
</label>
|
||||
<div class="relative rounded-lg shadow-sm">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
|
||||
</svg>
|
||||
</div>
|
||||
<input
|
||||
id="username"
|
||||
v-model="formState.username"
|
||||
type="text"
|
||||
name="username"
|
||||
autocomplete="username"
|
||||
required
|
||||
class="block w-full pl-10 pr-3 py-3 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-rose-500 focus:border-rose-500 bg-white/50 dark:bg-gray-700/50 backdrop-blur-sm text-gray-900 dark:text-white text-sm"
|
||||
placeholder="请输入用户名"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 密码 -->
|
||||
<div data-aos="fade-up" data-aos-delay="300">
|
||||
<label for="password" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
密码
|
||||
</label>
|
||||
<div class="relative rounded-lg shadow-sm">
|
||||
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" />
|
||||
</svg>
|
||||
</div>
|
||||
<input
|
||||
id="password"
|
||||
v-model="formState.password"
|
||||
type="password"
|
||||
name="password"
|
||||
autocomplete="current-password"
|
||||
required
|
||||
class="block w-full pl-10 pr-3 py-3 border border-gray-300 dark:border-gray-600 rounded-lg focus:outline-none focus:ring-rose-500 focus:border-rose-500 bg-white/50 dark:bg-gray-700/50 backdrop-blur-sm text-gray-900 dark:text-white text-sm"
|
||||
placeholder="请输入密码"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 记住我 -->
|
||||
<div class="flex items-center justify-between" data-aos="fade-up" data-aos-delay="400">
|
||||
<div class="flex items-center">
|
||||
<input
|
||||
id="remember-me"
|
||||
v-model="formState.remember"
|
||||
name="remember-me"
|
||||
type="checkbox"
|
||||
class="h-4 w-4 text-rose-600 focus:ring-rose-500 border-gray-300 dark:border-gray-600 rounded cursor-pointer"
|
||||
/>
|
||||
<label for="remember-me" class="ml-2 block text-sm text-gray-700 dark:text-gray-300 cursor-pointer">
|
||||
记住我
|
||||
</label>
|
||||
</div>
|
||||
<div class="text-sm">
|
||||
<a href="#" class="font-medium text-rose-600 hover:text-rose-500 dark:text-rose-400 dark:hover:text-rose-300 cursor-pointer">
|
||||
忘记密码?
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 登录按钮 -->
|
||||
<div data-aos="fade-up" data-aos-delay="500">
|
||||
<button
|
||||
type="submit"
|
||||
class="w-full flex justify-center py-3 px-4 border border-transparent rounded-lg shadow-sm text-sm font-medium text-white bg-rose-600 hover:bg-rose-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-rose-500 cursor-pointer transition-all duration-300 hover:shadow-lg"
|
||||
:disabled="loading"
|
||||
>
|
||||
<svg v-if="loading" class="animate-spin -ml-1 mr-2 h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
{{ loading ? '登录中...' : '立即登录' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 分割线和其他登录方式 -->
|
||||
<div class="mt-6" data-aos="fade-up" data-aos-delay="600">
|
||||
<div class="relative">
|
||||
<div class="absolute inset-0 flex items-center">
|
||||
<div class="w-full border-t border-gray-300 dark:border-gray-600"></div>
|
||||
</div>
|
||||
<div class="relative flex justify-center text-sm">
|
||||
<span class="px-2 bg-white/90 dark:bg-gray-800/90 text-gray-500 dark:text-gray-400">
|
||||
其他登录方式
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 grid grid-cols-3 gap-3">
|
||||
<div>
|
||||
<a href="#" class="w-full inline-flex justify-center py-2 px-4 border border-gray-300 dark:border-gray-600 rounded-lg shadow-sm bg-white/70 dark:bg-gray-700/70 backdrop-blur-sm text-sm font-medium text-gray-500 dark:text-gray-300 hover:bg-white dark:hover:bg-gray-600 cursor-pointer transition-all duration-300">
|
||||
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path fill-rule="evenodd" d="M22 12c0-5.523-4.477-10-10-10S2 6.477 2 12c0 4.991 3.657 9.128 8.438 9.878v-6.987h-2.54V12h2.54V9.797c0-2.506 1.492-3.89 3.777-3.89 1.094 0 2.238.195 2.238.195v2.46h-1.26c-1.243 0-1.63.771-1.63 1.562V12h2.773l-.443 2.89h-2.33v6.988C18.343 21.128 22 16.991 22 12z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a href="#" class="w-full inline-flex justify-center py-2 px-4 border border-gray-300 dark:border-gray-600 rounded-lg shadow-sm bg-white/70 dark:bg-gray-700/70 backdrop-blur-sm text-sm font-medium text-gray-500 dark:text-gray-300 hover:bg-white dark:hover:bg-gray-600 cursor-pointer transition-all duration-300">
|
||||
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M8.29 20.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0022 5.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.072 4.072 0 012.8 9.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 012 18.407a11.616 11.616 0 006.29 1.84" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a href="#" class="w-full inline-flex justify-center py-2 px-4 border border-gray-300 dark:border-gray-600 rounded-lg shadow-sm bg-white/70 dark:bg-gray-700/70 backdrop-blur-sm text-sm font-medium text-gray-500 dark:text-gray-300 hover:bg-white dark:hover:bg-gray-600 cursor-pointer transition-all duration-300">
|
||||
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 注册链接 -->
|
||||
<div class="text-sm text-center mt-6" data-aos="fade-up" data-aos-delay="700">
|
||||
<span class="text-gray-600 dark:text-gray-400">还没有账号? </span>
|
||||
<a href="#" class="font-medium text-rose-600 hover:text-rose-500 dark:text-rose-400 dark:hover:text-rose-300 cursor-pointer">
|
||||
立即注册
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:deep(.ant-modal-body) {
|
||||
padding: 40px;
|
||||
/* 自定义样式 */
|
||||
button, a, [role="button"], .cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
:deep(.ant-input-affix-wrapper) {
|
||||
padding: 12px 16px;
|
||||
|
||||
/* 毛玻璃效果增强 */
|
||||
.backdrop-blur-xl {
|
||||
backdrop-filter: blur(16px);
|
||||
}
|
||||
</style>
|
||||
|
||||
.backdrop-blur-md {
|
||||
backdrop-filter: blur(12px);
|
||||
}
|
||||
|
||||
.backdrop-blur-sm {
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
/* 确保动画平滑 */
|
||||
* {
|
||||
transition-property: background-color, border-color, color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user