Files
vueadmin/src/pages/login/index.vue
2026-01-14 12:14:32 +08:00

400 lines
7.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup>
import { ref } from 'vue'
import { useI18n } from '@/hooks/useI18n'
import LanguageSwitcher from '@/layouts/components/LanguageSwitcher.vue'
const { t } = useI18n()
const loginForm = ref({
username: '',
password: '',
})
const loading = ref(false)
const handleLogin = () => {
loading.value = true
// 模拟登录请求
setTimeout(() => {
console.log('登录信息:', loginForm.value)
loading.value = false
// 这里可以添加实际的登录逻辑
alert(t('login.loginSuccess') + '(模拟)')
}, 1000)
}
</script>
<template>
<div class="login-container">
<div class="language-switcher-wrapper">
<LanguageSwitcher />
</div>
<div class="login-card">
<div class="login-header">
<h2>{{ t('login.title') }}</h2>
<p>{{ t('login.subtitle') }}</p>
</div>
<form @submit.prevent="handleLogin" class="login-form">
<div class="form-group">
<label for="username">{{ t('common.username') }}</label>
<input id="username" v-model="loginForm.username" type="text"
:placeholder="t('login.usernamePlaceholder')" required />
</div>
<div class="form-group">
<label for="password">{{ t('common.password') }}</label>
<input id="password" v-model="loginForm.password" type="password"
:placeholder="t('login.passwordPlaceholder')" required />
</div>
<div class="form-options">
<label class="remember-me">
<input type="checkbox" />
<span>{{ t('common.rememberMe') }}</span>
</label>
<a href="#" class="forgot-password">{{ t('common.forgotPassword') }}</a>
</div>
<button type="submit" class="login-btn" :disabled="loading">
<span v-if="!loading">{{ t('login.loginButton') }}</span>
<span v-else>{{ t('common.loading') }}</span>
</button>
</form>
<div class="login-footer">
<p>{{ t('login.noAccount') }} <a href="#">{{ t('login.registerNow') }}</a></p>
</div>
</div>
</div>
</template>
<style scoped>
.login-container {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #0c1929 0%, #1a237e 50%, #0d47a1 100%);
padding: 20px;
position: relative;
overflow: hidden;
}
.language-switcher-wrapper {
position: absolute;
top: 20px;
right: 20px;
z-index: 10;
}
/* 网格背景 */
.login-container::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image:
linear-gradient(rgba(0, 212, 255, 0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(0, 212, 255, 0.03) 1px, transparent 1px);
background-size: 50px 50px;
animation: gridMove 20s linear infinite;
}
@keyframes gridMove {
0% {
transform: translate(0, 0);
}
100% {
transform: translate(50px, 50px);
}
}
/* 科技光效 */
.login-container::after {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle, rgba(0, 212, 255, 0.1) 0%, transparent 50%);
animation: rotate 30s linear infinite;
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.login-card {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(20px);
border-radius: 20px;
box-shadow:
0 20px 60px rgba(0, 0, 0, 0.3),
0 0 40px rgba(0, 212, 255, 0.1),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.1);
width: 100%;
max-width: 420px;
overflow: hidden;
position: relative;
z-index: 1;
animation: fadeInUp 0.8s ease-out;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.login-header {
text-align: center;
padding: 40px 40px 20px;
position: relative;
}
.login-header::before {
content: '';
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
width: 60px;
height: 4px;
background: linear-gradient(90deg, transparent, #00d4ff, #7c4dff, transparent);
border-radius: 2px;
animation: lineGlow 2s ease-in-out infinite;
}
@keyframes lineGlow {
0%,
100% {
box-shadow: 0 0 10px rgba(0, 212, 255, 0.5);
}
50% {
box-shadow: 0 0 20px rgba(0, 212, 255, 0.8), 0 0 30px rgba(124, 77, 255, 0.5);
}
}
.login-header h2 {
margin: 0 0 10px;
font-size: 28px;
font-weight: 700;
background: linear-gradient(135deg, #00d4ff 0%, #7c4dff 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
text-shadow: 0 0 20px rgba(0, 212, 255, 0.3);
letter-spacing: 1px;
}
.login-header p {
margin: 0;
color: rgba(255, 255, 255, 0.6);
font-size: 14px;
font-weight: 300;
}
.login-form {
padding: 20px 40px 40px;
}
.form-group {
margin-bottom: 20px;
position: relative;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-size: 14px;
font-weight: 500;
color: rgba(255, 255, 255, 0.8);
letter-spacing: 0.5px;
}
.form-group input {
width: 100%;
padding: 14px 20px;
border: 2px solid rgba(0, 212, 255, 0.2);
border-radius: 12px;
font-size: 14px;
transition: all 0.3s ease;
box-sizing: border-box;
background: rgba(255, 255, 255, 0.05);
color: white;
backdrop-filter: blur(10px);
}
.form-group input:focus {
outline: none;
border-color: #00d4ff;
box-shadow: 0 0 20px rgba(0, 212, 255, 0.3), inset 0 0 10px rgba(0, 212, 255, 0.1);
background: rgba(255, 255, 255, 0.1);
}
.form-group input::placeholder {
color: rgba(255, 255, 255, 0.3);
}
.form-group input:focus::placeholder {
color: rgba(255, 255, 255, 0.5);
}
.form-options {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
}
.remember-me {
display: flex;
align-items: center;
gap: 8px;
font-size: 14px;
color: rgba(255, 255, 255, 0.7);
cursor: pointer;
transition: all 0.3s ease;
}
.remember-me:hover {
color: rgba(255, 255, 255, 0.9);
}
.remember-me input[type='checkbox'] {
width: 18px;
height: 18px;
cursor: pointer;
accent-color: #00d4ff;
transition: all 0.3s ease;
}
.remember-me input[type='checkbox']:checked {
box-shadow: 0 0 10px rgba(0, 212, 255, 0.5);
}
.forgot-password {
font-size: 14px;
color: #00d4ff;
text-decoration: none;
transition: all 0.3s ease;
font-weight: 500;
}
.forgot-password:hover {
color: #7c4dff;
text-shadow: 0 0 10px rgba(124, 77, 255, 0.5);
}
.login-btn {
width: 100%;
padding: 15px;
background: linear-gradient(135deg, #00d4ff 0%, #7c4dff 100%);
color: white;
border: none;
border-radius: 12px;
font-size: 16px;
font-weight: 700;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
letter-spacing: 1px;
}
.login-btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
transition: left 0.5s ease;
}
.login-btn:hover:not(:disabled)::before {
left: 100%;
}
.login-btn:hover:not(:disabled) {
transform: translateY(-3px);
box-shadow:
0 10px 30px rgba(0, 212, 255, 0.4),
0 0 20px rgba(124, 77, 255, 0.3);
}
.login-btn:active:not(:disabled) {
transform: translateY(-1px);
box-shadow: 0 5px 15px rgba(0, 212, 255, 0.4);
}
.login-btn:disabled {
opacity: 0.7;
cursor: not-allowed;
}
.login-footer {
text-align: center;
padding: 20px 40px;
background: rgba(0, 0, 0, 0.2);
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.login-footer p {
margin: 0;
font-size: 14px;
color: rgba(255, 255, 255, 0.6);
}
.login-footer a {
color: #00d4ff;
text-decoration: none;
font-weight: 500;
transition: all 0.3s ease;
}
.login-footer a:hover {
color: #7c4dff;
text-shadow: 0 0 10px rgba(124, 77, 255, 0.5);
}
@media (max-width: 480px) {
.login-card {
max-width: 100%;
}
.login-header,
.login-form,
.login-footer {
padding-left: 20px;
padding-right: 20px;
}
.login-header h2 {
font-size: 24px;
}
}
</style>