main
elmer-20 2 months ago
parent a694d2f958
commit 46545d44a8

@ -1,12 +1,13 @@
<?php <?php
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Models\ProcesoAdmision; use App\Models\ProcesoAdmision;
use App\Models\ProcesoAdmisionDetalle; use Illuminate\Support\Carbon;
use Illuminate\Http\Request;
class WebController extends Controller class WebController extends Controller
{ {
public function GetProcesoAdmision() public function GetProcesoAdmision()
{ {
$procesos = ProcesoAdmision::select( $procesos = ProcesoAdmision::select(
@ -57,7 +58,7 @@ public function GetProcesoAdmision()
); );
} }
]) ])
->latest() // 🔥 Esto ordena por created_at DESC ->latest()
->get(); ->get();
return response()->json([ return response()->json([
@ -67,4 +68,33 @@ public function GetProcesoAdmision()
} }
public function obtenerProcesosDisponiblesPreinscripcion(Request $request)
{
$now = Carbon::now();
$postulante = $request->user();
$procesos = ProcesoAdmision::query()
->select([
'id',
'titulo',
'slug',
'link_preinscripcion',
'fecha_inicio_preinscripcion',
'fecha_fin_preinscripcion',
])
->where('publicado', 1)
->whereIn('estado', ['publicado', 'en_proceso'])
->whereNotNull('link_preinscripcion')
->whereNotNull('fecha_inicio_preinscripcion')
->whereNotNull('fecha_fin_preinscripcion')
->where('fecha_inicio_preinscripcion', '<=', $now)
->where('fecha_fin_preinscripcion', '>=', $now)
->orderByDesc('fecha_inicio_preinscripcion')
->orderBy('titulo')
->get();
return response()->json([
'success' => true,
'data' => $procesos
]);
}
} }

