web_page_finish

main
elmer-20 2 months ago
parent 9cbd6d2a88
commit 7a528bd7bf

@ -161,28 +161,28 @@ class PostulanteAuthController extends Controller
$pagos = []; $pagos = [];
// =============================== // // ===============================
// 1⃣ PAGOS PYTO PERÚ // // 1⃣ PAGOS PYTO PERÚ
// =============================== // // ===============================
$urlPyto = "https://service2.unap.edu.pe/PAYMENTS_MNG/v1/{$dni}/8/"; // $urlPyto = "https://service2.unap.edu.pe/PAYMENTS_MNG/v1/{$dni}/8/";
$responsePyto = Http::get($urlPyto); // $responsePyto = Http::get($urlPyto);
if ($responsePyto->successful()) { // if ($responsePyto->successful()) {
$dataPyto = $responsePyto->json(); // $dataPyto = $responsePyto->json();
if (!empty($dataPyto['data'])) { // if (!empty($dataPyto['data'])) {
foreach ($dataPyto['data'] as $pago) { // foreach ($dataPyto['data'] as $pago) {
$pagos[] = [ // $pagos[] = [
'tipo' => 'pyto_peru', // 'tipo' => 'pyto_peru',
'codigo' => $pago['autorizationCode'] ?? null, // 'codigo' => $pago['autorizationCode'] ?? null,
'monto' => $pago['total'] ?? null, // 'monto' => $pago['total'] ?? null,
'fecha_pago' => $pago['confirmedDate'] ?? null, // 'fecha_pago' => $pago['confirmedDate'] ?? null,
'estado' => true, // 'estado' => true,
'raw' => $pago // devuelve toda la info original // 'raw' => $pago // devuelve toda la info original
]; // ];
} // }
} // }
} // }
// =============================== // ===============================
// 2⃣ PAGOS CAJA // 2⃣ PAGOS CAJA

