You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1284 lines
31 KiB
Vue
1284 lines
31 KiB
Vue
<!-- views/LoginView.vue -->
|
|
<template>
|
|
<div class="login-page">
|
|
<!-- Encabezado con logo UNA -->
|
|
<header class="login-header">
|
|
<div class="header-container">
|
|
<div class="una-logo">
|
|
<div class="logo-wrapper">
|
|
<img src="/logotiny.png" alt="Logo UNA" class="logo-img" />
|
|
</div>
|
|
<div class="una-titles">
|
|
<h1 class="una-main-title">Universidad Nacional del Altiplano</h1>
|
|
<h2 class="una-subtitle">Portal del Postulante</h2>
|
|
</div>
|
|
</div>
|
|
<div class="header-contact">
|
|
<div class="contact-item">
|
|
<span class="contact-label">Admisión:</span>
|
|
<span class="contact-value">(051) 123-4567</span>
|
|
</div>
|
|
<div class="contact-item">
|
|
<span class="contact-label">Email:</span>
|
|
<span class="contact-value">admision@una.edu.pe</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Contenido principal -->
|
|
<main class="login-main">
|
|
<div class="login-container">
|
|
<!-- Card de Login/Registro -->
|
|
<div class="auth-card">
|
|
<!-- Logo más pequeño dentro del card -->
|
|
<div class="card-logo">
|
|
<div class="logo-icon-small">
|
|
<img src="/logotiny.png" alt="Logo UNA" />
|
|
</div>
|
|
<div class="card-logo-text">
|
|
<h2>Acceso al Sistema</h2>
|
|
<span>Ingresa o crea tu cuenta para continuar</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tabs para Login/Registro -->
|
|
<a-tabs v-model:activeKey="activeTab" centered class="auth-tabs">
|
|
<a-tab-pane key="login" tab="Iniciar Sesión">
|
|
<div class="form-section">
|
|
<div class="form-header">
|
|
<h3>Acceder a mi cuenta</h3>
|
|
<p>Ingresa tus credenciales para continuar</p>
|
|
</div>
|
|
|
|
<a-form
|
|
:model="loginForm"
|
|
:rules="loginRules"
|
|
layout="vertical"
|
|
@finish="handleLogin"
|
|
class="auth-form"
|
|
ref="loginFormRef"
|
|
>
|
|
<a-form-item label="Correo Electrónico" name="email">
|
|
<a-input
|
|
v-model:value="loginForm.email"
|
|
placeholder="ejemplo@correo.com"
|
|
size="large"
|
|
:disabled="authStore.loading"
|
|
autocomplete="username"
|
|
>
|
|
<template #prefix>
|
|
<MailOutlined />
|
|
</template>
|
|
</a-input>
|
|
</a-form-item>
|
|
|
|
<a-form-item label="Contraseña" name="password">
|
|
<a-input-password
|
|
v-model:value="loginForm.password"
|
|
placeholder="Tu contraseña"
|
|
size="large"
|
|
:disabled="authStore.loading"
|
|
autocomplete="current-password"
|
|
>
|
|
<template #prefix>
|
|
<LockOutlined />
|
|
</template>
|
|
</a-input-password>
|
|
</a-form-item>
|
|
|
|
<!-- Opciones adicionales login -->
|
|
<div class="form-options">
|
|
<a-checkbox v-model:checked="rememberMe">
|
|
Recordar sesión
|
|
</a-checkbox>
|
|
<a-button type="link" @click="showForgotPassword">
|
|
¿Olvidaste tu contraseña?
|
|
</a-button>
|
|
</div>
|
|
|
|
<!-- Mensaje de error -->
|
|
<div v-if="authStore.error && activeTab === 'login'" class="error-message">
|
|
<AlertOutlined />
|
|
<span>{{ authStore.error }}</span>
|
|
</div>
|
|
|
|
<!-- Botón de submit -->
|
|
<a-form-item>
|
|
<a-button
|
|
type="primary"
|
|
html-type="submit"
|
|
size="large"
|
|
:loading="authStore.loading && activeTab === 'login'"
|
|
block
|
|
class="submit-btn"
|
|
>
|
|
<template v-if="!authStore.loading || activeTab !== 'login'">
|
|
<LoginOutlined />
|
|
Iniciar Sesión
|
|
</template>
|
|
<span v-else>Verificando...</span>
|
|
</a-button>
|
|
</a-form-item>
|
|
|
|
<!-- Enlace para registrarse -->
|
|
<div class="switch-auth">
|
|
<span>¿No tienes una cuenta? </span>
|
|
<a-button type="link" @click="activeTab = 'register'">
|
|
Regístrate aquí
|
|
</a-button>
|
|
</div>
|
|
</a-form>
|
|
</div>
|
|
</a-tab-pane>
|
|
|
|
<a-tab-pane key="register" tab="Registrarse">
|
|
<div class="form-section">
|
|
<div class="form-header">
|
|
<h3>Crear nueva cuenta</h3>
|
|
<p>Completa el formulario para registrarte</p>
|
|
</div>
|
|
|
|
<a-form
|
|
:model="registerForm"
|
|
:rules="registerRules"
|
|
layout="vertical"
|
|
@finish="handleRegister"
|
|
class="auth-form"
|
|
ref="registerFormRef"
|
|
>
|
|
<a-row :gutter="16">
|
|
<a-col :xs="24" :sm="24" :md="12">
|
|
<a-form-item label="Nombres" name="name">
|
|
<a-input
|
|
v-model:value="registerForm.name"
|
|
placeholder="Tus nombres completos"
|
|
size="large"
|
|
:disabled="authStore.loading"
|
|
autocomplete="username"
|
|
>
|
|
<template #prefix>
|
|
<UserOutlined />
|
|
</template>
|
|
</a-input>
|
|
</a-form-item>
|
|
</a-col>
|
|
<a-col :xs="24" :sm="24" :md="12">
|
|
<a-form-item label="DNI" name="dni">
|
|
<a-input
|
|
v-model:value="registerForm.dni"
|
|
placeholder="87654321"
|
|
size="large"
|
|
:maxlength="8"
|
|
:disabled="authStore.loading"
|
|
>
|
|
<template #prefix>
|
|
<IdcardOutlined />
|
|
</template>
|
|
</a-input>
|
|
</a-form-item>
|
|
</a-col>
|
|
</a-row>
|
|
|
|
<a-form-item label="Correo Electrónico" name="email">
|
|
<a-input
|
|
v-model:value="registerForm.email"
|
|
placeholder="ejemplo@correo.com"
|
|
size="large"
|
|
:disabled="authStore.loading"
|
|
autocomplete="email"
|
|
>
|
|
<template #prefix>
|
|
<MailOutlined />
|
|
</template>
|
|
</a-input>
|
|
</a-form-item>
|
|
|
|
<a-row :gutter="16">
|
|
<a-col :xs="24" :sm="24" :md="12">
|
|
<a-form-item label="Contraseña" name="password">
|
|
<a-input-password
|
|
v-model:value="registerForm.password"
|
|
placeholder="Mínimo 6 caracteres"
|
|
size="large"
|
|
:disabled="authStore.loading"
|
|
autocomplete="new-password"
|
|
>
|
|
<template #prefix>
|
|
<LockOutlined />
|
|
</template>
|
|
</a-input-password>
|
|
</a-form-item>
|
|
</a-col>
|
|
<a-col :xs="24" :sm="24" :md="12">
|
|
<a-form-item label="Confirmar Contraseña" name="password_confirmation">
|
|
<a-input-password
|
|
v-model:value="registerForm.password_confirmation"
|
|
placeholder="Repite tu contraseña"
|
|
size="large"
|
|
:disabled="authStore.loading"
|
|
autocomplete="new-password"
|
|
>
|
|
<template #prefix>
|
|
<SafetyOutlined />
|
|
</template>
|
|
</a-input-password>
|
|
</a-form-item>
|
|
</a-col>
|
|
</a-row>
|
|
|
|
<!-- Términos y condiciones -->
|
|
<a-form-item name="terms">
|
|
<a-checkbox v-model:checked="registerForm.terms">
|
|
Acepto los
|
|
<a href="#" @click.prevent="showTermsModal">términos y condiciones</a>
|
|
y la
|
|
<a href="#" @click.prevent="showPrivacyModal">política de privacidad</a>
|
|
</a-checkbox>
|
|
</a-form-item>
|
|
|
|
<!-- Mensaje de error -->
|
|
<div v-if="authStore.error && activeTab === 'register'" class="error-message">
|
|
<AlertOutlined />
|
|
<span>{{ authStore.error }}</span>
|
|
</div>
|
|
|
|
<!-- Botón de submit -->
|
|
<a-form-item>
|
|
<a-button
|
|
type="primary"
|
|
html-type="submit"
|
|
size="large"
|
|
:loading="authStore.loading && activeTab === 'register'"
|
|
block
|
|
class="submit-btn"
|
|
>
|
|
<template v-if="!authStore.loading || activeTab !== 'register'">
|
|
<UserAddOutlined />
|
|
Crear Cuenta
|
|
</template>
|
|
<span v-else>Registrando...</span>
|
|
</a-button>
|
|
</a-form-item>
|
|
|
|
<!-- Enlace para iniciar sesión -->
|
|
<div class="switch-auth">
|
|
<span>¿Ya tienes una cuenta? </span>
|
|
<a-button type="link" @click="activeTab = 'login'">
|
|
Inicia sesión aquí
|
|
</a-button>
|
|
</div>
|
|
</a-form>
|
|
</div>
|
|
</a-tab-pane>
|
|
</a-tabs>
|
|
|
|
<!-- Enlace de ayuda -->
|
|
<div class="help-section">
|
|
<a-divider>¿Necesitas ayuda?</a-divider>
|
|
<p class="help-text">
|
|
Si tienes problemas para acceder, comunícate con la
|
|
Dirección de Admisión al
|
|
<a href="tel:0511234567">(051) 123-4567</a>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<!-- Footer minimalista -->
|
|
<footer class="login-footer">
|
|
<div class="footer-container">
|
|
<p>© 2024 Universidad Nacional del Altiplano - Dirección de Admisión</p>
|
|
<div class="footer-links">
|
|
<a href="#" @click.prevent="showTermsModal">Términos y Condiciones</a>
|
|
<a href="#" @click.prevent="showPrivacyModal">Política de Privacidad</a>
|
|
<a href="#" @click.prevent="showHelpModal">Ayuda</a>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
|
|
<!-- Modales -->
|
|
<a-modal
|
|
v-model:visible="termsModalVisible"
|
|
title="Términos y Condiciones"
|
|
:width="modalWidth"
|
|
:footer="null"
|
|
>
|
|
<div class="modal-content">
|
|
<h3>Términos y Condiciones del Portal del Postulante</h3>
|
|
<p>1. El postulante se compromete a proporcionar información veraz y actualizada.</p>
|
|
<p>2. La Universidad se reserva el derecho de verificar la autenticidad de los documentos.</p>
|
|
<p>3. El acceso al portal es personal e intransferible.</p>
|
|
<p>4. El postulante es responsable de mantener la confidencialidad de sus credenciales.</p>
|
|
</div>
|
|
</a-modal>
|
|
|
|
<a-modal
|
|
v-model:visible="privacyModalVisible"
|
|
title="Política de Privacidad"
|
|
:width="modalWidth"
|
|
:footer="null"
|
|
>
|
|
<div class="modal-content">
|
|
<h3>Política de Privacidad</h3>
|
|
<p>1. Protegemos tus datos personales conforme a la Ley de Protección de Datos Personales.</p>
|
|
<p>2. Tu información será utilizada exclusivamente para fines de admisión.</p>
|
|
<p>3. No compartiremos tu información con terceros sin tu consentimiento.</p>
|
|
<p>4. Puedes solicitar la eliminación de tus datos según la normativa vigente.</p>
|
|
</div>
|
|
</a-modal>
|
|
|
|
<a-modal
|
|
v-model:visible="forgotPasswordModalVisible"
|
|
title="Recuperar Contraseña"
|
|
:width="modalWidth"
|
|
:footer="null"
|
|
>
|
|
<div class="modal-content">
|
|
<p>Ingresa tu correo electrónico para recibir un enlace de recuperación:</p>
|
|
<a-form
|
|
:model="forgotPasswordForm"
|
|
:rules="forgotPasswordRules"
|
|
layout="vertical"
|
|
@finish="handleForgotPassword"
|
|
>
|
|
<a-form-item label="Correo Electrónico" name="email">
|
|
<a-input
|
|
v-model:value="forgotPasswordForm.email"
|
|
placeholder="ejemplo@correo.com"
|
|
size="large"
|
|
>
|
|
<template #prefix>
|
|
<MailOutlined />
|
|
</template>
|
|
</a-input>
|
|
</a-form-item>
|
|
<a-button type="primary" html-type="submit" block :loading="sendingResetLink">
|
|
<template v-if="!sendingResetLink">
|
|
Enviar enlace de recuperación
|
|
</template>
|
|
<span v-else>Enviando...</span>
|
|
</a-button>
|
|
</a-form>
|
|
</div>
|
|
</a-modal>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, reactive, onMounted, computed, nextTick } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
import { useAuthStore } from '../../store/postulanteStore'
|
|
import {
|
|
UserOutlined,
|
|
MailOutlined,
|
|
LockOutlined,
|
|
LoginOutlined,
|
|
UserAddOutlined,
|
|
SafetyOutlined,
|
|
IdcardOutlined,
|
|
AlertOutlined
|
|
} from '@ant-design/icons-vue'
|
|
import { message } from 'ant-design-vue'
|
|
|
|
const router = useRouter()
|
|
const authStore = useAuthStore()
|
|
|
|
// Refs
|
|
const activeTab = ref('login')
|
|
const loginFormRef = ref()
|
|
const registerFormRef = ref()
|
|
const rememberMe = ref(false)
|
|
const termsModalVisible = ref(false)
|
|
const privacyModalVisible = ref(false)
|
|
const forgotPasswordModalVisible = ref(false)
|
|
const sendingResetLink = ref(false)
|
|
|
|
// Computed para ancho de modal responsivo
|
|
const modalWidth = computed(() => {
|
|
const width = window.innerWidth
|
|
if (width < 640) return '90%'
|
|
if (width < 768) return '85%'
|
|
if (width < 992) return '80%'
|
|
return '600px'
|
|
})
|
|
|
|
// Estados de formularios
|
|
const loginForm = reactive({
|
|
email: '',
|
|
password: ''
|
|
})
|
|
|
|
const registerForm = reactive({
|
|
name: '',
|
|
email: '',
|
|
dni: '',
|
|
password: '',
|
|
password_confirmation: '',
|
|
terms: false
|
|
})
|
|
|
|
const forgotPasswordForm = reactive({
|
|
email: ''
|
|
})
|
|
|
|
// Reglas de validación
|
|
const loginRules = {
|
|
email: [
|
|
{ required: true, message: 'Por favor ingresa tu correo', trigger: 'blur' },
|
|
{ type: 'email', message: 'Correo electrónico inválido', trigger: 'blur' }
|
|
],
|
|
password: [
|
|
{ required: true, message: 'Por favor ingresa tu contraseña', trigger: 'blur' },
|
|
{ min: 6, message: 'La contraseña debe tener al menos 6 caracteres', trigger: 'blur' }
|
|
]
|
|
}
|
|
|
|
const registerRules = {
|
|
name: [
|
|
{ required: true, message: 'Por favor ingresa tus nombres', trigger: 'blur' },
|
|
{ min: 3, message: 'El nombre debe tener al menos 3 caracteres', trigger: 'blur' }
|
|
],
|
|
email: [
|
|
{ required: true, message: 'Por favor ingresa tu correo', trigger: 'blur' },
|
|
{ type: 'email', message: 'Correo electrónico inválido', trigger: 'blur' }
|
|
],
|
|
dni: [
|
|
{ required: true, message: 'Por favor ingresa tu DNI', trigger: 'blur' },
|
|
{ pattern: /^\d{8}$/, message: 'El DNI debe tener 8 dígitos', trigger: 'blur' }
|
|
],
|
|
password: [
|
|
{ required: true, message: 'Por favor crea una contraseña', trigger: 'blur' },
|
|
{ min: 6, message: 'La contraseña debe tener al menos 6 caracteres', trigger: 'blur' }
|
|
],
|
|
password_confirmation: [
|
|
{
|
|
required: true,
|
|
message: 'Por favor confirma tu contraseña',
|
|
trigger: 'blur'
|
|
},
|
|
{
|
|
async validator(_, value) {
|
|
if (!value) return
|
|
if (value !== registerForm.password) {
|
|
throw new Error('Las contraseñas no coinciden')
|
|
}
|
|
},
|
|
trigger: 'blur'
|
|
}
|
|
]
|
|
,
|
|
terms: [
|
|
{
|
|
async validator(_, value) {
|
|
if (!value) {
|
|
throw new Error('Debes aceptar los términos y condiciones')
|
|
}
|
|
},
|
|
trigger: 'change'
|
|
}
|
|
]
|
|
|
|
}
|
|
|
|
const forgotPasswordRules = {
|
|
email: [
|
|
{ required: true, message: 'Por favor ingresa tu correo', trigger: 'blur' },
|
|
{ type: 'email', message: 'Correo electrónico inválido', trigger: 'blur' }
|
|
]
|
|
}
|
|
|
|
// Manejar login
|
|
const handleLogin = async (values) => {
|
|
const deviceId = rememberMe.value ? generateDeviceId() : null
|
|
|
|
const result = await authStore.login({
|
|
email: values.email,
|
|
password: values.password,
|
|
device_id: deviceId
|
|
})
|
|
|
|
if (result.success) {
|
|
// Redirigir al portal
|
|
router.push('/portal-postulante')
|
|
}
|
|
}
|
|
|
|
// Manejar registro - MODIFICADO: Ahora cambia a login después del registro
|
|
const handleRegister = async (values) => {
|
|
try {
|
|
const result = await authStore.register({
|
|
name: values.name,
|
|
email: values.email,
|
|
dni: values.dni,
|
|
password: values.password,
|
|
password_confirmation: values.password_confirmation
|
|
})
|
|
|
|
if (result.success) {
|
|
// Mostrar mensaje de éxito
|
|
message.success({
|
|
content: '¡Registro exitoso! Ahora puedes iniciar sesión con tus credenciales.',
|
|
duration: 5,
|
|
})
|
|
|
|
// Guardar el email del registro para facilitar el login
|
|
loginForm.email = values.email
|
|
loginForm.password = '' // Limpiar la contraseña por seguridad
|
|
|
|
// Cambiar a la pestaña de login
|
|
activeTab.value = 'login'
|
|
|
|
// Limpiar el formulario de registro después de un breve delay
|
|
setTimeout(() => {
|
|
registerForm.name = ''
|
|
registerForm.email = ''
|
|
registerForm.dni = ''
|
|
registerForm.password = ''
|
|
registerForm.password_confirmation = ''
|
|
registerForm.terms = false
|
|
|
|
// Resetear errores de validación
|
|
if (registerFormRef.value) {
|
|
registerFormRef.value.clearValidate()
|
|
}
|
|
}, 500)
|
|
|
|
return
|
|
}
|
|
|
|
// Si hay error en el registro, mostrar mensaje
|
|
if (result.error) {
|
|
message.error(result.error)
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('Error en registro:', error)
|
|
message.error('Error en el proceso de registro. Por favor, inténtalo nuevamente.')
|
|
}
|
|
}
|
|
|
|
// Funciones auxiliares
|
|
const generateDeviceId = () => {
|
|
return 'device_' + Math.random().toString(36).substr(2, 9)
|
|
}
|
|
|
|
const showForgotPassword = () => {
|
|
forgotPasswordModalVisible.value = true
|
|
}
|
|
|
|
const handleForgotPassword = async (values) => {
|
|
sendingResetLink.value = true
|
|
try {
|
|
// Aquí implementarías la llamada a la API para recuperar contraseña
|
|
// await api.post('/postulante/forgot-password', { email: values.email })
|
|
|
|
// Simulando envío
|
|
await new Promise(resolve => setTimeout(resolve, 1500))
|
|
|
|
message.success('Se ha enviado un enlace de recuperación a tu correo electrónico')
|
|
forgotPasswordModalVisible.value = false
|
|
forgotPasswordForm.email = ''
|
|
} catch (error) {
|
|
console.error('Error enviando enlace de recuperación:', error)
|
|
message.error('Error al enviar el enlace de recuperación')
|
|
} finally {
|
|
sendingResetLink.value = false
|
|
}
|
|
}
|
|
|
|
const showTermsModal = () => {
|
|
termsModalVisible.value = true
|
|
}
|
|
|
|
const showPrivacyModal = () => {
|
|
privacyModalVisible.value = true
|
|
}
|
|
|
|
const showHelpModal = () => {
|
|
alert('Para ayuda, contacta a la Dirección de Admisión al (051) 123-4567 o escribe a admision@una.edu.pe')
|
|
}
|
|
|
|
// Si ya está autenticado, redirigir al portal
|
|
onMounted(async () => {
|
|
const isAuthenticated = await authStore.checkAuth()
|
|
if (isAuthenticated) {
|
|
router.push('/portal')
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
/* Variables */
|
|
:root {
|
|
--primary-color: #1890ff;
|
|
--secondary-color: #4a5568;
|
|
--accent-color: #4299e1;
|
|
--light-gray: #f7fafc;
|
|
--medium-gray: #e2e8f0;
|
|
--dark-gray: #2d3748;
|
|
--white: #ffffff;
|
|
--shadow-light: 0 2px 8px rgba(0, 0, 0, 0.06);
|
|
--shadow-medium: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
--shadow-heavy: 0 8px 24px rgba(0, 0, 0, 0.12);
|
|
--font-family: "Times New Roman", Times, serif;
|
|
--una-blue: #1a365d;
|
|
--una-gold: #d4af37;
|
|
}
|
|
|
|
/* Estructura de la página */
|
|
.login-page {
|
|
min-height: 100vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
font-family: var(--font-family);
|
|
background: #f8f9fa;
|
|
}
|
|
|
|
/* =========================================== */
|
|
/* ENCABEZADO CON LOGO UNA */
|
|
/* =========================================== */
|
|
.login-header {
|
|
background: var(--una-blue);
|
|
color: white;
|
|
padding: 12px 0;
|
|
box-shadow: var(--shadow-heavy);
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 1000;
|
|
}
|
|
|
|
.header-container {
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: 0 20px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.una-logo {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16px;
|
|
}
|
|
|
|
.logo-wrapper {
|
|
width: 50px;
|
|
height: 50px;
|
|
border-radius: 8px;
|
|
background: white;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 4px;
|
|
box-shadow: var(--shadow-medium);
|
|
}
|
|
|
|
.logo-img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: contain;
|
|
}
|
|
|
|
.una-titles {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.una-main-title {
|
|
margin: 0;
|
|
font-size: 1.25rem;
|
|
font-weight: 700;
|
|
color: white;
|
|
line-height: 1.2;
|
|
}
|
|
|
|
.una-subtitle {
|
|
margin: 4px 0 0;
|
|
font-size: 1rem;
|
|
font-weight: 500;
|
|
color: var(--una-gold);
|
|
letter-spacing: 0.5px;
|
|
}
|
|
|
|
.header-contact {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
text-align: right;
|
|
}
|
|
|
|
.contact-item {
|
|
display: flex;
|
|
gap: 8px;
|
|
align-items: center;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.contact-label {
|
|
font-weight: 600;
|
|
color: var(--una-gold);
|
|
}
|
|
|
|
.contact-value {
|
|
color: white;
|
|
}
|
|
|
|
/* Contenido principal - CENTRADO */
|
|
.login-main {
|
|
flex: 1;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 30px 20px;
|
|
width: 100%;
|
|
}
|
|
|
|
.login-container {
|
|
max-width: 500px; /* Ancho fijo para centrar */
|
|
width: 100%;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
/* Card de autenticación */
|
|
.auth-card {
|
|
background: rgb(255, 255, 255);
|
|
border-radius: 12px;
|
|
padding: 40px;
|
|
box-shadow: var(--shadow-heavy);
|
|
border: 1px solid var(--medium-gray);
|
|
width: 100%;
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.card-logo {
|
|
text-align: center;
|
|
margin-bottom: 30px;
|
|
padding-bottom: 20px;
|
|
border-bottom: 1px solid var(--medium-gray);
|
|
}
|
|
|
|
.logo-icon-small {
|
|
width: 60px;
|
|
height: 60px;
|
|
border-radius: 10px;
|
|
background: var(--white);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
margin: 0 auto 15px;
|
|
border: 2px solid var(--primary-color);
|
|
padding: 5px;
|
|
}
|
|
|
|
.logo-icon-small img {
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: contain;
|
|
}
|
|
|
|
.card-logo-text h2 {
|
|
margin: 0 0 8px;
|
|
color: var(--primary-color);
|
|
font-size: 1.35rem;
|
|
font-weight: 700;
|
|
}
|
|
|
|
.card-logo-text span {
|
|
color: var(--secondary-color);
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
/* Tabs de autenticación */
|
|
.auth-tabs :deep(.ant-tabs-nav) {
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.auth-tabs :deep(.ant-tabs-tab) {
|
|
font-size: 1rem;
|
|
font-weight: 500;
|
|
padding: 12px 24px;
|
|
}
|
|
|
|
.auth-tabs :deep(.ant-tabs-tab-active .ant-tabs-tab-btn) {
|
|
color: var(--primary-color);
|
|
font-weight: 600;
|
|
}
|
|
|
|
.auth-tabs :deep(.ant-tabs-ink-bar) {
|
|
background: var(--primary-color);
|
|
}
|
|
|
|
/* Formularios */
|
|
.form-section {
|
|
background: var(--white);
|
|
margin-top: 6px;
|
|
border-radius: 8px;
|
|
padding: 0;
|
|
}
|
|
|
|
.form-header {
|
|
text-align: center;
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
.form-header h3 {
|
|
margin: 0 0 8px;
|
|
color: var(--primary-color);
|
|
font-size: 1.25rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.form-header p {
|
|
margin: 0;
|
|
color: var(--secondary-color);
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.auth-form :deep(.ant-form-item-label) {
|
|
font-weight: 600;
|
|
color: var(--secondary-color);
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.auth-form :deep(.ant-input),
|
|
.auth-form :deep(.ant-input-password) {
|
|
border-radius: 6px;
|
|
border: 1px solid var(--medium-gray);
|
|
transition: all 0.3s;
|
|
font-family: var(--font-family);
|
|
}
|
|
|
|
.auth-form :deep(.ant-input:hover),
|
|
.auth-form :deep(.ant-input-password:hover) {
|
|
border-color: var(--primary-color);
|
|
}
|
|
|
|
.auth-form :deep(.ant-input:focus),
|
|
.auth-form :deep(.ant-input-password:focus) {
|
|
border-color: var(--primary-color);
|
|
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.1);
|
|
}
|
|
|
|
/* Opciones del formulario */
|
|
.form-options {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
margin-bottom: 20px;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.form-options :deep(.ant-checkbox-wrapper) {
|
|
color: var(--secondary-color);
|
|
}
|
|
|
|
.form-options :deep(.ant-btn-link) {
|
|
padding: 0;
|
|
height: auto;
|
|
color: var(--primary-color);
|
|
text-align: left;
|
|
}
|
|
|
|
.form-options :deep(.ant-btn-link:hover) {
|
|
color: #096dd9;
|
|
}
|
|
|
|
/* Switch entre login y registro */
|
|
.switch-auth {
|
|
text-align: center;
|
|
margin-top: 20px;
|
|
color: var(--secondary-color);
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.switch-auth :deep(.ant-btn-link) {
|
|
padding: 0;
|
|
height: auto;
|
|
color: var(--primary-color);
|
|
font-weight: 500;
|
|
}
|
|
|
|
.switch-auth :deep(.ant-btn-link:hover) {
|
|
color: #096dd9;
|
|
}
|
|
|
|
/* Mensajes de error */
|
|
.error-message {
|
|
background: #fff2f0;
|
|
border: 1px solid #ffccc7;
|
|
border-radius: 6px;
|
|
padding: 12px 16px;
|
|
margin-bottom: 20px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
color: #cf1322;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.error-message svg {
|
|
font-size: 16px;
|
|
}
|
|
|
|
/* BOTÓN DE SUBMIT - AZUL SÓLIDO */
|
|
.submit-btn {
|
|
height: 48px;
|
|
font-weight: 600;
|
|
background: var(--primary-color); /* Azul sólido */
|
|
border: none;
|
|
border-radius: 8px;
|
|
box-shadow: var(--shadow-medium);
|
|
transition: all 0.3s;
|
|
margin-top: 10px;
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.submit-btn:hover {
|
|
background: #096dd9; /* Azul más oscuro para hover */
|
|
transform: translateY(-2px);
|
|
box-shadow: var(--shadow-heavy);
|
|
}
|
|
|
|
.submit-btn:active {
|
|
background: #0050b3;
|
|
transform: translateY(0);
|
|
}
|
|
|
|
/* Términos y condiciones */
|
|
.auth-form :deep(.ant-form-item-control-input-content) .ant-checkbox-wrapper a {
|
|
color: var(--primary-color);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.auth-form :deep(.ant-form-item-control-input-content) .ant-checkbox-wrapper a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
/* Sección de ayuda */
|
|
.help-section {
|
|
margin-top: 30px;
|
|
}
|
|
|
|
.help-text {
|
|
text-align: center;
|
|
color: var(--secondary-color);
|
|
font-size: 0.875rem;
|
|
margin: 0;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.help-text a {
|
|
color: var(--primary-color);
|
|
text-decoration: none;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.help-text a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
/* Footer */
|
|
.login-footer {
|
|
background: var(--una-blue);
|
|
color: white;
|
|
padding: 20px 0;
|
|
margin-top: auto;
|
|
width: 100%;
|
|
}
|
|
|
|
.footer-container {
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: 0 20px;
|
|
text-align: center;
|
|
}
|
|
|
|
.footer-container p {
|
|
margin: 0 0 12px;
|
|
color: rgba(255, 255, 255, 0.8);
|
|
font-size: 0.75rem;
|
|
}
|
|
|
|
.footer-links {
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: 20px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.footer-links a {
|
|
color: rgba(255, 255, 255, 0.8);
|
|
font-size: 0.75rem;
|
|
text-decoration: none;
|
|
transition: color 0.3s;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.footer-links a:hover {
|
|
color: var(--una-gold);
|
|
text-decoration: underline;
|
|
}
|
|
|
|
/* Modales */
|
|
.modal-content {
|
|
padding: 16px 0;
|
|
font-family: var(--font-family);
|
|
font-size: 0.938rem;
|
|
}
|
|
|
|
.modal-content h3 {
|
|
color: var(--primary-color);
|
|
margin-bottom: 16px;
|
|
font-size: 1.125rem;
|
|
}
|
|
|
|
.modal-content p {
|
|
color: var(--secondary-color);
|
|
margin-bottom: 12px;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
/* =========================================== */
|
|
/* MEDIA QUERIES PARA RESPONSIVIDAD */
|
|
/* =========================================== */
|
|
|
|
/* Tablets pequeñas y móviles grandes (576px - 768px) */
|
|
@media (max-width: 768px) {
|
|
.header-container {
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
text-align: center;
|
|
}
|
|
|
|
.una-logo {
|
|
justify-content: center;
|
|
}
|
|
|
|
.header-contact {
|
|
text-align: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.contact-item {
|
|
justify-content: center;
|
|
}
|
|
|
|
.login-main {
|
|
padding: 20px 15px;
|
|
}
|
|
|
|
.auth-card {
|
|
padding: 30px 25px;
|
|
}
|
|
|
|
.card-logo-text h2 {
|
|
font-size: 1.25rem;
|
|
}
|
|
|
|
.auth-tabs :deep(.ant-tabs-tab) {
|
|
padding: 10px 20px;
|
|
font-size: 0.938rem;
|
|
}
|
|
|
|
.form-header h3 {
|
|
font-size: 1.125rem;
|
|
}
|
|
|
|
.submit-btn {
|
|
height: 46px;
|
|
font-size: 0.938rem;
|
|
}
|
|
}
|
|
|
|
/* Móviles pequeños y medianos (480px - 576px) */
|
|
@media (max-width: 576px) {
|
|
.login-header {
|
|
padding: 10px 0;
|
|
}
|
|
|
|
.una-main-title {
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.una-subtitle {
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.logo-wrapper {
|
|
width: 40px;
|
|
height: 40px;
|
|
}
|
|
|
|
.contact-item {
|
|
font-size: 0.813rem;
|
|
}
|
|
|
|
.login-main {
|
|
padding: 15px 10px;
|
|
}
|
|
|
|
.auth-card {
|
|
padding: 25px 20px;
|
|
border-radius: 10px;
|
|
}
|
|
|
|
.card-logo {
|
|
margin-bottom: 25px;
|
|
}
|
|
|
|
.logo-icon-small {
|
|
width: 50px;
|
|
height: 50px;
|
|
}
|
|
|
|
.card-logo-text h2 {
|
|
font-size: 1.125rem;
|
|
}
|
|
|
|
.card-logo-text span {
|
|
font-size: 0.813rem;
|
|
}
|
|
|
|
.auth-tabs :deep(.ant-tabs-nav) {
|
|
margin-bottom: 25px;
|
|
}
|
|
|
|
.auth-tabs :deep(.ant-tabs-tab) {
|
|
padding: 8px 16px;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.form-header {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.form-header h3 {
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.form-header p {
|
|
font-size: 0.813rem;
|
|
}
|
|
|
|
.auth-form :deep(.ant-form-item-label) {
|
|
font-size: 0.813rem;
|
|
}
|
|
|
|
.auth-form :deep(.ant-input),
|
|
.auth-form :deep(.ant-input-password) {
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.form-options {
|
|
font-size: 0.813rem;
|
|
}
|
|
|
|
.switch-auth {
|
|
font-size: 0.813rem;
|
|
}
|
|
|
|
.error-message {
|
|
padding: 10px 14px;
|
|
font-size: 0.813rem;
|
|
}
|
|
|
|
.submit-btn {
|
|
height: 44px;
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.help-section {
|
|
margin-top: 25px;
|
|
}
|
|
|
|
.help-text {
|
|
font-size: 0.813rem;
|
|
}
|
|
|
|
.login-footer {
|
|
padding: 16px 0;
|
|
}
|
|
|
|
.footer-container p {
|
|
font-size: 0.688rem;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.footer-links {
|
|
gap: 15px;
|
|
}
|
|
|
|
.footer-links a {
|
|
font-size: 0.688rem;
|
|
}
|
|
}
|
|
|
|
/* Móviles muy pequeños (menos de 480px) */
|
|
@media (max-width: 480px) {
|
|
.una-logo {
|
|
flex-direction: column;
|
|
text-align: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
.header-contact {
|
|
width: 100%;
|
|
}
|
|
|
|
.login-main {
|
|
padding: 10px 8px;
|
|
}
|
|
|
|
.auth-card {
|
|
padding: 20px 16px;
|
|
}
|
|
|
|
.auth-tabs :deep(.ant-tabs-tab) {
|
|
padding: 6px 12px;
|
|
font-size: 0.813rem;
|
|
}
|
|
|
|
.card-logo-text h2 {
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.form-options {
|
|
flex-direction: column;
|
|
gap: 10px;
|
|
}
|
|
|
|
.form-options :deep(.ant-checkbox-wrapper) {
|
|
width: 100%;
|
|
}
|
|
|
|
.form-options :deep(.ant-btn-link) {
|
|
align-self: flex-start;
|
|
}
|
|
|
|
.submit-btn {
|
|
height: 42px;
|
|
}
|
|
|
|
.modal-content {
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
.modal-content h3 {
|
|
font-size: 1rem;
|
|
}
|
|
}
|
|
|
|
/* Pantallas muy altas */
|
|
@media (min-height: 800px) {
|
|
.login-main {
|
|
padding-top: 50px;
|
|
padding-bottom: 50px;
|
|
}
|
|
}
|
|
</style> |