@ -52,12 +52,9 @@ Route::middleware(['auth:sanctum'])->prefix('admin')->group(function () {
Route::put('/areas/{id}', [AreaController::class, 'update']); Route::put('/areas/{id}', [AreaController::class, 'update']);
Route::delete('/areas/{id}', [AreaController::class, 'destroy']); Route::delete('/areas/{id}', [AreaController::class, 'destroy']);
Route::patch('/areas/{id}/toggle', [AreaController::class, 'toggleEstado']); Route::patch('/areas/{id}/toggle', [AreaController::class, 'toggleEstado']);
Route::post('/areas/{area}/vincular-cursos', [AreaController::class, 'vincularCursosArea']); Route::post('/areas/{area}/vincular-cursos', [AreaController::class, 'vincularCursosArea']);
Route::post('/areas/{area}/desvincular-curso', [AreaController::class, 'desvincularCursoArea']); Route::post('/areas/{area}/desvincular-curso', [AreaController::class, 'desvincularCursoArea']);
Route::get('/areas/{area}/cursos-disponibles', [AreaController::class, 'getCursosPorArea']); Route::get('/areas/{area}/cursos-disponibles', [AreaController::class, 'getCursosPorArea']);
Route::post('areas/{area}/vincular-procesos', [AreaController::class, 'vincularProcesosArea']); Route::post('areas/{area}/vincular-procesos', [AreaController::class, 'vincularProcesosArea']);
Route::get('areas/{area}/procesos-disponibles', [AreaController::class, 'getProcesosPorArea'] ); Route::get('areas/{area}/procesos-disponibles', [AreaController::class, 'getProcesosPorArea'] );
Route::post('areas/{area}/desvincular-procesos', [AreaController::class, 'desvincularProcesoArea'] ); Route::post('areas/{area}/desvincular-procesos', [AreaController::class, 'desvincularProcesoArea'] );
@ -67,19 +64,14 @@ Route::middleware(['auth:sanctum'])->prefix('admin')->group(function () {
Route::middleware(['auth:sanctum'])->prefix('admin')->group(function () { Route::middleware(['auth:sanctum'])->prefix('admin')->group(function () {
// NOTICIAS
Route::get('/noticias', [NoticiaController::class, 'index']); Route::get('/noticias', [NoticiaController::class, 'index']);
Route::get('/noticias/{noticia}', [NoticiaController::class, 'show']); Route::get('/noticias/{noticia}', [NoticiaController::class, 'show']);
Route::post('/noticias', [NoticiaController::class, 'store']); Route::post('/noticias', [NoticiaController::class, 'store']);
// usa SOLO UNA (PUT o PATCH). Aquí dejo PUT:
Route::put('/noticias/{noticia}', [NoticiaController::class, 'update']); Route::put('/noticias/{noticia}', [NoticiaController::class, 'update']);
Route::delete('/noticias/{noticia}', [NoticiaController::class, 'destroy']); Route::delete('/noticias/{noticia}', [NoticiaController::class, 'destroy']);
}); });
Route::get('/noticias', [NoticiaController::class, 'index']);
Route::get('/noticias/{noticia:slug}', [NoticiaController::class, 'showPublic']);
Route::middleware(['auth:sanctum'])->prefix('admin')->group(function () { Route::middleware(['auth:sanctum'])->prefix('admin')->group(function () {
@ -99,8 +91,6 @@ Route::middleware(['auth:sanctum'])->prefix('admin')->group(function () {
}); });
Route::middleware(['auth:sanctum'])->prefix('admin')->group(function () { Route::middleware(['auth:sanctum'])->prefix('admin')->group(function () {
Route::get('cursos/{cursoId}/preguntas', [PreguntaController::class, 'getPreguntasCurso']); Route::get('cursos/{cursoId}/preguntas', [PreguntaController::class, 'getPreguntasCurso']);
@ -113,7 +103,6 @@ Route::middleware(['auth:sanctum'])->prefix('admin')->group(function () {
Route::middleware('auth:sanctum')->group(function () { Route::middleware('auth:sanctum')->group(function () {
Route::get('/calificaciones', [CalificacionController::class, 'index']); Route::get('/calificaciones', [CalificacionController::class, 'index']);
Route::post('/calificaciones', [CalificacionController::class, 'store']); Route::post('/calificaciones', [CalificacionController::class, 'store']);
Route::get('/calificaciones/{id}', [CalificacionController::class, 'show']); Route::get('/calificaciones/{id}', [CalificacionController::class, 'show']);
@ -122,17 +111,11 @@ Route::middleware('auth:sanctum')->group(function () {
}); });
Route::prefix('postulante')->group(function () { Route::prefix('postulante')->group(function () {
// Registro
Route::post('/register', [PostulanteAuthController::class, 'register']); Route::post('/register', [PostulanteAuthController::class, 'register']);
// Login
Route::post('/login', [PostulanteAuthController::class, 'login']); Route::post('/login', [PostulanteAuthController::class, 'login']);
// Rutas protegidas por token
Route::middleware('auth:sanctum')->group(function () { Route::middleware('auth:sanctum')->group(function () {
Route::post('/logout', [PostulanteAuthController::class, 'logout']); Route::post('/logout', [PostulanteAuthController::class, 'logout']);
Route::get('/me', [PostulanteAuthController::class, 'me']); Route::get('/me', [PostulanteAuthController::class, 'me']);
@ -142,10 +125,8 @@ Route::prefix('postulante')->group(function () {
}); });
}); });
// Route::middleware('auth:sanctum')->group(function () { // Route::middleware('auth:sanctum')->group(function () {
// Route::get('/procesos', [ExamenController::class, 'procesoexamen']); // Route::get('/procesos', [ExamenController::class, 'procesoexamen']);
// Route::get('/areas', [ExamenController::class, 'areas']); // Route::get('/areas', [ExamenController::class, 'areas']);
@ -157,51 +138,35 @@ Route::prefix('postulante')->group(function () {
Route::middleware(['auth:sanctum'])->prefix('area-proceso')->group(function () { Route::middleware(['auth:sanctum'])->prefix('area-proceso')->group(function () {
Route::get('areasprocesos', [ReglaAreaProcesoController::class, 'areasProcesos']); Route::get('areasprocesos', [ReglaAreaProcesoController::class, 'areasProcesos']);
Route::prefix('{areaProcesoId}/reglas')->group(function () { Route::prefix('{areaProcesoId}/reglas')->group(function () {
Route::get('/', [ReglaAreaProcesoController::class, 'index']); // Listar reglas Route::get('/', [ReglaAreaProcesoController::class, 'index']);
Route::post('/', [ReglaAreaProcesoController::class, 'store']); // Crear/actualizar regla individual Route::post('/', [ReglaAreaProcesoController::class, 'store']);
Route::post('/multiple', [ReglaAreaProcesoController::class, 'storeMultiple']); // Guardar múltiples reglas Route::post('/multiple', [ReglaAreaProcesoController::class, 'storeMultiple']);
}); });
}); });
Route::middleware(['auth:sanctum'])->prefix('reglas')->group(function () { Route::middleware(['auth:sanctum'])->prefix('reglas')->group(function () {
Route::put('/{reglaId}', [ReglaAreaProcesoController::class, 'update']); // Editar regla Route::put('/{reglaId}', [ReglaAreaProcesoController::class, 'update']);
Route::delete('/{reglaId}', [ReglaAreaProcesoController::class, 'destroy']); // Eliminar regla Route::delete('/{reglaId}', [ReglaAreaProcesoController::class, 'destroy']);
}); });
Route::middleware(['auth:sanctum'])->group(function () {
// Examen - Flujo separado
Route::middleware(['auth:postulante'])->group(function () {
Route::get('/examen/procesos', [ExamenController::class, 'procesoexamen']); Route::get('/examen/procesos', [ExamenController::class, 'procesoexamen']);
Route::get('/examen/areas', [ExamenController::class, 'areas']); Route::get('/examen/areas', [ExamenController::class, 'areas']);
Route::get('/examen/actual', [ExamenController::class, 'miExamenActual']); Route::get('/examen/actual', [ExamenController::class, 'miExamenActual']);
// Crear examen (sin preguntas)
Route::post('/examen/crear', [ExamenController::class, 'crearExamen']); Route::post('/examen/crear', [ExamenController::class, 'crearExamen']);
// Generar preguntas
Route::post('/examen/{examen}/generar-preguntas', [ExamenController::class, 'generarPreguntas']); Route::post('/examen/{examen}/generar-preguntas', [ExamenController::class, 'generarPreguntas']);
// Obtener preguntas
Route::get('/examen/{examen}/preguntas', [ExamenController::class, 'obtenerPreguntas']); Route::get('/examen/{examen}/preguntas', [ExamenController::class, 'obtenerPreguntas']);
// Iniciar examen (marcar hora inicio)
Route::post('/examen/iniciar', [ExamenController::class, 'iniciarExamen']); Route::post('/examen/iniciar', [ExamenController::class, 'iniciarExamen']);
// Responder preguntas
Route::post('/examen/pregunta/{pregunta}/responder', [ExamenController::class, 'responderPregunta']); Route::post('/examen/pregunta/{pregunta}/responder', [ExamenController::class, 'responderPregunta']);
// Finalizar examen
Route::post('/examen/{examen}/finalizar', [ExamenController::class, 'finalizarExamen']); Route::post('/examen/{examen}/finalizar', [ExamenController::class, 'finalizarExamen']);
Route::post('/examen/{examenId}/calificar', [ExamenController::class, 'calificarExamen']); Route::post('/examen/{examenId}/calificar', [ExamenController::class, 'calificarExamen']);
}); });
Route::middleware('auth:sanctum')->prefix('admin')->group(function () { Route::middleware('auth:sanctum')->prefix('admin')->group(function () {
// PROCESOS
Route::prefix('procesos-admision')->group(function () { Route::prefix('procesos-admision')->group(function () {
Route::get('/', [ProcesoAdmisionController::class, 'index'])->name('procesos-admision.index'); Route::get('/', [ProcesoAdmisionController::class, 'index'])->name('procesos-admision.index');
Route::post('/', [ProcesoAdmisionController::class, 'store'])->name('procesos-admision.store'); Route::post('/', [ProcesoAdmisionController::class, 'store'])->name('procesos-admision.store');
@ -221,6 +186,14 @@ Route::middleware(['auth:postulante'])->group(function () {
}); });
Route::middleware('auth:sanctum')->group(function () {
Route::get('/procesos-disponibles-preinscripcion', [WebController::class, 'obtenerProcesosDisponiblesPreinscripcion']);
});
Route::get('/procesos-admision', [WebController::class, 'GetProcesoAdmision']); Route::get('/procesos-admision', [WebController::class, 'GetProcesoAdmision']);
Route::get('/noticias', [NoticiaController::class, 'index']);
Route::get('/noticias/{noticia:slug}', [NoticiaController::class, 'showPublic']);

@ -54,11 +54,10 @@
</div> </div>
<div class="tiny-hint"> <div class="tiny-hint">
Tip: Si ves 🟢 en una fecha, significa que esa etapa está activa hoy. Si ves 🟢 en una fecha, significa que esa etapa está activa hoy.
</div> </div>
</div> </div>
<!-- Qué hacer -->
<div class="help-item"> <div class="help-item">
<div class="help-label">2) ¿Qué debo hacer ahora?</div> <div class="help-label">2) ¿Qué debo hacer ahora?</div>

@ -122,11 +122,11 @@ onMounted(() => {
} }
.markdown-content :deep(.katex-display) { .markdown-content :deep(.katex-display) {
margin: 0.75em 0; margin: 14px 0; /* espacio arriba/abajo */
text-align: center; padding: 10px 0; /* aire dentro del bloque */
line-height: 1.25; /* evita que el contenedor aplaste */
overflow-x: auto; /* si es largo, que haga scroll horizontal */ overflow-x: auto;
overflow-y: hidden; /* IMPORTANTE: no scroll vertical -> no flechas */ overflow-y: visible; /* ✅ CLAVE: que NO recorte arriba/abajo */
} }
/* Quitar botones/flechas del scrollbar (Chrome/Edge) */ /* Quitar botones/flechas del scrollbar (Chrome/Edge) */
.markdown-content :deep(.katex-display::-webkit-scrollbar-button) { .markdown-content :deep(.katex-display::-webkit-scrollbar-button) {

@ -1,6 +1,5 @@
<template> <template>
<a-spin :spinning="loading"> <a-spin :spinning="loading">
<div class="section-container"> <div class="section-container">
<div class="page"> <div class="page">
<!-- Topbar --> <!-- Topbar -->
@ -9,14 +8,12 @@
<div class="hello">Bienvenido, {{ authStore.userName }}</div> <div class="hello">Bienvenido, {{ authStore.userName }}</div>
<div class="sub">DNI: {{ authStore.userDni || "No registrado" }}</div> <div class="sub">DNI: {{ authStore.userDni || "No registrado" }}</div>
</div> </div>
</div> </div>
<a-divider class="softDivider" /> <a-divider class="softDivider" />
<!-- Test -->
<a-card :bordered="false" class="testBox"> <a-card :bordered="false" class="testBox">
<div class="testHead"> <div class="testHead">
<div class="testHeadLeft"> <div class="testHeadLeft">
<div class="testTitle">Tu test diagnóstico</div> <div class="testTitle">Tu test diagnóstico</div>
@ -42,7 +39,14 @@
</div> </div>
<div class="testHeadRight"> <div class="testHeadRight">
<a-button type="primary" size="large" class="btnTest" :disabled="!canGoTest" @click="goToTest" block> <a-button
type="primary"
size="large"
class="btnTest"
:disabled="!canGoTest"
@click="goToTest"
block
>
Ir al test Ir al test
</a-button> </a-button>
@ -53,7 +57,7 @@
<a-divider class="softDivider" /> <a-divider class="softDivider" />
<!-- Procesos -->
<div class="sectionHead"> <div class="sectionHead">
<div> <div>
<div class="sectionTitle">Procesos activos</div> <div class="sectionTitle">Procesos activos</div>
@ -76,40 +80,31 @@
class="modernTable" class="modernTable"
> >
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.key === 'status'"> <template v-if="column.key === 'fecha_inicio_preinscripcion'">
<a-tag class="status-tag" :color="record.statusColor">{{ record.statusText }}</a-tag> {{ formatDate(record.fecha_inicio_preinscripcion) }}
</template> </template>
<template v-else-if="column.key === 'eligibility'"> <template v-else-if="column.key === 'fecha_fin_preinscripcion'">
<a-badge {{ formatDate(record.fecha_fin_preinscripcion) }}
:status="record.isEligible ? 'success' : 'error'"
:text="record.isEligible ? 'Apto' : 'No apto'"
/>
</template> </template>
<template v-else-if="column.key === 'actions'"> <template v-else-if="column.key === 'actions'">
<div class="actions"> <div class="actions">
<a-button size="small" block class="actionBtn" @click="onViewProcess(record)">Ver</a-button>
<a-button <a-button
size="small" size="small"
type="primary" type="primary"
block block
class="actionBtnPrimary" class="actionBtnPrimary"
:disabled="!record.canApply" :disabled="!record.link_preinscripcion"
@click="onApply(record)" @click="onApply(record)"
> >
Postular Postular
</a-button> </a-button>
</div> </div>
<div v-if="record.canApply === false && record.blockReason" class="microHelp">
{{ record.blockReason }}
</div>
</template> </template>
</template> </template>
</a-table> </a-table>
</div> </div>
</div>
<a-empty <a-empty
v-if="!loading && state.processes.length === 0" v-if="!loading && state.processes.length === 0"
@ -117,6 +112,7 @@
description="No hay procesos activos por el momento." description="No hay procesos activos por el momento."
/> />
</div> </div>
</div>
</a-spin> </a-spin>
</template> </template>
@ -125,10 +121,7 @@ import { computed, onMounted, reactive, ref } from "vue";
import { Modal, message } from "ant-design-vue"; import { Modal, message } from "ant-design-vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { useAuthStore } from "../../store/postulanteStore"; import { useAuthStore } from "../../store/postulanteStore";
import axios from "../../axiosPostulante";
const ROUTE_TEST_PANEL = { name: "PanelTest" };
const ROUTE_PROCESS_DETAIL = (id) => ({ name: "ProcesoDetalle", params: { id } });
const router = useRouter(); const router = useRouter();
const authStore = useAuthStore(); const authStore = useAuthStore();
@ -143,56 +136,35 @@ const state = reactive({
const canGoTest = computed(() => !!state.test.hasAssigned); const canGoTest = computed(() => !!state.test.hasAssigned);
const processColumns = computed(() => [ const processColumns = computed(() => [
{ title: "Proceso", dataIndex: "name", key: "name", ellipsis: true }, { title: "Título", dataIndex: "titulo", key: "titulo", ellipsis: true },
{ title: "Estado", key: "status", responsive: ["sm"] }, { title: "Inicio preinscripción", dataIndex: "fecha_inicio_preinscripcion", key: "fecha_inicio_preinscripcion" },
{ title: "Aptitud", key: "eligibility", responsive: ["md"] }, { title: "Fin preinscripción", dataIndex: "fecha_fin_preinscripcion", key: "fecha_fin_preinscripcion" },
{ title: "Acciones", key: "actions" }, { title: "Acciones", key: "actions" },
]); ]);
function formatDate(val) {
if (!val) return "-";
if (typeof val === "string" && val.includes("T")) return val.split("T")[0];
const d = new Date(val);
if (isNaN(d.getTime())) return String(val);
return d.toLocaleDateString();
}
const api = { const api = {
async getDashboard() { async getProcesosActivos() {
return new Promise((resolve) => { const { data } = await axios.get("/procesos-disponibles-preinscripcion");
setTimeout(() => { return data;
resolve({
test: { hasAssigned: true },
processes: [
{
id: 10,
name: "Admisión 2026-I",
statusText: "ABIERTO",
statusColor: "blue",
isEligible: true,
canApply: true,
blockReason: "",
},
{
id: 11,
name: "Admisión Extraordinaria 2026",
statusText: "PRONTO",
statusColor: "gold",
isEligible: false,
canApply: false,
blockReason: "Este proceso aún no permite postular.",
},
],
});
}, 250);
});
},
async applyToProcess(processId) {
return new Promise((resolve) => setTimeout(resolve, 300));
}, },
}; };
async function fetchDashboard() { async function fetchDashboard() {
loading.value = true; loading.value = true;
try { try {
const data = await api.getDashboard(); const resp = await api.getProcesosActivos();
state.test = { ...state.test, ...data.test }; state.processes = Array.isArray(resp?.data) ? resp.data : [];
state.processes = Array.isArray(data.processes) ? data.processes : []; } catch (e) {
} catch { console.error(e);
message.error("No se pudo cargar el dashboard."); state.processes = [];
} finally { } finally {
loading.value = false; loading.value = false;
} }
@ -212,91 +184,33 @@ function goToTest() {
}); });
} }
function onViewProcess(process) {
message.info(`Abrir detalle del proceso: ${process.name}`);
}
function onApply(process) { function onApply(process) {
if (!process.canApply) return; if (!process.link_preinscripcion) return;
window.open(process.link_preinscripcion, "_blank", "noopener,noreferrer");
Modal.confirm({
title: "Confirmar postulación",
content: `¿Deseas postular al proceso "${process.name}"?`,
okText: "Postular",
cancelText: "Cancelar",
async onOk() {
try {
await api.applyToProcess(process.id);
message.success("Postulación registrada.");
await fetchDashboard();
} catch {
message.error("No se pudo completar la postulación.");
}
},
});
} }
onMounted(fetchDashboard); onMounted(fetchDashboard);
</script> </script>
<style scoped> <style scoped>
/* ====== BASE ====== */
.dashboard-modern {
position: relative;
padding: 40px 0;
font-family: "Times New Roman", Times, serif;
background: #fbfcff;
overflow: hidden;
}
.dashboard-modern::before {
content: "";
position: absolute;
inset: 0;
pointer-events: none;
z-index: 0;
background-image:
repeating-linear-gradient(
to right,
rgba(13, 27, 82, 0.06) 0,
rgba(13, 27, 82, 0.06) 1px,
transparent 1px,
transparent 24px
),
repeating-linear-gradient(
to bottom,
rgba(13, 27, 82, 0.06) 0,
rgba(13, 27, 82, 0.06) 1px,
transparent 1px,
transparent 24px
);
opacity: 0.55;
}
.section-container { .section-container {
position: relative;
z-index: 1;
max-width: 1200px; max-width: 1200px;
margin: 0 auto; margin: 0 auto;
padding: 0 24px; padding: 0 24px;
} }
.page { .page {
width: 100%; width: 100%;
max-width: 1120px; max-width: 1120px;
margin: 0 auto; margin: 0 auto;
padding: 0;
} }
.mt12 { margin-top: 12px; } .mt12 { margin-top: 12px; }
.microHelp { font-size: 0.95rem; color: #666; margin-top: 6px; } .microHelp { font-size: 12px; color: #6b7280; margin-top: 8px; }
.softDivider { margin: 18px 0; } .softDivider { margin: 16px 0; }
/* ====== TOPBAR ====== */
.topbar { .topbar {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@ -306,91 +220,62 @@ onMounted(fetchDashboard);
} }
.hello { .hello {
font-size: 2rem; font-size: 28px;
font-weight: 700; font-weight: 900;
color: #0d1b52; color: #0f172a;
margin: 0; margin: 0;
letter-spacing: 0.2px;
} }
.sub { .sub {
margin-top: 6px; margin-top: 6px;
font-size: 1rem; font-size: 14px;
color: #666; color: #64748b;
}
.topbarRight {
min-width: 260px;
display: flex;
justify-content: flex-end;
}
.btnTop {
min-width: 180px;
height: 46px;
border-radius: 10px;
font-weight: 700;
} }
/* ====== TEST CARD ====== */
.testBox { .testBox {
position: relative; border: 1px solid rgba(15, 23, 42, 0.08);
border: none; border-radius: 18px;
border-radius: 16px; box-shadow: 0 10px 24px rgba(15, 23, 42, 0.06);
box-shadow: 0 10px 34px rgba(0, 0, 0, 0.08);
background: #fff; background: #fff;
} }
.testBox :deep(.ant-card-body) { .testBox :deep(.ant-card-body) {
padding: 28px; padding: 24px;
}
.cardBadge {
position: absolute;
top: -12px;
left: 24px;
background: linear-gradient(45deg, #1890ff, #52c41a);
color: #fff;
padding: 6px 16px;
border-radius: 999px;
font-size: 0.75rem;
font-weight: 700;
} }
.testHead { .testHead {
display: flex; display: grid;
justify-content: space-between; grid-template-columns: 1fr 300px;
gap: 16px; gap: 18px;
flex-wrap: wrap; align-items: start;
align-items: flex-start;
} }
.testTitle { .testTitle {
font-size: 1.55rem; font-size: 20px;
font-weight: 700; font-weight: 900;
color: #1a237e; color: #0f172a;
} }
.testSub { .testSub {
margin-top: 8px; margin-top: 8px;
font-size: 1rem; font-size: 14px;
color: #666; color: #475569;
line-height: 1.55; line-height: 1.6;
max-width: 760px; max-width: 760px;
} }
.testHeadRight { .testHeadRight {
min-width: 260px; display: grid;
display: flex;
flex-direction: column;
gap: 8px; gap: 8px;
align-items: flex-end; align-content: start;
} }
.btnTest { .btnTest {
height: 52px; height: 48px;
border-radius: 12px; border-radius: 12px;
font-weight: 700; font-weight: 900;
background: linear-gradient(135deg, #1a237e 0%, #283593 100%);
border: none; border: none;
} }
@ -399,21 +284,21 @@ onMounted(fetchDashboard);
display: flex; display: flex;
gap: 10px; gap: 10px;
align-items: flex-start; align-items: flex-start;
font-size: 1rem; font-size: 14px;
color: #666; color: #475569;
line-height: 1.55; line-height: 1.6;
} }
.dot { .dot {
width: 8px; width: 8px;
height: 8px; height: 8px;
border-radius: 999px; border-radius: 999px;
background: #1a237e; background: #1677ff;
margin-top: 9px; margin-top: 9px;
flex: 0 0 auto; flex: 0 0 auto;
} }
/* ====== SECTION HEAD ====== */
.sectionHead { .sectionHead {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@ -422,34 +307,33 @@ onMounted(fetchDashboard);
align-items: flex-start; align-items: flex-start;
} }
.sectionRight { margin-top: 4px; }
.sectionTitle { .sectionTitle {
font-size: 1.55rem; font-size: 20px;
font-weight: 700; font-weight: 900;
color: #0d1b52; color: #0f172a;
margin: 0; margin: 0;
} }
.sectionSub { .sectionSub {
margin-top: 8px; margin-top: 6px;
font-size: 1rem; font-size: 14px;
color: #666; color: #64748b;
line-height: 1.55; line-height: 1.6;
} }
/* Badge Nuevo (como convocatorias) */
.new-badge :deep(.ant-badge-count) { .new-badge :deep(.ant-badge-count) {
background: linear-gradient(45deg, #ff6b6b, #ffd700); background: linear-gradient(45deg, #ff6b6b, #ffd700);
box-shadow: 0 2px 8px rgba(255, 107, 107, 0.3); box-shadow: 0 2px 8px rgba(255, 107, 107, 0.25);
border-radius: 999px; border-radius: 999px;
} }
/* ====== TABLE WRAP ====== */
.tableWrap { .tableWrap {
width: 100%; width: 100%;
overflow-x: auto; overflow-x: auto;
border-radius: 16px; border-radius: 18px;
box-shadow: 0 10px 34px rgba(0, 0, 0, 0.08); border: 1px solid rgba(15, 23, 42, 0.08);
box-shadow: 0 10px 24px rgba(15, 23, 42, 0.06);
background: #fff; background: #fff;
padding: 8px; padding: 8px;
} }
@ -460,86 +344,92 @@ onMounted(fetchDashboard);
:deep(.modernTable .ant-table-container) { :deep(.modernTable .ant-table-container) {
overflow-x: auto; overflow-x: auto;
border-radius: 12px; border-radius: 14px;
} }
:deep(.modernTable .ant-table-thead > tr > th) { :deep(.modernTable .ant-table-thead > tr > th) {
background: rgba(13, 27, 82, 0.03); background: rgba(15, 23, 42, 0.03);
color: #0d1b52; color: #0f172a;
font-weight: 700; font-weight: 900;
} }
:deep(.modernTable .ant-table-tbody > tr > td) { :deep(.modernTable .ant-table-tbody > tr > td) {
color: #666; color: #475569;
}
.status-tag {
font-weight: 700;
padding: 4px 12px;
border-radius: 999px;
white-space: nowrap;
} }
.actions { .actions {
display: grid; display: grid;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr;
gap: 8px; gap: 8px;
} }
.actionBtn {
border-radius: 10px;
height: 38px;
font-weight: 700;
}
.actionBtnPrimary { .actionBtnPrimary {
border-radius: 10px; border-radius: 10px;
height: 38px; height: 36px;
font-weight: 700; font-weight: 900;
} }
/* ====== RESPONSIVE ====== */
@media (max-width: 992px) {
.section-container {
padding: 0 16px;
}
@media (max-width: 768px) { .testHead {
.hide-mobile{ grid-template-columns: 1fr;
display: none !important;
} }
.test-modern{ .testHeadRight {
padding-top: 0 !important; justify-items: stretch;
padding-bottom: 24px; }
} }
@media (max-width: 768px) {
.section-container { .section-container {
max-width: none; max-width: none;
padding: 0 !important; padding: 0 !important;
margin: 0 !important; margin: 0 !important;
} }
.hero{ .page {
grid-template-columns: 1fr; max-width: none;
width: 100%; margin: 0;
margin: 0 !important; padding: 0;
border-radius: 0 !important; }
padding: 14px 16px 18px !important; .softDivider {
margin: 12px 0;
} }
.heroKicker{ margin-top: 0 !important; } .hello {
.heroTitle{ margin-top: 6px !important; } font-size: 22px;
.heroText{ margin-top: 8px !important; } }
.section{ /* card full width en móvil (pro) */
padding: 0 16px; .testBox,
.tableWrap {
border-radius: 0;
border-left: 0;
border-right: 0;
}
.testBox :deep(.ant-card-body) {
padding: 14px;
} }
.heroFacts{ .tableWrap {
grid-template-columns: repeat(2, minmax(0, 1fr)); padding: 6px;
} }
} }
@media (max-width: 576px){ @media (max-width: 480px) {
.heroFacts{ .hello {
grid-template-columns: 1fr; font-size: 20px;
}
.testSub,
.bulletRow,
.sectionSub {
font-size: 13px;
} }
} }
</style> </style>

@ -690,23 +690,16 @@ onUnmounted(() => {
height: 100%; height: 100%;
} }
@media (max-width: 992px) {
.main-layout,
.main-layout.layout-collapsed {
margin-left: 0 !important;
}
.content-container {
max-width: 100%;
}
}
@media (max-width: 768px) { @media (max-width: 768px) {
.header, .header,
.header-container { .header-container {
height: 56px; height: 56px;
} }
.header-container {
padding: 0 12px; /* ✅ menos padding lateral en móvil */
}
.sidebar, .sidebar,
.sidebar.sidebar-mobile { .sidebar.sidebar-mobile {
top: 56px; top: 56px;
@ -714,8 +707,8 @@ onUnmounted(() => {
} }
.logo-img { .logo-img {
height: 36px; height: 34px;
width: 36px; width: 34px;
} }
.portal-title { .portal-title {
@ -726,12 +719,58 @@ onUnmounted(() => {
display: none; display: none;
} }
/* ✅ CONTENT: padding externo pequeño (se ve pro y no encoge tanto) */
.content { .content {
padding: 12px; padding: 8px !important;
background: var(--ant-colorBgLayout, #f5f5f5);
}
.content-container {
max-width: 100% !important;
margin: 0 !important;
padding: 0 !important;
} }
/* ✅ CARD: sin borde/sombra pesada en móvil y radio moderado */
.content-card { .content-card {
border-radius: 14px; border-radius: 12px !important;
margin: 0 !important;
border: 1px solid var(--ant-colorBorderSecondary, rgba(0,0,0,.06)) !important;
box-shadow: 0 6px 16px rgba(0,0,0,.06) !important;
background: #fff;
overflow: hidden;
}
/* ✅ CLAVE: padding interno del body (no exagerado) */
.content-card :deep(.ant-card-body) {
padding: 12px !important;
}
/* ✅ opcional: quita el “papel cuadriculado” en móvil (se ve más limpio) */
.content-card::before {
display: none !important;
}
}
/* Extra: teléfonos chicos (más pro aún) */
@media (max-width: 480px) {
.content {
padding: 6px !important;
}
.content-card :deep(.ant-card-body) {
padding: 10px !important;
}
}
/* ===== FIX MÓVIL REAL ===== */
@media (max-width: 992px) {
.main-layout,
.main-layout.layout-collapsed {
margin-left: 0 !important;
}
.sidebar {
position: fixed !important;
left: 0;
} }
} }
</style> </style>

File diff suppressed because it is too large Load Diff

@ -1,6 +1,10 @@
<!-- PanelResultados.vue (DISEÑO ALTERNATIVO: "Scoreboard" moderno, full responsive) --> <!-- PanelResultados.vue (DASH STYLE + RESPONSIVE PRO) -->
<template> <template>
<div class="dashboard-modern">
<a-spin :spinning="cargando" tip="Cargando resultados...">
<div class="section-container">
<div class="page alt"> <div class="page alt">
<!-- Head -->
<div class="head"> <div class="head">
<div> <div>
<div class="hTitle">Resultados del examen</div> <div class="hTitle">Resultados del examen</div>
@ -17,7 +21,6 @@
</div> </div>
</div> </div>
<a-spin :spinning="cargando" tip="Cargando resultados...">
<template v-if="resultado"> <template v-if="resultado">
<a-row :gutter="[16, 16]"> <a-row :gutter="[16, 16]">
<a-col :xs="24" :lg="10"> <a-col :xs="24" :lg="10">
@ -38,10 +41,7 @@
<div class="bigProgress"> <div class="bigProgress">
<a-progress :percent="notaPercent" /> <a-progress :percent="notaPercent" />
<div class="bigProgressMeta"> <div class="bigProgressMeta"></div>
<!-- <span>Nota equivalente</span>
<b>{{ fmt2(resultado.calificacion_sobre_20) }}/20</b> -->
</div>
</div> </div>
<a-alert <a-alert
@ -164,6 +164,8 @@
</a-button> </a-button>
</a-empty> </a-empty>
</template> </template>
</div>
</div>
</a-spin> </a-spin>
</div> </div>
</template> </template>
@ -242,7 +244,9 @@ const rowsCursos = computed(() => {
const rows = Array.from(keys).map((k) => { const rows = Array.from(keys).map((k) => {
const correctas = parseCorrectas(corr?.[k] ?? 0) const correctas = parseCorrectas(corr?.[k] ?? 0)
const total = parseTotal(k) || (() => { const total =
parseTotal(k) ||
(() => {
const val = corr?.[k] const val = corr?.[k]
if (typeof val === 'string' && val.includes('de')) { if (typeof val === 'string' && val.includes('de')) {
const [, b] = val.split('de') const [, b] = val.split('de')
@ -262,7 +266,6 @@ const rowsCursos = computed(() => {
const recalcular = async () => { const recalcular = async () => {
if (!examenId.value) return if (!examenId.value) return
cargando.value = true cargando.value = true
try { try {
const r = await examenStore.calificarExamen(examenId.value) const r = await examenStore.calificarExamen(examenId.value)
@ -286,17 +289,58 @@ onMounted(async () => {
</script> </script>
<style scoped> <style scoped>
/* ====== MISMO BACKGROUND QUE DASH ====== */
.dashboard-modern {
position: relative;
padding: 22px 0;
font-family: "Times New Roman", Times, serif;
background: #fbfcff;
overflow: hidden;
}
.dashboard-modern::before {
content: "";
position: absolute;
inset: 0;
pointer-events: none;
z-index: 0;
background-image:
repeating-linear-gradient(
to right,
rgba(13, 27, 82, 0.06) 0,
rgba(13, 27, 82, 0.06) 1px,
transparent 1px,
transparent 24px
),
repeating-linear-gradient(
to bottom,
rgba(13, 27, 82, 0.06) 0,
rgba(13, 27, 82, 0.06) 1px,
transparent 1px,
transparent 24px
);
opacity: 0.55;
}
.section-container {
position: relative;
z-index: 1;
max-width: 1200px;
margin: 0 auto;
padding: 0 24px;
}
.page { .page {
padding: 16px; width: 100%;
max-width: 1120px; max-width: 1120px;
margin: 0 auto; margin: 0 auto;
padding: 0;
} }
.mt16 { margin-top: 16px; }
.alt { .mt16 { margin-top: 16px; }
background: transparent; .alt { background: transparent; }
}
/* ====== HEADER ====== */
.head { .head {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@ -305,35 +349,77 @@ onMounted(async () => {
align-items: flex-start; align-items: flex-start;
margin-bottom: 14px; margin-bottom: 14px;
} }
.hTitle { .hTitle {
margin: 0; margin: 0;
font-size: 1.85rem; font-size: 1.85rem;
font-weight: 700; font-weight: 900;
color: #0d1b52; color: #0d1b52;
line-height: 1.15; line-height: 1.15;
} }
.hSub { .hSub {
margin-top: 4px; margin-top: 4px;
font-size: 12.5px; font-size: 12.5px;
color: var(--ant-colorTextSecondary, #6b7280); color: var(--ant-colorTextSecondary, #6b7280);
line-height: 1.35; line-height: 1.35;
} }
.headActions { .headActions {
min-width: 260px; min-width: 260px;
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
} }
.btnSoft, .btnPrimary { border-radius: 12px; font-weight: 900; }
.btnSoft, .btnPrimary {
border-radius: 12px;
font-weight: 900;
}
/* ====== CARD (igual dash content-card) ====== */
.card { .card {
position: relative;
border-radius: 18px; border-radius: 18px;
border: 1px solid var(--ant-colorBorderSecondary, rgba(0,0,0,.06)); border: 1px solid var(--ant-colorBorderSecondary, rgba(0,0,0,.06));
box-shadow: var(--ant-boxShadowSecondary, 0 10px 28px rgba(0,0,0,.08)); box-shadow: var(--ant-boxShadowSecondary, 0 10px 28px rgba(0,0,0,.08));
background: var(--ant-colorBgContainer, #fff); background: var(--ant-colorBgContainer, #fff);
overflow: hidden;
}
.card::before {
content: "";
position: absolute;
inset: 0;
pointer-events: none;
z-index: 0;
background-image:
repeating-linear-gradient(
to right,
rgba(13, 27, 82, 0.05) 0,
rgba(13, 27, 82, 0.05) 1px,
transparent 1px,
transparent 24px
),
repeating-linear-gradient(
to bottom,
rgba(13, 27, 82, 0.05) 0,
rgba(13, 27, 82, 0.05) 1px,
transparent 1px,
transparent 24px
);
opacity: 0.35;
}
.card :deep(.ant-card-body),
.card :deep(.ant-card-head) {
position: relative;
z-index: 1;
} }
.card :deep(.ant-card-body) { padding: 16px; } .card :deep(.ant-card-body) { padding: 16px; }
.scoreCard :deep(.ant-card-body) { padding: 18px; } .scoreCard :deep(.ant-card-body) { padding: 18px; }
/* ====== SCORE ====== */
.scoreTop { .scoreTop {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@ -342,6 +428,7 @@ onMounted(async () => {
align-items: center; align-items: center;
margin-bottom: 10px; margin-bottom: 10px;
} }
.chipDone, .chipRank { .chipDone, .chipRank {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
@ -354,6 +441,7 @@ onMounted(async () => {
font-size: 12px; font-size: 12px;
color: #111827; color: #111827;
} }
.chipDot { .chipDot {
width: 8px; width: 8px;
height: 8px; height: 8px;
@ -367,38 +455,31 @@ onMounted(async () => {
color: #111827; color: #111827;
line-height: 1; line-height: 1;
} }
.scoreLabel { .scoreLabel {
margin-top: 4px; margin-top: 4px;
font-size: 12px; font-size: 12px;
color: #6b7280; color: #6b7280;
font-weight: 800; font-weight: 900;
} }
.bigProgress { margin-top: 12px; } .bigProgress { margin-top: 12px; }
.bigProgressMeta {
margin-top: 6px;
display: flex;
justify-content: space-between;
gap: 10px;
font-size: 12px;
color: #6b7280;
}
.bigProgressMeta b { color: #111827; }
.advice { margin-top: 12px; border-radius: 14px; } .advice { margin-top: 12px; border-radius: 14px; }
/* KPIs */ /* ====== KPIs ====== */
.kpi .kpiK, .kpiWide .kpiK, .noteCard .kpiK { .kpi .kpiK, .kpiWide .kpiK, .noteCard .kpiK {
font-size: 12px; font-size: 12px;
color: #6b7280; color: #6b7280;
font-weight: 900; font-weight: 900;
} }
.kpi .kpiV, .kpiWide .kpiV, .noteCard .kpiV { .kpi .kpiV, .kpiWide .kpiV, .noteCard .kpiV {
margin-top: 6px; margin-top: 6px;
font-size: 26px; font-size: 26px;
font-weight: 950; font-weight: 950;
color: #111827; color: #111827;
} }
.kpiHint { .kpiHint {
margin-top: 2px; margin-top: 2px;
font-size: 12px; font-size: 12px;
@ -419,29 +500,42 @@ onMounted(async () => {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.miniCircleLabel { .miniCircleLabel {
position: absolute; position: absolute;
text-align: center; text-align: center;
} }
.miniCircleMain { font-weight: 950; font-size: 16px; color: #111827; line-height: 1; }
.miniCircleMain {
font-weight: 950;
font-size: 16px;
color: #111827;
line-height: 1;
}
.miniCircleSub { font-size: 12px; color: #6b7280; } .miniCircleSub { font-size: 12px; color: #6b7280; }
/* Tabla */ /* ====== TABLE ====== */
.tableWrap { .tableWrap {
width: 100%; width: 100%;
overflow-x: auto; overflow-x: auto;
border-radius: 14px; border-radius: 14px;
} }
.tableWrap :deep(.ant-table-container) { overflow-x: auto; } .tableWrap :deep(.ant-table-container) { overflow-x: auto; }
:deep(.modernTable .ant-table-thead > tr > th) { :deep(.modernTable .ant-table-thead > tr > th) {
background: rgba(22,119,255,.04); background: rgba(13, 27, 82, 0.03);
color: #0d1b52;
font-weight: 900; font-weight: 900;
} }
.courseCell { .courseCell {
display: flex; display: flex;
gap: 10px; gap: 10px;
align-items: flex-start; align-items: flex-start;
} }
.courseDot { .courseDot {
width: 10px; width: 10px;
height: 10px; height: 10px;
@ -450,6 +544,7 @@ onMounted(async () => {
margin-top: 6px; margin-top: 6px;
flex: 0 0 auto; flex: 0 0 auto;
} }
.courseName { font-weight: 900; color: #111827; line-height: 1.2; } .courseName { font-weight: 900; color: #111827; line-height: 1.2; }
.courseMeta { margin-top: 2px; font-size: 12px; color: #6b7280; } .courseMeta { margin-top: 2px; font-size: 12px; color: #6b7280; }
@ -467,27 +562,43 @@ onMounted(async () => {
background: rgba(0,0,0,.03); background: rgba(0,0,0,.03);
color: #111827; color: #111827;
} }
.pill.good { border-color: rgba(22,119,255,.25); background: rgba(22,119,255,.08); } .pill.good { border-color: rgba(22,119,255,.25); background: rgba(22,119,255,.08); }
.pill.bad { border-color: rgba(0,0,0,.10); background: rgba(0,0,0,.04); } .pill.bad { border-color: rgba(0,0,0,.10); background: rgba(0,0,0,.04); }
.pill.neutral { opacity: .92; } .pill.neutral { opacity: .92; }
.empty { margin-top: 12px; } .empty { margin-top: 12px; }
/* ====== MOBILE: FULL WIDTH, SIN ESPACIOS ====== */
@media (max-width: 768px) { @media (max-width: 768px) {
.dashboard-modern { padding: 0 0 14px; }
.section-container { max-width: none; padding: 0 !important; margin: 0 !important; }
.page { max-width: none; padding: 0; }
.head { padding: 0 16px; margin-bottom: 10px; }
.headActions { width: 100%; min-width: 0; justify-content: flex-start; } .headActions { width: 100%; min-width: 0; justify-content: flex-start; }
.headSpace { .headSpace {
width: 100%; width: 100%;
display: grid; display: grid;
grid-template-columns: 1fr; grid-template-columns: 1fr;
gap: 10px; gap: 10px;
} }
.btnSoft, .btnPrimary { width: 100%; } .btnSoft, .btnPrimary { width: 100%; }
/* cards full width */
.card {
border-radius: 0 !important;
border-left: 0 !important;
border-right: 0 !important;
}
.scoreMain { font-size: 36px; } .scoreMain { font-size: 36px; }
} }
@media (max-width: 480px) { @media (max-width: 480px) {
.page { padding: 12px; } .head { padding: 0 12px; }
.scoreMain { font-size: 32px; } .scoreMain { font-size: 32px; }
.bigProgressMeta { flex-direction: column; align-items: flex-start; }
} }
</style> </style>

@ -550,10 +550,10 @@ No se realiza ningún pago adicional.
</template> </template>
<style scoped> <style scoped>
/* ====== BASE (igual dash) ====== */
.test-modern { .test-modern {
position: relative; position: relative;
padding: 40px 0; padding: 32px 0;
font-family: "Times New Roman", Times, serif; font-family: "Times New Roman", Times, serif;
background: #fbfcff; background: #fbfcff;
overflow: hidden; overflow: hidden;
@ -565,7 +565,6 @@ No se realiza ningún pago adicional.
inset: 0; inset: 0;
pointer-events: none; pointer-events: none;
z-index: 0; z-index: 0;
background-image: background-image:
repeating-linear-gradient( repeating-linear-gradient(
to right, to right,
@ -581,7 +580,6 @@ No se realiza ningún pago adicional.
transparent 1px, transparent 1px,
transparent 24px transparent 24px
); );
opacity: 0.55; opacity: 0.55;
} }
@ -593,51 +591,22 @@ No se realiza ningún pago adicional.
padding: 0 24px; padding: 0 24px;
} }
.mt12 { margin-top: 12px; } .mt12 { margin-top: 12px; }
.mt16 { margin-top: 16px; } .mt16 { margin-top: 16px; }
.mb12 { margin-bottom: 12px; } .mb12 { margin-bottom: 12px; }
.muted { color: #666; line-height: 1.6; } .muted { color: #666; line-height: 1.6; }
/* ====== HERO TITLES ====== */
.hero {
position: relative;
border: none;
border-radius: 16px;
box-shadow: 0 10px 34px rgba(0, 0, 0, 0.08);
padding: 28px;
display: grid;
grid-template-columns: 1.2fr 0.8fr;
gap: 22px;
align-items: start;
background: #fff;
overflow: hidden;
}
.hero::after {
position: absolute;
top: -12px;
left: 24px;
background: linear-gradient(45deg, #1890ff, #52c41a);
color: #fff;
padding: 6px 16px;
border-radius: 999px;
font-size: 0.75rem;
font-weight: 700;
}
.heroLeft, .heroRight { min-width: 0; }
.heroKicker { .heroKicker {
font-size: 0.95rem; font-size: 0.95rem;
color: #666; color: #6b7280;
margin-bottom: 6px; margin-bottom: 6px;
} }
.heroTitle { .heroTitle {
margin: 0; margin: 0;
font-size: 1.85rem; font-size: 1.85rem;
font-weight: 700; font-weight: 900;
color: #0d1b52; color: #0d1b52;
line-height: 1.15; line-height: 1.15;
} }
@ -645,9 +614,27 @@ No se realiza ningún pago adicional.
.heroText { .heroText {
margin-top: 10px; margin-top: 10px;
font-size: 1.05rem; font-size: 1.05rem;
color: #666; color: #6b7280;
} }
/* ====== HERO CARD (igual dash) ====== */
.hero {
margin-top: 14px;
border-radius: 18px;
border: 1px solid rgba(13, 27, 82, 0.08);
background: #fff;
box-shadow: 0 10px 28px rgba(0,0,0,0.08);
padding: 24px;
display: grid;
grid-template-columns: 1.2fr 0.8fr;
gap: 18px;
align-items: start;
overflow: hidden;
}
.heroLeft, .heroRight { min-width: 0; }
/* ====== FACTS ====== */
.heroFacts { .heroFacts {
margin-top: 16px; margin-top: 16px;
display: grid; display: grid;
@ -664,13 +651,13 @@ No se realiza ningún pago adicional.
.factK { .factK {
font-size: 0.9rem; font-size: 0.9rem;
color: #666; color: #6b7280;
font-weight: 700; font-weight: 900;
} }
.factV { .factV {
margin-top: 6px; margin-top: 6px;
font-weight: 700; font-weight: 900;
font-size: 0.95rem; font-size: 0.95rem;
color: #1a237e; color: #1a237e;
overflow: hidden; overflow: hidden;
@ -678,7 +665,7 @@ No se realiza ningún pago adicional.
white-space: nowrap; white-space: nowrap;
} }
/* ====== BANK ACTIONS ====== */
.bankActions { .bankActions {
margin-top: 18px; margin-top: 18px;
padding: 16px; padding: 16px;
@ -694,28 +681,29 @@ No se realiza ningún pago adicional.
margin: 0; margin: 0;
font-size: 1.05rem; font-size: 1.05rem;
color: #1a237e; color: #1a237e;
font-weight: 700; font-weight: 900;
} }
.bankSub { .bankSub {
margin-top: 6px; margin-top: 6px;
font-size: 0.95rem; font-size: 0.95rem;
color: #666; color: #6b7280;
line-height: 1.45; line-height: 1.55;
} }
.bankBtn { .bankBtn {
height: 44px; height: 44px;
border-radius: 10px; border-radius: 10px;
font-weight: 700; font-weight: 900;
} }
/* ====== CTA CARD ====== */
.ctaCard { .ctaCard {
border: none; border-radius: 18px;
border-radius: 16px; border: 1px solid rgba(13, 27, 82, 0.08);
box-shadow: 0 10px 34px rgba(0, 0, 0, 0.08); box-shadow: 0 10px 28px rgba(0,0,0,0.08);
background: #fff; background: #fff;
padding: 20px; padding: 18px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 12px; gap: 12px;
@ -731,25 +719,25 @@ No se realiza ningún pago adicional.
.ctaTitle { .ctaTitle {
margin: 0; margin: 0;
font-size: 1.1rem; font-size: 1.1rem;
font-weight: 700; font-weight: 900;
color: #0d1b52; color: #0d1b52;
} }
.ctaHint { .ctaHint {
margin-top: 6px; margin-top: 6px;
font-size: 0.95rem; font-size: 0.95rem;
color: #666; color: #6b7280;
line-height: 1.45; line-height: 1.55;
} }
.statusTag { .statusTag {
font-weight: 700; font-weight: 900;
padding: 4px 12px; padding: 4px 12px;
border-radius: 999px; border-radius: 999px;
white-space: nowrap; white-space: nowrap;
border: 1px solid rgba(0,0,0,0.06); border: 1px solid rgba(0,0,0,0.06);
background: rgba(0,0,0,0.03); background: rgba(0,0,0,0.03);
color: #666; color: #6b7280;
} }
.statusTag.ok { .statusTag.ok {
@ -771,9 +759,9 @@ No se realiza ningún pago adicional.
} }
.ctaBtn { .ctaBtn {
height: 52px; height: 50px;
border-radius: 12px; border-radius: 12px;
font-weight: 700; font-weight: 900;
} }
.primaryBtn { .primaryBtn {
@ -786,11 +774,12 @@ No se realiza ningún pago adicional.
border: 1px solid rgba(13, 27, 82, 0.14); border: 1px solid rgba(13, 27, 82, 0.14);
} }
.ctaDivider { margin: 14px 0 0; } .ctaDivider { margin: 12px 0 0; }
/* ====== SECTION ====== */
.sectionTitle { .sectionTitle {
font-size: 1.35rem; font-size: 1.35rem;
font-weight: 700; font-weight: 900;
color: #0d1b52; color: #0d1b52;
margin: 0; margin: 0;
} }
@ -798,15 +787,16 @@ No se realiza ningún pago adicional.
.sectionSub { .sectionSub {
margin-top: 8px; margin-top: 8px;
font-size: 1rem; font-size: 1rem;
color: #666; color: #6b7280;
} }
.hint { .hint {
margin-top: 10px; margin-top: 10px;
font-size: 0.95rem; font-size: 0.95rem;
color: #666; color: #6b7280;
} }
/* ====== MODALS ====== */
:deep(.voucher-modal .ant-modal-content), :deep(.voucher-modal .ant-modal-content),
:deep(.select-modal .ant-modal-content) { :deep(.select-modal .ant-modal-content) {
border-radius: 16px; border-radius: 16px;
@ -827,7 +817,7 @@ No se realiza ningún pago adicional.
.voucher-caption { .voucher-caption {
margin-bottom: 10px; margin-bottom: 10px;
color: #666; color: #6b7280;
line-height: 1.6; line-height: 1.6;
} }
@ -845,17 +835,27 @@ No se realiza ningún pago adicional.
gap: 10px; gap: 10px;
} }
/* ====== GLOBAL ANT LOOK ====== */
:deep(.ant-card) { border-radius: 12px; } :deep(.ant-card) { border-radius: 12px; }
:deep(.ant-card-bordered) { border: 1px solid rgba(13, 27, 82, 0.10); } :deep(.ant-card-bordered) { border: 1px solid rgba(13, 27, 82, 0.10); }
/* ====== RESPONSIVE ====== */
@media (max-width: 992px) {
.hero {
grid-template-columns: 1fr;
}
@media (max-width: 768px) { .heroFacts {
.hide-mobile{ grid-template-columns: repeat(2, minmax(0, 1fr));
display: none !important;
} }
}
@media (max-width: 768px) {
.hide-mobile { display: none !important; }
/* mismo patrón del dash: full width en móvil */
.test-modern { .test-modern {
padding-top: 0 !important; padding: 0 0 18px;
padding-bottom: 24px; /* opcional */
} }
.section-container { .section-container {
@ -864,32 +864,35 @@ No se realiza ningún pago adicional.
margin: 0 !important; margin: 0 !important;
} }
.heroKicker,
.heroTitle,
.heroText {
padding: 0 16px;
}
.hero { .hero {
grid-template-columns: 1fr;
width: 100%;
margin: 0 !important;
border-radius: 0 !important; border-radius: 0 !important;
border-left: 0 !important;
border-right: 0 !important;
padding: 14px 16px 18px !important; padding: 14px 16px 18px !important;
} }
.heroKicker{ margin-top: 0 !important; }
.heroTitle{ margin-top: 6px !important; }
.heroText{ margin-top: 8px !important; }
.section { .section {
padding: 0 16px; padding: 0 16px;
} }
.heroFacts{
grid-template-columns: repeat(2, minmax(0, 1fr));
}
} }
@media (max-width: 576px) { @media (max-width: 576px) {
.heroFacts { .heroFacts {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
.heroTitle {
font-size: 1.55rem;
} }
.ctaBtn {
height: 48px;
}
}
</style> </style>
Loading…
Cancel
Save