@ -79,7 +79,7 @@ Route::middleware(['auth:sanctum'])->prefix('admin')->group(function () {
Route::delete('/noticias/{noticia}', [NoticiaController::class, 'destroy']); Route::delete('/noticias/{noticia}', [NoticiaController::class, 'destroy']);
}); });
Route::get('/noticias', [NoticiaController::class, 'index']); Route::get('/noticias', [NoticiaController::class, 'index']);
Route::get('/noticias/{noticia}', [NoticiaController::class, 'showPublic']); Route::get('/noticias/{noticia}', [NoticiaController::class, 'showPublic']);
Route::middleware(['auth:sanctum'])->prefix('admin')->group(function () { Route::middleware(['auth:sanctum'])->prefix('admin')->group(function () {

@ -2,9 +2,9 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> <link rel="icon" type="image/svg+xml" href="" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>frontend</title> <title>Admisión</title>
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 346 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

@ -11,7 +11,7 @@
<ConvocatoriasSection/> <ConvocatoriasSection/>
<ProgramasSection/> <!-- <ProgramasSection/> -->
<StatsSection /> <StatsSection />
@ -19,6 +19,7 @@
<ContactSection /> <ContactSection />
</div> </div>

@ -1,139 +1,171 @@
<!-- components/contact/ContactSection.vue -->
<template> <template>
<section class="contact-section"> <section class="process-section" aria-labelledby="faq-title">
<div class="section-container"> <div class="section-container">
<div class="contact-grid">
<div class="contact-info"> <!-- Header -->
<h2 class="section-title">¿Necesitas Ayuda?</h2> <div class="section-header">
<p class="contact-subtitle">Nuestro equipo está listo para asistirte en todo el proceso de admisión</p> <h2 id="faq-title" class="section-title">
Preguntas Frecuentes
<div class="contact-methods"> </h2>
<div class="contact-method"> <p class="section-subtitle">
<PhoneOutlined /> Resolvemos las dudas más comunes sobre el proceso de admisión y el uso de nuestra plataforma.
<div> </p>
<h4>Teléfono</h4> </div>
<p>(01) 123-4567</p>
</div> <div class="process-card">
</div>
<div class="contact-method">
<MailOutlined /> <!-- FAQ -->
<div> <a-collapse accordion class="modern-collapse">
<h4>Email</h4>
<p>admision@universidad.edu.pe</p> <a-collapse-panel key="1" header="01. ¿Puedo postular con DNI caducado?">
</div> No, su DNI debe estar vigente al momento de la inscripción.
</div> En su defecto, puede presentar la Hoja C4 o el ticket de trámite acompañado de una copia del DNI.
<div class="contact-method"> </a-collapse-panel>
<ClockCircleOutlined />
<div> <a-collapse-panel key="2" header="02. ¿Qué requisitos debo presentar si postulo como persona con discapacidad?">
<h4>Horario</h4> Certificado de Discapacidad emitido por entidades de salud acreditadas en el RENIPRESS.
<p>Lun-Vie: 8:00 AM - 6:00 PM</p> Este debe ser adjuntado junto a los demás requisitos.
</div> </a-collapse-panel>
</div>
</div> <a-collapse-panel key="3" header="03. ¿Qué hago si ingreso mal mis datos en la preinscripción?">
</div> No es posible modificarlos en línea una vez guardados.
Debe acercarse al local de inscripción y solicitar ayuda en la oficina de soporte técnico.
<div class="contact-form"> </a-collapse-panel>
<h3>Envíanos un Mensaje</h3>
<a-form layout="vertical"> <a-collapse-panel key="4" header="04. ¿Cuáles son los códigos para realizar los pagos?">
<a-form-item label="Nombre completo"> <p><b>Código 26:</b> Derechos de Admisión.</p>
<a-input placeholder="Ingresa tu nombre completo" /> <p><b>Código 27:</b> Rezagados al proceso de inscripción.</p>
</a-form-item> <p><b>Código 28:</b> Carpeta de postulante.</p>
<a-form-item label="Email"> </a-collapse-panel>
<a-input placeholder="tu@email.com" />
</a-form-item> <a-collapse-panel key="5" header="05. ¿Cómo debo realizar la preinscripción e inscripción?">
<a-form-item label="Consulta"> Ingrese a admision.unap.edu.pe para la preinscripción.
<a-textarea placeholder="Describe tu consulta..." :rows="4" /> <br /><br />
</a-form-item> La inscripción presencial se realiza según el último dígito del DNI, según el cronograma oficial.
<a-button type="primary" block>Enviar Mensaje</a-button> </a-collapse-panel>
</a-form>
</div> <a-collapse-panel key="6" header="06. ¿Qué requisitos debo presentar si postulo a Medicina Humana o Educación Física?">
Constancia de evaluación médica emitida por un establecimiento de salud primario,
además de los demás requisitos exigidos.
</a-collapse-panel>
<a-collapse-panel key="7" header="07. ¿Puedo cambiar de programa de estudio luego de inscribirme?">
. Tras obtener su constancia de inscripción, debe realizar un pago de S/.100 (Código 27)
en caja de la Universidad o Banco de la Nación, incluyendo comisión.
</a-collapse-panel>
<a-collapse-panel key="8" header="08. ¿Qué debo traer para inscribirme presencialmente?">
<ul>
<li>Comprobantes de pago o vouchers</li>
<li>DNI original y copia</li>
<li>Solicitud de Preinscripción impresa</li>
<li>Certificado de estudios original y copia</li>
</ul>
</a-collapse-panel>
<a-collapse-panel key="9" header="09. ¿Los postulantes con discapacidad hacen cola?">
No. Deben presentar su Certificado de Discapacidad y se les brindará atención preferencial.
</a-collapse-panel>
</a-collapse>
</div> </div>
</div> </div>
</section> </section>
</template> </template>
<script setup>
import { PhoneOutlined, MailOutlined, ClockCircleOutlined } from '@ant-design/icons-vue'
</script>
<style scoped> <style scoped>
.contact-section { /* reutiliza la misma base visual de ProcessSection */
padding: 80px 0;
.process-section {
padding: 30px 0;
background: #ffffff;
font-family: "Times New Roman", Times, serif;
} }
.section-container { .section-container {
max-width: 1200px; max-width: 1100px;
margin: 0 auto; margin: 0 auto;
padding: 0 24px; padding: 0 20px;
} }
.contact-grid { .section-header {
display: grid; text-align: center;
grid-template-columns: 1fr 1fr; margin-bottom: 18px;
gap: 80px;
align-items: start;
} }
.section-title { .section-title {
font-size: 2.5rem; font-size: 2.1rem;
font-weight: 700; font-weight: 700;
color: #1a237e; color: #2c3e50;
margin-bottom: 16px; margin: 0 0 6px 0;
} }
.contact-subtitle { .section-subtitle {
color: #666; font-size: 1rem;
font-size: 1.125rem; color: #777;
margin-bottom: 40px; margin: 0;
} }
.contact-methods { .process-card {
display: flex; border: 1px solid #e5e7eb;
flex-direction: column; border-radius: 14px;
gap: 24px; padding: 20px 18px;
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.04);
background: #fff;
} }
.contact-method { /* Ilustración */
display: flex; .illustration-box {
align-items: center; text-align: center;
gap: 16px; margin-bottom: 20px;
} }
.contact-method svg { .illustration-img {
color: #1890ff; width: 160px;
font-size: 24px; margin-bottom: 8px;
} }
.contact-method h4 { .illustration-text {
margin: 0 0 4px; font-size: 0.9rem;
color: #1a237e; color: #6b7280;
} }
.contact-method p { /* Collapse estilo limpio */
margin: 0; .modern-collapse {
color: #666; background: transparent;
} }
.contact-form { .modern-collapse :deep(.ant-collapse-item) {
background: white; border-radius: 10px !important;
padding: 40px; margin-bottom: 10px;
border-radius: 16px; background: #f8fafc;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08); border: 1px solid #e5e7eb;
} }
.contact-form h3 { .modern-collapse :deep(.ant-collapse-header) {
margin: 0 0 32px; font-weight: 700;
color: #1a237e; color: #1e3a8a;
} }
@media (max-width: 992px) { .modern-collapse :deep(.ant-collapse-content) {
.contact-grid { background: #ffffff;
grid-template-columns: 1fr; border-top: 1px solid #eef2f7;
gap: 48px; }
}
/* Responsive */
@media (max-width: 768px) {
.section-title { .section-title {
font-size: 2rem; font-size: 1.6rem;
}
.process-card {
padding: 14px 12px;
}
.illustration-img {
width: 120px;
} }
} }
</style> </style>

@ -140,51 +140,53 @@
<!-- SECUNDARIAS (hardcode por ahora) --> <!-- SECUNDARIAS (hardcode por ahora) -->
<div class="secondary-list"> <div class="secondary-list">
<a-card class="secondary-convocatoria-card">
<a-card class="secondary-convocatoria-card">
<div class="convocatoria-header"> <div class="convocatoria-header">
<div> <div>
<h4 class="secondary-title">CEPREUNA</h4> <h4 class="secondary-title">Extraordinario</h4>
<p class="convocatoria-date">30 de enero</p> <p class="convocatoria-date">30 de enero</p>
</div> </div>
<a-tag class="status-tag" color="default">FINALIZADO</a-tag> <a-tag class="status-tag" color="orange">Finalizado</a-tag>
</div> </div>
<p class="convocatoria-desc">Postulantes del CEPRE</p> <p class="convocatoria-desc">
Modalidad extraordinaria para perfiles específicos
</p>
<div class="card-footer"> <!-- <div class="card-footer">
<a-button type="link" size="small" @click="emit('show-modal', 'cepreuna')"> <a-button
type="link"
size="small"
@click="emit('show-modal', 'extraordinario')"
>
Ver detalles Ver detalles
</a-button> </a-button>
<a-button type="primary" ghost size="small">Consultar</a-button> <a-button type="primary" ghost size="small">Consultar</a-button>
</div> </div> -->
</a-card> </a-card>
<a-card class="secondary-convocatoria-card"> <a-card class="secondary-convocatoria-card">
<div class="convocatoria-header"> <div class="convocatoria-header">
<div> <div>
<h4 class="secondary-title">Extraordinario</h4> <h4 class="secondary-title">CEPREUNA</h4>
<p class="convocatoria-date">15 de febrero</p> <p class="convocatoria-date">10 y 11 de enero</p>
</div> </div>
<a-tag class="status-tag" color="orange">PRÓXIMAMENTE</a-tag> <a-tag class="status-tag" color="orange">Finalizado</a-tag>
</div> </div>
<p class="convocatoria-desc"> <p class="convocatoria-desc">Postulantes del CEPREUNA</p>
Modalidad extraordinaria para perfiles específicos
</p>
<div class="card-footer"> <!-- <div class="card-footer">
<a-button <a-button type="link" size="small" @click="emit('show-modal', 'cepreuna')">
type="link"
size="small"
@click="emit('show-modal', 'extraordinario')"
>
Ver detalles Ver detalles
</a-button> </a-button>
<a-button type="primary" ghost size="small">Consultar</a-button> <a-button type="primary" ghost size="small">Consultar</a-button>
</div> </div> -->
</a-card> </a-card>
</div> </div>
</div> </div>
</div> </div>
@ -204,7 +206,7 @@
:key="detalle.id" :key="detalle.id"
style="margin-bottom: 25px" style="margin-bottom: 25px"
> >
<h3>{{ detalle.titulo_detalle }}</h3> <!-- <h3>{{ detalle.titulo_detalle }}</h3> -->
<p v-if="detalle.descripcion"> <p v-if="detalle.descripcion">
{{ detalle.descripcion }} {{ detalle.descripcion }}

@ -1,15 +1,16 @@
<!-- components/hero/HeroSection.vue --> <!-- components/hero/HeroSection.vue -->
<template> <template>
<section class="hero" aria-label="Sección principal de admisión"> <section
class="hero"
<div class="hero-bg" aria-hidden="true"> :style="{ backgroundImage: `url(${heroImg})` }"
<div class="hero-grid"></div> aria-label="Sección principal de admisión"
<div class="hero-shape hero-shape-1"></div> >
<div class="hero-shape hero-shape-2"></div> <!-- Overlay oscuro -->
</div> <div class="hero-overlay"></div>
<div class="hero-container"> <div class="hero-container">
<!-- CONTENIDO -->
<div class="hero-content"> <div class="hero-content">
<div class="hero-badges"> <div class="hero-badges">
<a-tag class="hero-tag">Convocatoria 2026</a-tag> <a-tag class="hero-tag">Convocatoria 2026</a-tag>
@ -18,14 +19,18 @@
Inscripciones abiertas Inscripciones abiertas
</span> </span>
</div> </div>
<div class="glass-cardtitle">
<h1 class="hero-title">
Admisión <span class="hero-year">2026</span>
</h1>
</div>
<h1 class="hero-title">
Admisión <span class="hero-year">2026</span>
</h1>
<p class="hero-subtitle"> <p class="hero-subtitle">
Forma parte de una comunidad académica de excelencia. Forma parte de una comunidad académica de excelencia.
<span class="hero-subtitle-muted">Postula, infórmate y conoce el proceso.</span> <span class="hero-subtitle-muted">
Postula, infórmate y conoce el proceso.
</span>
</p> </p>
<div class="hero-actions"> <div class="hero-actions">
@ -39,78 +44,48 @@
Postular ahora Postular ahora
</a-button> </a-button>
<a-button size="large" class="secondary-button" @click="$emit('virtual-tour')">
<template #icon><PlayCircleOutlined /></template>
Tour virtual
</a-button>
</div>
<div class="hero-metrics">
<div class="metric">
<span class="metric-value">44</span>
<span class="metric-label">Programas</span>
</div>
<div class="metric">
<span class="metric-value">3</span>
<span class="metric-label">Áreas</span>
</div>
<div class="metric">
<span class="metric-value">+10</span>
<span class="metric-label">Sedes</span>
</div>
</div> </div>
</div> </div>
<!-- Visual --> <!-- CARD -->
<div class="hero-visual"> <!-- <div class="hero-visual">
<div class="visual-stack"> <div class="glass-card">
<div class="floating-card"> <div class="card-header">
<div class="card-header"> <CalendarOutlined />
<CalendarOutlined /> <span>Próximo evento</span>
<span>Próximo evento</span>
</div>
<h3 class="card-title">Charla informativa</h3>
<div class="card-info">
<span class="info-item">
<ClockCircleOutlined />
25 Nov 4:00 PM
</span>
<span class="info-item">
<VideoCameraOutlined />
Virtual
</span>
</div>
<a-button type="primary" ghost class="card-cta" size="middle">
Registrarse
</a-button>
</div> </div>
<div class="mini-card" aria-hidden="true"> <h3>Charla informativa</h3>
<span class="mini-dot"></span>
<div class="mini-text"> <p class="card-date">
<div class="mini-title">Guía del postulante</div> <ClockCircleOutlined />
<div class="mini-sub">Requisitos y fechas</div> 25 Nov 4:00 PM Virtual
</div> </p>
<ArrowRightOutlined class="mini-icon" />
</div> <a-button
size="large"
class="secondary-button"
@click="$emit('virtual-tour')"
>
<template #icon><PlayCircleOutlined /></template>
Tour virtual
</a-button>
</div> </div>
</div> </div> -->
</div> </div>
</section> </section>
</template> </template>
<script setup> <script setup>
const heroImg = "/PORTADA.jpg.jpeg";
import { import {
RightCircleOutlined, RightCircleOutlined,
PlayCircleOutlined, PlayCircleOutlined,
CalendarOutlined, CalendarOutlined,
CheckCircleOutlined, CheckCircleOutlined,
ClockCircleOutlined, ClockCircleOutlined
VideoCameraOutlined,
ArrowRightOutlined,
} from "@ant-design/icons-vue"; } from "@ant-design/icons-vue";
defineEmits(["scroll-to-convocatoria", "virtual-tour"]); defineEmits(["scroll-to-convocatoria", "virtual-tour"]);
@ -118,346 +93,161 @@ defineEmits(["scroll-to-convocatoria", "virtual-tour"]);
<style scoped> <style scoped>
/* 🔥 TODA LA SECCIÓN EN TIMES */
.hero, .hero,
.hero * { .hero * {
font-family: "Times New Roman", Times, serif; font-family: "Times New Roman", Times, serif;
} }
.hero { .hero {
--inst-primary: #1a237e; /* AZUL institucional (ejemplo) */
--inst-secondary: #0f172a; /* oscuro de apoyo */
--inst-accent: #c8a100; /* dorado institucional (ejemplo) */
position: relative; position: relative;
padding: 110px 0;
color: white;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
overflow: hidden; overflow: hidden;
color: #ffffff; --text: rgba(245, 247, 255, 0.92); /* blanco suave */
padding: 88px 0; --muted: rgba(229, 235, 255, 0.72);
background: var(--inst-primary); /* SIN DEGRADADOS */
}
/* Fondo decorativo sutil (sin degradados) */
.hero-bg {
position: absolute;
inset: 0;
pointer-events: none;
}
/* Patrón de líneas muy suave */
.hero-grid {
position: absolute;
inset: 0;
opacity: 0.10;
background-image: linear-gradient(rgba(255, 255, 255, 0.14) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.14) 1px, transparent 1px);
background-size: 52px 52px;
} }
.hero-shape {
position: absolute;
border-radius: 999px;
opacity: 0.16;
background: #ffffff;
}
.hero-shape-1 {
width: 460px;
height: 460px;
left: -220px;
top: -240px;
}
.hero-shape-2 {
width: 560px;
height: 560px;
right: -260px;
bottom: -320px;
}
.hero-container { .hero-container {
position: relative; position: relative;
z-index: 1;
max-width: 1200px; max-width: 1200px;
margin: 0 auto; margin: auto;
padding: 0 24px; padding: 0 24px;
display: grid; display: grid;
grid-template-columns: 1.1fr 0.9fr; grid-template-columns: 1.2fr 0.8fr;
gap: 72px;
align-items: center; align-items: center;
gap: 60px;
} }
/* BADGES */
.hero-badges { .hero-badges {
display: flex; display: flex;
align-items: center;
gap: 12px; gap: 12px;
margin-bottom: 20px;
flex-wrap: wrap; flex-wrap: wrap;
margin-bottom: 22px;
} }
.hero-tag { .hero-tag {
background: rgba(255, 255, 255, 0.15);
border: 1px solid rgba(255, 255, 255, 0.25); border: 1px solid rgba(255, 255, 255, 0.25);
color: #fff; color: rgb(255, 255, 255);
background: rgba(255, 255, 255, 0.12); font-weight: bold;
font-weight: 700;
} }
.hero-pill { .hero-pill {
display: inline-flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 6px;
background: rgba(255, 255, 255, 0.12);
padding: 6px 12px; padding: 6px 12px;
border-radius: 999px; border-radius: 999px;
border: 1px solid rgba(255, 255, 255, 0.22); font-weight: bold;
background: rgba(0, 0, 0, 0.10);
font-size: 0.95rem;
font-weight: 700;
} }
/* TITULO */
.hero-title { .hero-title {
font-size: 3.4rem; font-size: 3.5rem;
font-weight: 900; font-weight: bold;
line-height: 1.08; margin: 0 0 20px;
margin: 0 0 18px; color: rgba(245, 247, 255, 0.96);
letter-spacing: -0.01em;
} }
.hero-year { .hero-year {
color: var(--inst-accent); font-size: 2.8rem;
position: relative; font-weight: 900;
} line-height: 1;
.hero-year::after { background: linear-gradient(45deg, #ffd700, #ff6b6b);
content: ""; -webkit-background-clip: text;
position: absolute; -webkit-text-fill-color: transparent;
left: 0; background-clip: text;
bottom: -10px;
width: 100%;
height: 4px;
background: var(--inst-accent);
border-radius: 999px;
opacity: 0.9;
} }
.hero-subtitle { .hero-subtitle {
font-size: 1.18rem; font-size: 1.2rem;
opacity: 0.95; max-width: 550px;
margin: 0 0 32px; margin-bottom: 30px;
line-height: 1.65; line-height: 1.6;
max-width: 560px;
font-weight: 600;
}
.hero-subtitle-muted {
display: inline-block;
margin-left: 6px;
opacity: 0.9;
font-weight: 600;
} }
/* BOTONES */
.hero-actions { .hero-actions {
display: flex; display: flex;
gap: 14px; gap: 15px;
flex-wrap: wrap; flex-wrap: wrap;
} }
.cta-button { .cta-button {
border: 1px solid rgba(255, 255, 255, 0.22); font-weight: bold;
font-weight: 800; border-radius: 8px;
border-radius: 12px;
background: var(--inst-accent);
color: var(--inst-secondary);
}
.cta-button:hover {
filter: brightness(1.02);
transform: translateY(-1px);
} }
.secondary-button { .secondary-button {
background: transparent; background: transparent;
border: 2px solid rgba(255, 255, 255, 0.28); border: 2px solid rgba(255, 255, 255, 0.6);
color: #fff; color: white;
border-radius: 12px; border-radius: 8px;
font-weight: 800; font-weight: bold;
} }
.secondary-button:hover { /* CARD */
background: rgba(255, 255, 255, 0.08);
}
.hero-metrics {
margin-top: 28px;
display: flex;
gap: 14px;
flex-wrap: wrap;
}
.metric {
min-width: 120px;
padding: 12px 14px;
border-radius: 14px;
background: rgba(255, 255, 255, 0.10);
border: 1px solid rgba(255, 255, 255, 0.18);
}
.metric-value {
display: block;
font-size: 1.25rem;
font-weight: 900;
line-height: 1.1;
color: #fff;
}
.metric-label {
display: block;
opacity: 0.9;
font-size: 0.95rem;
margin-top: 2px;
font-weight: 700;
}
/* ====== VISUAL ====== */
.hero-visual { .hero-visual {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
} }
.visual-stack { .glass-card {
width: min(420px, 100%); background: rgba(106, 136, 219, 0.55);
display: grid; padding: 28px;
gap: 14px; border-radius: 16px;
} width: 100%;
max-width: 360px;
.floating-card { box-shadow: 0 25px 60px rgba(0, 0, 0, 0.3);
background: #ffffff;
color: #111827;
padding: 22px;
border-radius: 18px;
box-shadow: 0 24px 60px rgba(0, 0, 0, 0.18);
border: 1px solid rgba(17, 24, 39, 0.08);
transition: transform 0.25s ease, box-shadow 0.25s ease;
} }
.glass-cardtitle {
.floating-card:hover { background: rgba(190, 200, 228, 0.55);
transform: translateY(-4px); padding: 12px 24px;
box-shadow: 0 28px 70px rgba(0, 0, 0, 0.22); border-radius: 16px;
width: fit-content; /* 👈 se ajusta al contenido */
max-width: 100%;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
} }
.card-header { .card-header {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 10px;
color: #6b7280;
margin-bottom: 14px;
font-weight: 800;
}
.card-title {
margin: 0 0 12px;
color: #111827;
font-weight: 900;
}
.card-info {
display: flex;
flex-wrap: wrap;
gap: 10px 14px;
margin-bottom: 14px;
color: #374151;
font-weight: 700;
}
.info-item {
display: inline-flex;
align-items: center;
gap: 8px; gap: 8px;
font-size: 0.95rem; font-weight: bold;
font-weight: 800;
} }
.card-cta { .card-date {
border-radius: 12px;
font-weight: 900;
border-color: var(--inst-primary);
color: var(--inst-primary);
}
.mini-card {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 12px; gap: 6px;
padding: 14px 16px; margin-bottom: 20px;
border-radius: 16px;
background: rgba(255, 255, 255, 0.10);
border: 1px solid rgba(255, 255, 255, 0.18);
}
.mini-dot {
width: 10px;
height: 10px;
border-radius: 999px;
background: var(--inst-accent);
box-shadow: 0 0 0 6px rgba(200, 161, 0, 0.18);
}
.mini-title {
font-weight: 900;
line-height: 1.1;
}
.mini-sub {
opacity: 0.9;
font-size: 0.95rem;
margin-top: 2px;
font-weight: 700;
} }
.mini-icon { /* RESPONSIVE */
opacity: 0.9;
}
/* ====== Responsive ====== */
@media (max-width: 992px) { @media (max-width: 992px) {
.hero {
padding: 72px 0;
}
.hero-container { .hero-container {
grid-template-columns: 1fr; grid-template-columns: 1fr;
text-align: center; text-align: center;
gap: 40px;
}
.hero-subtitle {
margin-left: auto;
margin-right: auto;
}
.hero-actions {
justify-content: center;
} }
.hero-visual { .hero-visual {
justify-content: center; justify-content: center;
margin-top: 40px;
} }
.hero-title { .hero-title {
font-size: 2.7rem; font-size: 2.4rem;
} }
.hero-metrics { .hero-actions {
justify-content: center; justify-content: center;
} }
} }
@media (max-width: 768px) {
.hero-title {
font-size: 2.15rem;
}
.metric {
min-width: 110px;
}
}
</style> </style>

@ -20,7 +20,7 @@
<!-- GUÍA PARA POSTULANTES --> <!-- GUÍA PARA POSTULANTES -->
<div class="help-box" v-if="store.procesoPrincipal"> <div class="help-box" v-if="store.procesoPrincipal">
<div class="help-title">📌 Guía rápida (para no perderte)</div> <div class="help-title"> Guía rápida (para no perderte)</div>
<div class="help-grid"> <div class="help-grid">
<!-- Etapas activas --> <!-- Etapas activas -->
@ -100,7 +100,7 @@
<!-- Nota fija sobre inscripción presencial --> <!-- Nota fija sobre inscripción presencial -->
<div class="campus-note"> <div class="campus-note">
🏫 <b>Importante:</b> La <b>Inscripción</b> se realiza de forma <b>presencial</b> en el <b>Importante:</b> La <b>Inscripción</b> se realiza de forma <b>presencial</b> en el
<b>Campus Universitario</b>. Lleva tu DNI y los requisitos solicitados. <b>Campus Universitario</b>. Lleva tu DNI y los requisitos solicitados.
</div> </div>
</div> </div>
@ -336,30 +336,30 @@ const tareasHoy = computed(() => {
const tareas = [] const tareas = []
if (a.pre) { if (a.pre) {
tareas.push("Entra a la Preinscripción Virtual y completa tus datos sin apuro (verifica nombres y DNI).") tareas.push("Entra a la Preinscripción Virtual y completa tus datos sin apuro (verifica nombres y DNI).")
tareas.push("📌 Al terminar, guarda tu constancia o captura y revisa los Requisitos del proceso.") tareas.push("Al terminar, descarga e imprime tu solicitud de preinscripción y revisa los Requisitos del proceso.")
} }
if (a.ins) { if (a.ins) {
tareas.push("🏫 Acércate al Campus Universitario para la Inscripción Presencial.") tareas.push("Acércate al Campus Universitario para la Inscripción Presencial.")
tareas.push("🪪 Lleva tu DNI y los documentos/pagos solicitados por Admisión.") tareas.push("Lleva tu DNI y los documentos/pagos solicitados.")
} }
if (a.exa) { if (a.exa) {
tareas.push("📝 Hoy es el Examen: llega temprano, lleva tu DNI y sigue las indicaciones del reglamento.") tareas.push("Hoy es el Examen: llega temprano, lleva tu DNI, constancia de inscripción y sigue las indicaciones del reglamento.")
} }
if (a.res) { if (a.res) {
tareas.push("📣 Hoy salen Resultados: revisa el enlace oficial y guarda una captura/constancia.") tareas.push("Hoy salen Resultados.")
} }
if (a.bio) { if (a.bio) {
tareas.push("Si ingresaste: acércate al control biométrico dentro de las fechas indicadas.") tareas.push("Si ingresaste: acércate al control biométrico dentro de las fechas indicadas.")
} }
if (tareas.length === 0) { if (tareas.length === 0) {
tareas.push("📅 Revisa las fechas del proceso en los pasos de arriba.") tareas.push("Revisa las fechas del proceso en los pasos de arriba.")
tareas.push("Si aún no inicia: alístate con requisitos, documentos y pagos para no correr a última hora.") tareas.push("Si aún no inicia: alístate con requisitos, documentos y pagos para no correr a última hora.")
} }
return tareas return tareas

@ -3,7 +3,7 @@
<section class="stats-section" aria-labelledby="stats-title"> <section class="stats-section" aria-labelledby="stats-title">
<div class="section-container"> <div class="section-container">
<div class="section-header"> <div class="section-header">
<h2 id="stats-title" class="section-title">Cifras Clave</h2> <h2 id="stats-title" class="section-title">LA UNA PUNO EN CIFRAS</h2>
<p class="section-subtitle"> <p class="section-subtitle">
Indicadores institucionales que reflejan nuestro compromiso académico Indicadores institucionales que reflejan nuestro compromiso académico
</p> </p>
@ -11,31 +11,35 @@
<div class="stats-grid"> <div class="stats-grid">
<div class="stat-card"> <div class="stat-card">
<p class="stat-label">Fundada en</p>
<div class="stat-top"> <div class="stat-top">
<span class="stat-number">25+</span> <span class="stat-number">1856</span>
</div> </div>
<p class="stat-label">Carreras Profesionales</p>
</div> </div>
<div class="stat-card"> <div class="stat-card">
<p class="stat-label">Facultades</p>
<div class="stat-top"> <div class="stat-top">
<span class="stat-number">98%</span> <span class="stat-number">20</span>
</div> </div>
<p class="stat-label">Índice de Satisfacción</p>
</div> </div>
<div class="stat-card"> <div class="stat-card">
<p class="stat-label">Escuelas Profesionales</p>
<div class="stat-top"> <div class="stat-top">
<span class="stat-number">15,000+</span> <span class="stat-number">39</span>
</div> </div>
<p class="stat-label">Estudiantes Activos</p>
</div> </div>
<div class="stat-card"> <div class="stat-card">
<p class="stat-label">Estudiantes Matriculados</p>
<div class="stat-top"> <div class="stat-top">
<span class="stat-number">85%</span> <span class="stat-number">19,160</span>
</div> </div>
<p class="stat-label">Egresados Laborando</p>
</div> </div>
</div> </div>
</div> </div>
@ -43,7 +47,6 @@
</template> </template>
<style scoped> <style scoped>
.stats-section { .stats-section {
position: relative; position: relative;
padding: 70px 0; padding: 70px 0;
@ -53,7 +56,6 @@
overflow: hidden; overflow: hidden;
} }
.stats-section::before { .stats-section::before {
content: ""; content: "";
position: absolute; position: absolute;
@ -79,7 +81,6 @@
); );
} }
.stats-section::after { .stats-section::after {
content: ""; content: "";
position: absolute; position: absolute;
@ -121,20 +122,17 @@
line-height: 1.45; line-height: 1.45;
} }
.stats-grid { .stats-grid {
display: grid; display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr)); grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 18px; gap: 18px;
} }
.stat-card { .stat-card {
padding: 22px 18px; padding: 22px 18px;
border-radius: 16px; border-radius: 16px;
text-align: center; text-align: center;
background: rgba(255, 255, 255, 0.10); background: rgba(255, 255, 255, 0.10);
border: 1px solid rgba(255, 255, 255, 0.18); border: 1px solid rgba(255, 255, 255, 0.18);
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
@ -156,7 +154,6 @@
gap: 6px; gap: 6px;
} }
.stat-number { .stat-number {
font-size: 2.8rem; font-size: 2.8rem;
font-weight: 900; font-weight: 900;
@ -168,14 +165,12 @@
background-clip: text; background-clip: text;
} }
/* Texto */
.stat-label { .stat-label {
margin: 10px 0 0; margin: 10px 0 0;
font-size: 1.02rem; font-size: 1.02rem;
opacity: 0.92; opacity: 0.92;
} }
@media (max-width: 992px) { @media (max-width: 992px) {
.stats-grid { .stats-grid {
grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-columns: repeat(2, minmax(0, 1fr));

@ -8,7 +8,7 @@
<a-badge count="Modalidad" class="new-badge" /> <a-badge count="Modalidad" class="new-badge" />
</div> </div>
<p class="section-subtitle"> <p class="section-subtitle">
Examen de admisión del Centro Preuniversitario (Capítulo VI Sub-capítulo I) Examen de admisión del Centro Preuniversitario
</p> </p>
</div> </div>
@ -20,7 +20,7 @@
<h3>Examen de Admisión del Centro Preuniversitario</h3> <h3>Examen de Admisión del Centro Preuniversitario</h3>
<p class="convocatoria-date">Convocatoria: una vez por semestre</p> <p class="convocatoria-date">Convocatoria: una vez por semestre</p>
</div> </div>
<a-tag class="status-tag" color="success">CEPREUNA</a-tag> <!-- <a-tag class="status-tag" color="success">CEPREUNA</a-tag> -->
</div> </div>
<a-alert <a-alert
@ -40,19 +40,12 @@
</p> </p>
</a-card> </a-card>
<a-card class="soft-card" size="small">
<h4 class="subheading">Asignación de vacantes</h4>
<p class="text">
Las vacantes se cubren de acuerdo con el puntaje alcanzado, hasta completar el número ofertado
por los programas de estudio, según lo dispuesto por el reglamento.
</p>
</a-card>
<a-card class="soft-card" size="small"> <a-card class="soft-card" size="small">
<h4 class="subheading">Requisitos y documentos</h4> <h4 class="subheading">Requisitos y documentos</h4>
<a-list size="small" :split="false" class="info-list"> <a-list size="small" :split="false" class="info-list">
<a-list-item> <a-list-item>
Presentar la constancia de no adeudar al CEPREUNA con la debida anticipación. Presentar la constancia de no adeudar al CEPREUNA y DNI vigente.
</a-list-item> </a-list-item>
<a-list-item> <a-list-item>
Presentar los documentos exigidos por el reglamento para esta modalidad (según requisitos generales). Presentar los documentos exigidos por el reglamento para esta modalidad (según requisitos generales).

@ -8,7 +8,7 @@
<a-badge count="Modalidades" class="new-badge" /> <a-badge count="Modalidades" class="new-badge" />
</div> </div>
<p class="section-subtitle"> <p class="section-subtitle">
Examen convocado una vez al año con varias formas de postulación (Capítulo VI Sub-capítulo II) Examen convocado una vez al año con varias formas de postulación
</p> </p>
</div> </div>
@ -20,7 +20,7 @@
<h3>Examen de Admisión Extraordinario</h3> <h3>Examen de Admisión Extraordinario</h3>
<p class="convocatoria-date">Convocatoria: una vez al año</p> <p class="convocatoria-date">Convocatoria: una vez al año</p>
</div> </div>
<a-tag class="status-tag" color="orange">Extraordinario</a-tag> <!-- <a-tag class="status-tag" color="orange">Extraordinario</a-tag> -->
</div> </div>
<a-card class="soft-card" size="small"> <a-card class="soft-card" size="small">
@ -31,13 +31,6 @@
</p> </p>
</a-card> </a-card>
<a-card class="soft-card" size="small">
<h4 class="subheading">Asignación de vacantes</h4>
<p class="text">
Las vacantes se cubren de acuerdo con el puntaje alcanzado hasta completar el número ofertado por los
programas de estudio, conforme a lo establecido en el reglamento.
</p>
</a-card>
<a-divider class="custom-divider" /> <a-divider class="custom-divider" />

@ -20,8 +20,8 @@
<h3>Examen de Admisión General</h3> <h3>Examen de Admisión General</h3>
<p class="convocatoria-date">Convocatoria: una vez por semestre</p> <p class="convocatoria-date">Convocatoria: una vez por semestre</p>
</div> </div>
<!--
<a-tag class="status-tag" color="blue">General</a-tag> <a-tag class="status-tag" color="blue">General</a-tag> -->
</div> </div>
<a-alert <a-alert
@ -69,7 +69,7 @@
<script setup> <script setup>
import NavbarModerno from '../../nabvar.vue' import NavbarModerno from '../../nabvar.vue'
import FooterModerno from '../../Footer.vue' import FooterModerno from '../../Footer.vue'
import Nabvar from '../../nabvar.vue';
</script> </script>

@ -2,6 +2,7 @@
import { createRouter, createWebHistory } from 'vue-router' import { createRouter, createWebHistory } from 'vue-router'
import Login from '../views/Login.vue' import Login from '../views/Login.vue'
import WebPage from '../components/WebPage.vue' import WebPage from '../components/WebPage.vue'
import NotFound from '../views/NotFound.vue'
import { useUserStore } from '../store/user' import { useUserStore } from '../store/user'
import { useAuthStore as usePostulanteStore } from '../store/postulanteStore' import { useAuthStore as usePostulanteStore } from '../store/postulanteStore'
@ -18,6 +19,12 @@ const routes = [
meta: { guest: true }, meta: { guest: true },
}, },
{
path: '/:pathMatch(.*)*',
name: 'NotFound',
component: NotFound
},
{ {
path: '/resultados', path: '/resultados',
name: 'Resultados', name: 'Resultados',

@ -0,0 +1,124 @@
<template>
<section class="modalidades-section">
<div class="section-container">
<div class="section-header">
<h1 class="section-title">404</h1>
<p class="section-subtitle">
La página que estás buscando no existe o fue movida.
</p>
</div>
<div class="modalidades-grid">
<a-card class="modalidad-card">
<div class="modalidad-icon bg-error">
<WarningOutlined />
</div>
<h4>Enlace incorrecto</h4>
<p>
Verifica que la dirección esté escrita correctamente
o regresa al inicio.
</p>
<a-button type="primary" @click="$router.push('/')">
Volver al Inicio
</a-button>
</a-card>
</div>
</div>
</section>
</template>
<script setup>
import { WarningOutlined } from "@ant-design/icons-vue"
</script>
<style scoped>
.modalidades-section {
padding: 100px 0;
background: #f8f9fa;
min-height: 100vh;
display: flex;
align-items: center;
}
.section-container {
max-width: 900px;
margin: 0 auto;
padding: 0 24px;
width: 100%;
}
.section-header {
text-align: center;
margin-bottom: 50px;
}
.section-title {
font-size: 5rem;
font-weight: 700;
color: #1a237e;
margin-bottom: 10px;
}
.section-subtitle {
font-size: 1.125rem;
color: #666;
}
.modalidades-grid {
display: flex;
justify-content: center;
}
.modalidad-card {
border: none;
border-radius: 12px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
text-align: center;
padding: 40px 32px;
transition: transform 0.3s ease;
max-width: 420px;
width: 100%;
}
.modalidad-card:hover {
transform: translateY(-4px);
}
.modalidad-icon {
width: 72px;
height: 72px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 24px;
color: white;
font-size: 32px;
}
.bg-error {
background: #ef4444;
}
.modalidad-card h4 {
margin: 0 0 12px;
color: #1a237e;
}
.modalidad-card p {
color: #666;
font-size: 0.95rem;
line-height: 1.6;
margin-bottom: 20px;
}
@media (max-width: 992px) {
.section-title {
font-size: 3rem;
}
}
</style>

@ -138,60 +138,69 @@
</div> </div>
</a-col> </a-col>
<!-- PANEL DERECHO: INFO (CORTO Y DINÁMICO) --> <!-- PANEL DERECHO: INFO (CORTO Y DINÁMICO) -->
<a-col :xs="24" :md="12" class="auth-pane auth-pane-info"> <a-col :xs="24" :md="12" class="auth-pane auth-pane-info">
<div class="pane-inner pane-inner-info"> <div class="pane-inner pane-inner-info">
<div class="info-top"> <div class="info-top">
<a-tag class="info-tag">Universidad Nacional del Altiplano Puno</a-tag> <a-tag class="info-tag">Universidad Nacional del Altiplano Puno</a-tag>
<a-typography-title :level="3" style="margin: 8px 0 0"> <a-typography-title :level="3" style="margin: 8px 0 0">
{{ isRegister ? "Registro de Postulante" : "Portal del Postulante" }} {{ isRegister ? "Registro de Postulante" : "Portal del Postulante" }}
</a-typography-title> </a-typography-title>
<a-typography-text type="secondary">
{{
isRegister
? "Crea tu cuenta para participar en el proceso de admisión y acceder a todos los servicios del portal."
: "Ingresa al portal para gestionar tu inscripción, revisar procesos disponibles y rendir un test de referencia."
}}
</a-typography-text>
</div>
<a-typography-text type="secondary"> <div class="info-section">
{{ <div class="info-section-title">
isRegister {{ isRegister ? "Al registrarte podrás" : "Al ingresar podrás" }}
? "Crea tu cuenta para iniciar tu inscripción al proceso de admisión." </div>
: "Inicia sesión para continuar tu inscripción y consultar tu estado."
}}
</a-typography-text>
</div>
<div class="info-section"> <div class="info-list">
<div class="info-section-title">
{{ isRegister ? "Al registrarte podrás" : "Al ingresar podrás" }}
</div>
<div class="info-list"> <div class="info-item">
<div class="info-item"> <span class="info-bullet"></span>
<span class="info-bullet"></span> <span><b>Rendir un test de referencia</b>.</span>
<span><b>Completar tu postulación</b> (modalidad, sede y programa).</span> </div>
</div> <div class="info-item">
<span class="info-bullet"></span>
<span><b>Ver procesos disponibles</b> según tu modalidad.</span>
</div>
<div class="info-item">
<span class="info-bullet"></span>
<span><b>Subir requisitos</b> y revisar observaciones.</span>
</div>
<div class="info-item" v-if="!isRegister">
<span class="info-bullet"></span> <div class="info-item">
<span><b>Ver comunicados y resultados</b> del proceso.</span> <span class="info-bullet"></span>
<span><b>Consultar tu estado</b> de inscripción y seguimiento del proceso.</span>
</div>
<!-- <div class="info-item">
<span class="info-bullet"></span>
<span><b>Ver tu resultado detallado</b> por cursos.</span>
</div> -->
<div class="info-item">
<span class="info-bullet"></span>
<span><b>Revisar comunicados oficiales</b> del proceso de admisión.</span>
</div>
</div>
</div> </div>
<div class="info-item"> <div class="info-foot">
<span class="info-bullet"></span> <a-typography-text type="secondary">
<span><b>Consultar tu estado</b> de inscripción/admisión.</span> Plataforma oficial de admisión Soporte en horario institucional
</a-typography-text>
</div> </div>
</div> </div>
</div> </a-col>
<div class="info-foot">
<a-typography-text type="secondary">
Soporte: Mesa de ayuda Atención en horario institucional
</a-typography-text>
</div>
</div>
</a-col>
</a-row> </a-row>
</div> </div>
</a-col> </a-col>

@ -1,14 +1,20 @@
<template> <template>
<div class="title">Mis procesos de admisión</div>
<a-card class="card" :bordered="true"> <a-card class="card" :bordered="true">
<template #title> <template #title>
<div class="header"> <div class="header">
<div class="headerLeft"> <div class="headerLeft">
<div class="title">Mis procesos de admisión</div>
<div class="subtitle">Resultados registrados por DNI</div> <div class="subtitle">Resultados registrados por DNI</div>
</div> </div>
<div class="headerRight"> <div class="headerRight">
<a-button @click="obtenerProcesos" :loading="loading" class="btn" block> <a-button
@click="obtenerProcesos"
:loading="loading"
class="btn"
type="primary"
>
Actualizar Actualizar
</a-button> </a-button>
</div> </div>
@ -16,7 +22,8 @@
</template> </template>
<a-spin :spinning="loading"> <a-spin :spinning="loading">
<!-- Top tools -->
<!-- Tools -->
<div class="tools"> <div class="tools">
<div class="counter"> <div class="counter">
<span class="counterLabel">Total</span> <span class="counterLabel">Total</span>
@ -31,10 +38,9 @@
/> />
</div> </div>
<!-- Desktop/tablet: tabla --> <!-- ================= DESKTOP / TABLE ================= -->
<div v-if="!isMobile" class="tableWrap"> <div class="tableWrap desktopOnly">
<a-table <a-table
class="table"
:dataSource="procesosFiltrados" :dataSource="procesosFiltrados"
:columns="columns" :columns="columns"
rowKey="id" rowKey="id"
@ -42,6 +48,7 @@
:scroll="{ x: 900 }" :scroll="{ x: 900 }"
> >
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.key === 'nombre'"> <template v-if="column.key === 'nombre'">
<div class="nombre">{{ record.nombre || "-" }}</div> <div class="nombre">{{ record.nombre || "-" }}</div>
<div class="meta">ID: {{ record.id }}</div> <div class="meta">ID: {{ record.id }}</div>
@ -59,10 +66,11 @@
</template> </template>
<template v-else-if="column.key === 'acciones'"> <template v-else-if="column.key === 'acciones'">
<a-space> <a-button size="small" @click="verDetalle(record)">
<a-button size="small" @click="verDetalle(record)">Ver detalle</a-button> Ver detalle
</a-space> </a-button>
</template> </template>
</template> </template>
<template #emptyText> <template #emptyText>
@ -71,10 +79,14 @@
</a-table> </a-table>
</div> </div>
<!-- Mobile: cards --> <!-- ================= MOBILE / CARDS ================= -->
<div v-else class="cards"> <div class="cards mobileOnly">
<template v-if="procesosFiltrados.length"> <template v-if="procesosFiltrados.length">
<div v-for="p in procesosFiltrados" :key="p.id" class="itemCard"> <div
v-for="p in procesosFiltrados"
:key="p.id"
class="itemCard"
>
<div class="itemTop"> <div class="itemTop">
<div class="itemTitle">{{ p.nombre || "-" }}</div> <div class="itemTitle">{{ p.nombre || "-" }}</div>
<span class="statusPill" :class="statusClass(p.apto)"> <span class="statusPill" :class="statusClass(p.apto)">
@ -87,6 +99,7 @@
<div class="k">Puntaje</div> <div class="k">Puntaje</div>
<div class="v strong">{{ p.puntaje ?? "-" }}</div> <div class="v strong">{{ p.puntaje ?? "-" }}</div>
</div> </div>
<div class="kv"> <div class="kv">
<div class="k">ID</div> <div class="k">ID</div>
<div class="v">{{ p.id }}</div> <div class="v">{{ p.id }}</div>
@ -94,7 +107,12 @@
</div> </div>
<div class="itemActions"> <div class="itemActions">
<a-button type="primary" class="btnPrimary" block @click="verDetalle(p)"> <a-button
type="primary"
block
class="btnPrimary"
@click="verDetalle(p)"
>
Ver detalle Ver detalle
</a-button> </a-button>
</div> </div>
@ -103,12 +121,13 @@
<a-empty v-else description="No se encontraron procesos" /> <a-empty v-else description="No se encontraron procesos" />
</div> </div>
</a-spin> </a-spin>
</a-card> </a-card>
</template> </template>
<script setup> <script setup>
import { ref, computed, onMounted, onBeforeUnmount } from "vue"; import { ref, computed, onMounted } from "vue";
import { message } from "ant-design-vue"; import { message } from "ant-design-vue";
import api from "../../axiosPostulante"; import api from "../../axiosPostulante";
@ -133,7 +152,6 @@ const obtenerProcesos = async () => {
message.error("No se pudieron obtener los procesos"); message.error("No se pudieron obtener los procesos");
} }
} catch (e) { } catch (e) {
console.error(e);
message.error(e.response?.data?.message || "Error al cargar procesos"); message.error(e.response?.data?.message || "Error al cargar procesos");
} finally { } finally {
loading.value = false; loading.value = false;
@ -141,58 +159,39 @@ const obtenerProcesos = async () => {
}; };
const aptoTexto = (apto) => { const aptoTexto = (apto) => {
if (apto === 1 || apto === true || apto === "1") return "APTO"; if (apto == 1) return "APTO";
if (apto === 0 || apto === false || apto === "0") return "NO APTO"; if (apto == 0) return "NO APTO";
return String(apto ?? "-").toUpperCase(); return "-";
}; };
/** ✅ Un solo color: no usamos verde/rojo; solo estilos neutros + primary sutil */
const statusClass = (apto) => { const statusClass = (apto) => {
if (apto === 1 || apto === true || apto === "1") return "ok"; if (apto == 1) return "ok";
if (apto === 0 || apto === false || apto === "0") return "bad"; if (apto == 0) return "bad";
return "neutral"; return "neutral";
}; };
const procesosFiltrados = computed(() => { const procesosFiltrados = computed(() => {
const q = search.value.trim().toLowerCase(); const q = search.value.trim().toLowerCase();
if (!q) return procesos.value; if (!q) return procesos.value;
return procesos.value.filter((p) => String(p.nombre || "").toLowerCase().includes(q)); return procesos.value.filter((p) =>
String(p.nombre || "").toLowerCase().includes(q)
);
}); });
const verDetalle = (record) => { const verDetalle = (record) => {
message.info(`Proceso: ${record.nombre} | Puntaje: ${record.puntaje ?? "-"}`); message.info(`Proceso: ${record.nombre} | Puntaje: ${record.puntaje ?? "-"}`);
}; };
/* ✅ Responsive real: detecta móvil para cambiar a cards */
const isMobile = ref(false);
let mq = null;
function setMobile() {
isMobile.value = window.matchMedia("(max-width: 640px)").matches;
}
onMounted(() => { onMounted(() => {
obtenerProcesos(); obtenerProcesos();
mq = window.matchMedia("(max-width: 640px)");
setMobile();
// addEventListener es lo moderno; fallback por compatibilidad
if (mq.addEventListener) mq.addEventListener("change", setMobile);
else mq.addListener(setMobile);
});
onBeforeUnmount(() => {
if (!mq) return;
if (mq.removeEventListener) mq.removeEventListener("change", setMobile);
else mq.removeListener(setMobile);
}); });
</script> </script>
<style scoped> <style scoped>
/* =========================
Base (formal 17+, sin degradados) /* Card */
1 color acento: primary
========================= */
.card { .card {
width: 100%;
max-width: 1100px; max-width: 1100px;
margin: 16px auto; margin: 16px auto;
border-radius: 14px; border-radius: 14px;
@ -202,32 +201,22 @@ onBeforeUnmount(() => {
.header { .header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: flex-start; gap: 16px;
gap: 12px;
flex-wrap: wrap; flex-wrap: wrap;
} }
.headerLeft {
min-width: 240px;
}
.title { .title {
margin: 0; font-size: clamp(1.2rem, 4vw, 1.8rem);
font-size: 1.85rem;
font-weight: 700; font-weight: 700;
color: #0d1b52; color: #0d1b52;
line-height: 1.15; line-height: 1.2;
word-break: break-word;
} }
.subtitle { .subtitle {
margin-top: 4px;
font-size: 12px; font-size: 12px;
color: var(--ant-colorTextSecondary, #6b7280); color: #6b7280;
} margin-top: 4px;
.headerRight {
min-width: 180px;
display: flex;
justify-content: flex-end;
}
.btn {
border-radius: 10px;
} }
/* Tools */ /* Tools */
@ -235,88 +224,71 @@ onBeforeUnmount(() => {
display: grid; display: grid;
grid-template-columns: 220px 1fr; grid-template-columns: 220px 1fr;
gap: 12px; gap: 12px;
align-items: center;
margin-bottom: 12px; margin-bottom: 12px;
} }
.counter { .counter {
border: 1px solid var(--ant-colorBorderSecondary, rgba(0,0,0,.08)); background: #fafafa;
background: var(--ant-colorFillAlter, #fafafa);
border-radius: 12px; border-radius: 12px;
padding: 10px 12px; padding: 10px 12px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: baseline;
}
.counterLabel {
font-size: 12px;
color: var(--ant-colorTextSecondary, #6b7280);
font-weight: 700; font-weight: 700;
} }
.counterValue { .counterValue {
font-size: 18px; font-size: 18px;
font-weight: 900;
color: var(--ant-colorTextHeading, #111827);
} }
.search { .search {
border-radius: 12px; border-radius: 12px;
} }
/* Table */ /* Table */
.tableWrap { .tableWrap {
border-radius: 12px; width: 100%;
overflow: hidden; overflow-x: auto;
}
.table :deep(.ant-table) {
border-radius: 12px;
overflow: hidden;
} }
.nombre { .nombre {
font-weight: 800; font-weight: 800;
color: var(--ant-colorTextHeading, #111827);
} }
.puntaje { .puntaje {
font-weight: 900; font-weight: 900;
color: var(--ant-colorPrimary, #1677ff); /* ✅ único acento */ color: #1677ff;
} }
.meta { .meta {
font-size: 12px; font-size: 12px;
color: var(--ant-colorTextSecondary, #6b7280); color: #6b7280;
margin-top: 2px;
} }
/* Status pill (sin verde/rojo) */ /* Status */
.statusPill { .statusPill {
display: inline-flex; padding: 4px 10px;
align-items: center;
padding: 3px 10px;
border-radius: 999px; border-radius: 999px;
font-weight: 900;
font-size: 12px; font-size: 12px;
border: 1px solid var(--ant-colorBorderSecondary, rgba(0,0,0,.08)); font-weight: 900;
background: var(--ant-colorFillAlter, #fafafa); background: #f5f5f5;
color: var(--ant-colorTextHeading, #111827);
} }
.statusPill.ok { .statusPill.ok {
border-color: rgba(22,119,255,.35); background: rgba(22,119,255,.1);
background: rgba(22,119,255,.08); border: 1px solid rgba(22,119,255,.3);
} }
.statusPill.bad { .statusPill.bad {
border-color: rgba(0,0,0,.10);
background: rgba(0,0,0,.04); background: rgba(0,0,0,.04);
} }
.statusPill.neutral {
opacity: .85;
}
/* Mobile cards */
.cards { .cards {
display: grid; display: grid;
gap: 12px; gap: 12px;
} }
.itemCard { .itemCard {
border: 1px solid var(--ant-colorBorderSecondary, rgba(0,0,0,.08)); border: 1px solid rgba(0,0,0,.08);
background: var(--ant-colorBgContainer, #fff);
border-radius: 14px; border-radius: 14px;
padding: 12px; padding: 12px;
} }
@ -324,68 +296,68 @@ onBeforeUnmount(() => {
.itemTop { .itemTop {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
gap: 10px;
align-items: flex-start;
flex-wrap: wrap; flex-wrap: wrap;
} }
.itemTitle { .itemTitle {
font-weight: 900; font-weight: 900;
color: var(--ant-colorTextHeading, #111827);
line-height: 1.2;
} }
.itemGrid { .itemGrid {
margin-top: 10px;
display: grid; display: grid;
grid-template-columns: 1fr 1fr; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 10px; gap: 10px;
margin-top: 10px;
} }
.kv { .kv {
border: 1px solid var(--ant-colorBorderSecondary, rgba(0,0,0,.06)); background: #fafafa;
background: var(--ant-colorFillAlter, #fafafa);
border-radius: 12px; border-radius: 12px;
padding: 10px 12px; padding: 10px;
} }
.k { .k {
font-size: 12px; font-size: 12px;
color: var(--ant-colorTextSecondary, #6b7280); color: #6b7280;
font-weight: 700;
} }
.v { .v {
margin-top: 4px;
font-weight: 900; font-weight: 900;
color: var(--ant-colorTextHeading, #111827);
} }
.v.strong { .v.strong {
color: var(--ant-colorPrimary, #1677ff); color: #1677ff;
} }
.itemActions {
margin-top: 12px;
}
.btnPrimary { .btnPrimary {
height: 42px; height: 42px;
border-radius: 12px; border-radius: 12px;
font-weight: 900; font-weight: 900;
margin-top: 12px;
} }
/* Responsive tools */ /* Responsive */
@media (max-width: 640px) { .desktopOnly { display: block; }
.card { .mobileOnly { display: none; }
margin: 0;
border-radius: 0; @media (max-width: 768px) {
}
.headerRight {
width: 100%;
min-width: 0;
}
.tools { .tools {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
.itemGrid {
grid-template-columns: 1fr; .desktopOnly { display: none; }
.mobileOnly { display: block; }
.header {
flex-direction: column;
}
.title {
font-size: 1.3rem;
}
.card {
margin: 0;
border-radius: 0;
} }
} }
</style> </style>

@ -1,9 +1,10 @@
<template> <template>
<div class="title">Mis pagos realizados</div>
<a-card class="card" :bordered="true"> <a-card class="card" :bordered="true">
<template #title> <template #title>
<div class="header"> <div class="header">
<div class="headerLeft"> <div class="headerLeft">
<div class="title">Mis pagos realizados</div>
<div class="subtitle">Historial de pagos registrados en el sistema</div> <div class="subtitle">Historial de pagos registrados en el sistema</div>
</div> </div>
@ -253,11 +254,11 @@ onBeforeUnmount(() => {
min-width: 240px; min-width: 240px;
} }
.title { .title {
margin: 0; font-size: clamp(1.2rem, 4vw, 1.8rem);
font-size: 1.85rem;
font-weight: 700; font-weight: 700;
color: #0d1b52; color: #0d1b52;
line-height: 1.15; line-height: 1.2;
word-break: break-word;
} }
.subtitle { .subtitle {
margin-top: 4px; margin-top: 4px;
@ -466,6 +467,9 @@ onBeforeUnmount(() => {
width: 100%; width: 100%;
min-width: 0; min-width: 0;
} }
.title {
font-size: 1.3rem;
}
.tools { .tools {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }

@ -273,7 +273,7 @@ const handleLogout = async () => {
try { try {
await authStore.logout() await authStore.logout()
message.success('Sesión cerrada correctamente') message.success('Sesión cerrada correctamente')
router.push('/login-postulante') router.push('/')
} catch (error) { } catch (error) {
message.error('Error al cerrar sesión') message.error('Error al cerrar sesión')
} }
@ -298,6 +298,7 @@ onUnmounted(() => {
}) })
</script> </script>
<style scoped> <style scoped>

@ -5,7 +5,7 @@
<div class="head"> <div class="head">
<div> <div>
<div class="hTitle">Resultados del examen</div> <div class="hTitle">Resultados del examen</div>
<div class="hSub">Resumen claro + detalle por curso. Todo responsivo.</div> <div class="hSub">Resumen claro + detalle por curso.</div>
</div> </div>
<!-- (opcional) acciones --> <!-- (opcional) acciones -->
@ -33,7 +33,7 @@
</div> </div>
<div v-if="resultado.orden_merito != null" class="chipRank"> <div v-if="resultado.orden_merito != null" class="chipRank">
Orden: <b>#{{ resultado.orden_merito }}</b> Puesto: <b>#{{ resultado.orden_merito }}</b>
</div> </div>
</div> </div>
@ -43,8 +43,8 @@
<div class="bigProgress"> <div class="bigProgress">
<a-progress :percent="notaPercent" /> <a-progress :percent="notaPercent" />
<div class="bigProgressMeta"> <div class="bigProgressMeta">
<span>Nota equivalente</span> <!-- <span>Nota equivalente</span>
<b>{{ fmt2(resultado.calificacion_sobre_20) }}/20</b> <b>{{ fmt2(resultado.calificacion_sobre_20) }}/20</b> -->
</div> </div>
</div> </div>
@ -135,7 +135,7 @@
<span class="courseDot"></span> <span class="courseDot"></span>
<div> <div>
<div class="courseName">{{ record.curso }}</div> <div class="courseName">{{ record.curso }}</div>
<div class="courseMeta">Ratio: {{ record.ratio }}%</div> <div class="courseMeta">{{ record.ratio }}%</div>
</div> </div>
</div> </div>
</template> </template>

@ -3,6 +3,9 @@ import { ref, computed, reactive, onMounted, watch } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { useExamenStore } from "../../store/examen.store"; import { useExamenStore } from "../../store/examen.store";
import { message } from "ant-design-vue"; import { message } from "ant-design-vue";
import voucherCaja from "../../assets/images/caja.png";
import voucherPagalo from "../../assets/images/pagalo.png";
import voucherBn from "../../assets/images/boletabn.jpg";
const router = useRouter(); const router = useRouter();
const examenStore = useExamenStore(); const examenStore = useExamenStore();
@ -50,11 +53,12 @@ const secuenciaTitle = computed(() => {
const voucherSrc = computed(() => { const voucherSrc = computed(() => {
const map = { const map = {
caja: "/voucher-caja.png", caja: voucherCaja,
pagalo: "/voucher-pagalo.png", pagalo: voucherPagalo,
bn: "/voucher-bn.png", bn: voucherBn,
}; };
return map[secuenciaTipo.value] || "/voucher-bn.png";
return map[secuenciaTipo.value] || "";
}); });
const habilitacionTexto = computed(() => const habilitacionTexto = computed(() =>
@ -155,27 +159,7 @@ const procesoRequierePago = computed(() => {
return normalizeRequierePago(proceso.requiere_pago); return normalizeRequierePago(proceso.requiere_pago);
}); });
/** Si ya tienes examen asignado */
const examenRequierePago = computed(() => {
const v = examenStore.examenActual?.proceso?.requiere_pago;
return normalizeRequierePago(v);
});
/** ✅ Solo para mostrar un texto informativo */
const requierePagoInfo = computed(() => procesoRequierePago.value || examenRequierePago.value);
/** ✅ Contexto para jóvenes (texto claro y tranquilizador) */
const textoReferencial = computed(() => ({
message: "✅ Test referencial (no afecta tu postulación)",
description:
"Este test solo te ayuda a medir tu nivel y practicar. No cambia tu puntaje ni tu postulación oficial.",
}));
const textoCarpeta = computed(() => ({
message: "💳 Secuencia: también sirve la de tu Carpeta de Postulante",
description:
"Si tu proceso pide secuencia, puedes usar la misma del pago de la Carpeta de Postulante. No pagas nada extra por este test.",
}));
/** Validación (condicional) */ /** Validación (condicional) */
const rules = { const rules = {
@ -362,6 +346,7 @@ onMounted(async () => {
<div class="muted"> <div class="muted">
Este test te ayuda a medir tu nivel y practicar. No cambia tu puntaje ni tu postulación oficial. Este test te ayuda a medir tu nivel y practicar. No cambia tu puntaje ni tu postulación oficial.
</div> </div>
</div> </div>
</a-space> </a-space>
</a-card> </a-card>
@ -370,15 +355,15 @@ onMounted(async () => {
<div class="heroFacts hide-mobile"> <div class="heroFacts hide-mobile">
<div class="fact"> <div class="fact">
<div class="factK">Proceso</div> <div class="factK">Nombre:</div>
<div class="factV">{{ procesoNombre }}</div> <div class="factV">{{ procesoNombre }}</div>
</div> </div>
<div class="fact"> <div class="fact">
<div class="factK">Área</div> <div class="factK">Área:</div>
<div class="factV">{{ areaNombre }}</div> <div class="factV">{{ areaNombre }}</div>
</div> </div>
<div class="fact"> <div class="fact">
<div class="factK">Intentos</div> <div class="factK">Intentos:</div>
<div class="factV">{{ intentosActuales }} / {{ intentosMax }}</div> <div class="factV">{{ intentosActuales }} / {{ intentosMax }}</div>
</div> </div>
</div> </div>
@ -386,12 +371,15 @@ onMounted(async () => {
<!-- BOTONES DE BANCO --> <!-- BOTONES DE BANCO -->
<div class="bankActions"> <div class="bankActions">
<div class="bankHead"> <div class="bankHead">
<div class="bankTitle">Ver ejemplos de Secuencia</div> <div class="bankTitle">Requisito de acceso</div>
<div class="bankSub"> <div class="bankSub">
Te sirve si el proceso te pide secuencia (puede ser la de la Carpeta de Postulante). Este test es completamente GRATUITO.
No se realiza ningún pago adicional.
Únicamente debes ingresar el número de secuencia del pago de tu Carpeta de Postulante, el cual ya realizaste previamente para el proceso de admisión.
</div> </div>
</div> </div>
<div style="font-weight: 700; color:#1a237e;">Ver Secuencia</div>
<a-space wrap> <a-space wrap>
<a-button class="bankBtn" @click="openSecuencia('caja')">Caja</a-button> <a-button class="bankBtn" @click="openSecuencia('caja')">Caja</a-button>
<a-button class="bankBtn" @click="openSecuencia('pagalo')">pagalo.pe</a-button> <a-button class="bankBtn" @click="openSecuencia('pagalo')">pagalo.pe</a-button>

Loading…
Cancel
Save