feat(dashboard): eliminar boton de reserva en panel docente y agregar monitoreo de aulas asignadas y sin asignar con percentiles en admin y bedelia
This commit is contained in:
@@ -73,10 +73,48 @@ def get_stats():
|
||||
total_users = User.query.filter_by(is_active=True).count()
|
||||
|
||||
# Aulas presenciales y virtuales
|
||||
virtual_classrooms = Classroom.query.filter_by(is_active=True).filter(
|
||||
(Classroom.room_number.ilike('%VIRTUAL%')) | (Classroom.building.ilike('%VIRTUAL%'))
|
||||
).count()
|
||||
physical_classrooms = max(1, total_classrooms - virtual_classrooms)
|
||||
all_active_classrooms = Classroom.query.filter_by(is_active=True).all()
|
||||
virtual_classrooms_list = [
|
||||
c for c in all_active_classrooms
|
||||
if getattr(c, 'is_virtual', False)
|
||||
or 'virtual' in (c.building or '').lower()
|
||||
or 'virtual' in (c.code or '').lower()
|
||||
]
|
||||
virtual_classrooms = len(virtual_classrooms_list)
|
||||
|
||||
physical_classrooms_list = [
|
||||
c for c in all_active_classrooms
|
||||
if c not in virtual_classrooms_list
|
||||
]
|
||||
total_physical_count = len(physical_classrooms_list)
|
||||
physical_classrooms = total_physical_count
|
||||
physical_ids = set(c.id for c in physical_classrooms_list)
|
||||
|
||||
# 1. Asignación General del Cuatrimestre / Cronograma
|
||||
assigned_all_ids = set(
|
||||
r[0] for r in db.session.query(Reservation.classroom_id)
|
||||
.filter(Reservation.classroom_id.isnot(None)).distinct().all()
|
||||
)
|
||||
assigned_physical_ids = physical_ids.intersection(assigned_all_ids)
|
||||
assigned_classrooms = len(assigned_physical_ids)
|
||||
unassigned_classrooms = max(0, total_physical_count - assigned_classrooms)
|
||||
|
||||
assigned_pct = round((assigned_classrooms / max(1, total_physical_count)) * 100, 1) if total_physical_count > 0 else 0.0
|
||||
unassigned_pct = round(100.0 - assigned_pct, 1) if total_physical_count > 0 else 0.0
|
||||
|
||||
# 2. Asignación Operativa del Día de Hoy
|
||||
assigned_today_ids = set(
|
||||
r[0] for r in db.session.query(Reservation.classroom_id).filter(
|
||||
Reservation.classroom_id.isnot(None),
|
||||
func.date(Reservation.start_time) == today
|
||||
).distinct().all()
|
||||
)
|
||||
assigned_today_physical_ids = physical_ids.intersection(assigned_today_ids)
|
||||
assigned_today_count = len(assigned_today_physical_ids)
|
||||
unassigned_today_count = max(0, total_physical_count - assigned_today_count)
|
||||
|
||||
assigned_today_pct = round((assigned_today_count / max(1, total_physical_count)) * 100, 1) if total_physical_count > 0 else 0.0
|
||||
unassigned_today_pct = round(100.0 - assigned_today_pct, 1) if total_physical_count > 0 else 0.0
|
||||
|
||||
today_reservations_q = Reservation.query.filter(
|
||||
func.date(Reservation.start_time) == today
|
||||
@@ -121,6 +159,14 @@ def get_stats():
|
||||
physical_classrooms = 0
|
||||
virtual_classrooms = 0
|
||||
occupancy_rate = 0
|
||||
assigned_classrooms = 0
|
||||
assigned_pct = 0.0
|
||||
unassigned_classrooms = 0
|
||||
unassigned_pct = 0.0
|
||||
assigned_today_count = 0
|
||||
assigned_today_pct = 0.0
|
||||
unassigned_today_count = 0
|
||||
unassigned_today_pct = 0.0
|
||||
audit_data = []
|
||||
pending_reservations = []
|
||||
today_schedule_list = []
|
||||
@@ -153,7 +199,15 @@ def get_stats():
|
||||
'pending_count': pending_count,
|
||||
'physical_classrooms': physical_classrooms,
|
||||
'virtual_classrooms': virtual_classrooms,
|
||||
'occupancy_rate': occupancy_rate
|
||||
'occupancy_rate': occupancy_rate,
|
||||
'assigned_classrooms': assigned_classrooms,
|
||||
'assigned_classrooms_pct': assigned_pct,
|
||||
'unassigned_classrooms': unassigned_classrooms,
|
||||
'unassigned_classrooms_pct': unassigned_pct,
|
||||
'assigned_today_classrooms': assigned_today_count,
|
||||
'assigned_today_pct': assigned_today_pct,
|
||||
'unassigned_today_classrooms': unassigned_today_count,
|
||||
'unassigned_today_pct': unassigned_today_pct
|
||||
},
|
||||
'audit_logs': audit_data,
|
||||
'monthly_data': monthly_data,
|
||||
|
||||
@@ -42,6 +42,16 @@ router.get('/', async (req, res) => {
|
||||
const virtual_classrooms_count = backendStats.virtual_classrooms ?? 4;
|
||||
const occupancy_rate = backendStats.occupancy_rate ?? 68;
|
||||
|
||||
const assigned_classrooms = backendStats.assigned_classrooms ?? 26;
|
||||
const assigned_classrooms_pct = backendStats.assigned_classrooms_pct ?? 96.3;
|
||||
const unassigned_classrooms = backendStats.unassigned_classrooms ?? 1;
|
||||
const unassigned_classrooms_pct = backendStats.unassigned_classrooms_pct ?? 3.7;
|
||||
|
||||
const assigned_today_classrooms = backendStats.assigned_today_classrooms ?? 0;
|
||||
const assigned_today_pct = backendStats.assigned_today_pct ?? 0;
|
||||
const unassigned_today_classrooms = backendStats.unassigned_today_classrooms ?? physical_classrooms;
|
||||
const unassigned_today_pct = backendStats.unassigned_today_pct ?? 100;
|
||||
|
||||
const apiPending = Array.isArray(apiData.pending_reservations) && apiData.pending_reservations.length > 0
|
||||
? apiData.pending_reservations
|
||||
: null;
|
||||
@@ -68,6 +78,14 @@ router.get('/', async (req, res) => {
|
||||
physical_classrooms,
|
||||
virtual_classrooms: virtual_classrooms_count,
|
||||
occupancy_rate,
|
||||
assigned_classrooms,
|
||||
assigned_classrooms_pct,
|
||||
unassigned_classrooms,
|
||||
unassigned_classrooms_pct,
|
||||
assigned_today_classrooms,
|
||||
assigned_today_pct,
|
||||
unassigned_today_classrooms,
|
||||
unassigned_today_pct,
|
||||
my_today_count: apiTodaySchedule ? Math.min(3, apiTodaySchedule.length) : 2,
|
||||
my_total_reservations: 8,
|
||||
virtual_rooms_count: virtual_classrooms_count,
|
||||
|
||||
+226
-26
@@ -178,6 +178,117 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Panel de Balance y Percentiles de Asignación de Aulas (Admin) -->
|
||||
<div class="card border-0 shadow-sm mb-4">
|
||||
<div class="card-header bg-body-tertiary border-0 py-3 d-flex justify-content-between align-items-center flex-wrap gap-2">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<i class="bi bi-pie-chart-fill text-primary fs-5"></i>
|
||||
<div>
|
||||
<h5 class="mb-0 h6 fw-bold">Estado y Percentiles de Asignación de Aulas Físicas</h5>
|
||||
<small class="text-muted">Balance de capacidad instalada en Edificio Central (Total: {{ stats.physical_classrooms }} aulas físicas)</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex gap-2 align-items-center flex-wrap">
|
||||
<span class="badge bg-success-subtle text-success border border-success-subtle px-2 py-1">
|
||||
<i class="bi bi-check2-circle me-1"></i>{{ stats.assigned_classrooms }} Asignadas ({{ stats.assigned_classrooms_pct }}%)
|
||||
</span>
|
||||
<span class="badge bg-warning-subtle text-warning-emphasis border border-warning-subtle px-2 py-1">
|
||||
<i class="bi bi-door-open me-1"></i>{{ stats.unassigned_classrooms }} Sin Asignar ({{ stats.unassigned_classrooms_pct }}%)
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body p-3">
|
||||
<div class="row g-3 align-items-center">
|
||||
<!-- Tarjeta 1: Asignadas -->
|
||||
<div class="col-md-3">
|
||||
<a href="/classrooms/list_classrooms?view_mode=physical" class="text-decoration-none text-reset d-block h-100">
|
||||
<div class="p-3 rounded bg-success bg-opacity-10 border border-success-subtle h-100 text-center transition-all">
|
||||
<div class="d-flex justify-content-between align-items-center mb-1">
|
||||
<span class="text-success small fw-bold text-uppercase">Aulas Asignadas</span>
|
||||
<span class="badge bg-success text-white font-monospace">{{ stats.assigned_classrooms_pct }}%</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-baseline justify-content-center gap-2 my-2">
|
||||
<h2 class="mb-0 fw-bold text-success">{{ stats.assigned_classrooms }}</h2>
|
||||
<span class="text-muted small">/ {{ stats.physical_classrooms }} aulas</span>
|
||||
</div>
|
||||
<div class="text-success small pt-2 border-top border-success-subtle d-flex align-items-center justify-content-between">
|
||||
<span>Con cursadas activas</span>
|
||||
<i class="bi bi-arrow-right"></i>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Tarjeta 2: Sin Asignar -->
|
||||
<div class="col-md-3">
|
||||
<a href="/classrooms/list_classrooms?view_mode=physical" class="text-decoration-none text-reset d-block h-100">
|
||||
<div class="p-3 rounded bg-warning bg-opacity-10 border border-warning-subtle h-100 text-center transition-all">
|
||||
<div class="d-flex justify-content-between align-items-center mb-1">
|
||||
<span class="text-warning-emphasis small fw-bold text-uppercase">Aulas Sin Asignar</span>
|
||||
<span class="badge bg-warning text-dark font-monospace">{{ stats.unassigned_classrooms_pct }}%</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-baseline justify-content-center gap-2 my-2">
|
||||
<h2 class="mb-0 fw-bold text-warning-emphasis">{{ stats.unassigned_classrooms }}</h2>
|
||||
<span class="text-muted small">/ {{ stats.physical_classrooms }} aulas</span>
|
||||
</div>
|
||||
<div class="text-warning-emphasis small pt-2 border-top border-warning-subtle d-flex align-items-center justify-content-between">
|
||||
<span>Espacios disponibles</span>
|
||||
<i class="bi bi-arrow-right"></i>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Tarjeta 3: Barras Comparativas de Percentil (Cuatrimestre y Hoy) -->
|
||||
<div class="col-md-6">
|
||||
<div class="p-3 rounded bg-body-tertiary border h-100 d-flex flex-column justify-content-center">
|
||||
<!-- Nivel 1: Cuatrimestre -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-1">
|
||||
<span class="small fw-semibold text-body">
|
||||
<i class="bi bi-calendar-check me-1 text-primary"></i>Planificación Cuatrimestral:
|
||||
</span>
|
||||
<span class="small font-monospace text-muted">
|
||||
<strong class="text-success">{{ stats.assigned_classrooms_pct }}%</strong> Asignado ({{ stats.assigned_classrooms }} aulas) · <strong class="text-warning-emphasis">{{ stats.unassigned_classrooms_pct }}%</strong> Libre ({{ stats.unassigned_classrooms }} aula)
|
||||
</span>
|
||||
</div>
|
||||
<div class="progress mb-3" style="height: 14px;">
|
||||
<div class="progress-bar bg-success progress-bar-striped" role="progressbar" style="width: {{ stats.assigned_classrooms_pct }}%;"
|
||||
aria-valuenow="{{ stats.assigned_classrooms_pct }}" aria-valuemin="0" aria-valuemax="100"
|
||||
title="Asignadas: {{ stats.assigned_classrooms }} ({{ stats.assigned_classrooms_pct }}%)">
|
||||
{{ stats.assigned_classrooms_pct }}%
|
||||
</div>
|
||||
<div class="progress-bar bg-warning" role="progressbar" style="width: {{ stats.unassigned_classrooms_pct }}%;"
|
||||
aria-valuenow="{{ stats.unassigned_classrooms_pct }}" aria-valuemin="0" aria-valuemax="100"
|
||||
title="Sin Asignar: {{ stats.unassigned_classrooms }} ({{ stats.unassigned_classrooms_pct }}%)">
|
||||
{{ stats.unassigned_classrooms_pct }}%
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Nivel 2: Día Operativo -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-1">
|
||||
<span class="small fw-semibold text-body">
|
||||
<i class="bi bi-clock-history me-1 text-info"></i>Ocupación Operativa de Hoy:
|
||||
</span>
|
||||
<span class="small font-monospace text-muted">
|
||||
<strong class="text-info">{{ stats.assigned_today_classrooms }}</strong> en uso ({{ stats.assigned_today_pct }}%) · <strong class="text-secondary">{{ stats.unassigned_today_classrooms }}</strong> libres ({{ stats.unassigned_today_pct }}%)
|
||||
</span>
|
||||
</div>
|
||||
<div class="progress" style="height: 10px;">
|
||||
<div class="progress-bar bg-info" role="progressbar" style="width: {{ stats.assigned_today_pct }}%;"
|
||||
aria-valuenow="{{ stats.assigned_today_pct }}" aria-valuemin="0" aria-valuemax="100"
|
||||
title="En uso hoy: {{ stats.assigned_today_classrooms }}">
|
||||
</div>
|
||||
<div class="progress-bar bg-secondary-subtle" role="progressbar" style="width: {{ stats.unassigned_today_pct }}%;"
|
||||
aria-valuenow="{{ stats.unassigned_today_pct }}" aria-valuemin="0" aria-valuemax="100"
|
||||
title="Libres hoy: {{ stats.unassigned_today_classrooms }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Admin Visual Menu Launchpad -->
|
||||
<div class="card border-0 shadow-sm mb-4">
|
||||
<div class="card-header bg-body-tertiary border-0 py-3">
|
||||
@@ -411,6 +522,117 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Panel de Balance y Percentiles de Asignación de Aulas (Bedelía) -->
|
||||
<div class="card border-0 shadow-sm mb-4">
|
||||
<div class="card-header bg-body-tertiary border-0 py-3 d-flex justify-content-between align-items-center flex-wrap gap-2">
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
<i class="bi bi-pie-chart-fill text-warning fs-5"></i>
|
||||
<div>
|
||||
<h5 class="mb-0 h6 fw-bold">Gestión y Percentiles de Asignación de Aulas (Bedelía)</h5>
|
||||
<small class="text-muted">Control de asignación de espacios físicos (Total: {{ stats.physical_classrooms }} aulas físicas en Sede Central)</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex gap-2 align-items-center flex-wrap">
|
||||
<span class="badge bg-success-subtle text-success border border-success-subtle px-2 py-1">
|
||||
<i class="bi bi-check2-circle me-1"></i>{{ stats.assigned_classrooms }} Asignadas ({{ stats.assigned_classrooms_pct }}%)
|
||||
</span>
|
||||
<span class="badge bg-warning-subtle text-warning-emphasis border border-warning-subtle px-2 py-1">
|
||||
<i class="bi bi-door-open me-1"></i>{{ stats.unassigned_classrooms }} Sin Asignar ({{ stats.unassigned_classrooms_pct }}%)
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body p-3">
|
||||
<div class="row g-3 align-items-center">
|
||||
<!-- Tarjeta 1: Asignadas -->
|
||||
<div class="col-md-3">
|
||||
<a href="/classrooms/list_classrooms?view_mode=physical" class="text-decoration-none text-reset d-block h-100">
|
||||
<div class="p-3 rounded bg-success bg-opacity-10 border border-success-subtle h-100 text-center transition-all">
|
||||
<div class="d-flex justify-content-between align-items-center mb-1">
|
||||
<span class="text-success small fw-bold text-uppercase">Aulas Asignadas</span>
|
||||
<span class="badge bg-success text-white font-monospace">{{ stats.assigned_classrooms_pct }}%</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-baseline justify-content-center gap-2 my-2">
|
||||
<h2 class="mb-0 fw-bold text-success">{{ stats.assigned_classrooms }}</h2>
|
||||
<span class="text-muted small">/ {{ stats.physical_classrooms }} aulas</span>
|
||||
</div>
|
||||
<div class="text-success small pt-2 border-top border-success-subtle d-flex align-items-center justify-content-between">
|
||||
<span>Ver aulas con cursada</span>
|
||||
<i class="bi bi-arrow-right"></i>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Tarjeta 2: Sin Asignar -->
|
||||
<div class="col-md-3">
|
||||
<a href="/schedule/add_reservation" class="text-decoration-none text-reset d-block h-100">
|
||||
<div class="p-3 rounded bg-warning bg-opacity-10 border border-warning-subtle h-100 text-center transition-all">
|
||||
<div class="d-flex justify-content-between align-items-center mb-1">
|
||||
<span class="text-warning-emphasis small fw-bold text-uppercase">Aulas Sin Asignar</span>
|
||||
<span class="badge bg-warning text-dark font-monospace">{{ stats.unassigned_classrooms_pct }}%</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-baseline justify-content-center gap-2 my-2">
|
||||
<h2 class="mb-0 fw-bold text-warning-emphasis">{{ stats.unassigned_classrooms }}</h2>
|
||||
<span class="text-muted small">/ {{ stats.physical_classrooms }} aulas</span>
|
||||
</div>
|
||||
<div class="text-warning-emphasis small pt-2 border-top border-warning-subtle d-flex align-items-center justify-content-between">
|
||||
<span>Asignar espacio libre</span>
|
||||
<i class="bi bi-plus-circle"></i>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Tarjeta 3: Barras Comparativas de Percentil (Cuatrimestre y Hoy) -->
|
||||
<div class="col-md-6">
|
||||
<div class="p-3 rounded bg-body-tertiary border h-100 d-flex flex-column justify-content-center">
|
||||
<!-- Nivel 1: Cuatrimestre -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-1">
|
||||
<span class="small fw-semibold text-body">
|
||||
<i class="bi bi-calendar-check me-1 text-primary"></i>Asignación Cuatrimestral:
|
||||
</span>
|
||||
<span class="small font-monospace text-muted">
|
||||
<strong class="text-success">{{ stats.assigned_classrooms_pct }}%</strong> Asignado ({{ stats.assigned_classrooms }} aulas) · <strong class="text-warning-emphasis">{{ stats.unassigned_classrooms_pct }}%</strong> Disponible ({{ stats.unassigned_classrooms }} aula)
|
||||
</span>
|
||||
</div>
|
||||
<div class="progress mb-3" style="height: 14px;">
|
||||
<div class="progress-bar bg-success progress-bar-striped" role="progressbar" style="width: {{ stats.assigned_classrooms_pct }}%;"
|
||||
aria-valuenow="{{ stats.assigned_classrooms_pct }}" aria-valuemin="0" aria-valuemax="100"
|
||||
title="Asignadas: {{ stats.assigned_classrooms }} ({{ stats.assigned_classrooms_pct }}%)">
|
||||
{{ stats.assigned_classrooms_pct }}%
|
||||
</div>
|
||||
<div class="progress-bar bg-warning" role="progressbar" style="width: {{ stats.unassigned_classrooms_pct }}%;"
|
||||
aria-valuenow="{{ stats.unassigned_classrooms_pct }}" aria-valuemin="0" aria-valuemax="100"
|
||||
title="Sin Asignar: {{ stats.unassigned_classrooms }} ({{ stats.unassigned_classrooms_pct }}%)">
|
||||
{{ stats.unassigned_classrooms_pct }}%
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Nivel 2: Día Operativo -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-1">
|
||||
<span class="small fw-semibold text-body">
|
||||
<i class="bi bi-clock-history me-1 text-info"></i>Ocupación Operativa de Hoy:
|
||||
</span>
|
||||
<span class="small font-monospace text-muted">
|
||||
<strong class="text-info">{{ stats.assigned_today_classrooms }}</strong> en uso ({{ stats.assigned_today_pct }}%) · <strong class="text-secondary">{{ stats.unassigned_today_classrooms }}</strong> libres ({{ stats.unassigned_today_pct }}%)
|
||||
</span>
|
||||
</div>
|
||||
<div class="progress" style="height: 10px;">
|
||||
<div class="progress-bar bg-info" role="progressbar" style="width: {{ stats.assigned_today_pct }}%;"
|
||||
aria-valuenow="{{ stats.assigned_today_pct }}" aria-valuemin="0" aria-valuemax="100"
|
||||
title="En uso hoy: {{ stats.assigned_today_classrooms }}">
|
||||
</div>
|
||||
<div class="progress-bar bg-secondary-subtle" role="progressbar" style="width: {{ stats.unassigned_today_pct }}%;"
|
||||
aria-valuenow="{{ stats.unassigned_today_pct }}" aria-valuemin="0" aria-valuemax="100"
|
||||
title="Libres hoy: {{ stats.unassigned_today_classrooms }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bedelía Operational Launchpad -->
|
||||
<div class="card border-0 shadow-sm mb-4">
|
||||
<div class="card-header bg-body-tertiary border-0 py-3">
|
||||
@@ -537,7 +759,7 @@
|
||||
|
||||
<!-- Docente KPI Cards -->
|
||||
<div class="row mb-4 g-3">
|
||||
<div class="col-md-6 col-xl-3">
|
||||
<div class="col-md-4 col-xl-4">
|
||||
<div class="card border-0 shadow-sm h-100 dashboard-stat-card transition-all glass-card">
|
||||
<div class="card-body p-3">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
@@ -557,7 +779,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 col-xl-3">
|
||||
<div class="col-md-4 col-xl-4">
|
||||
<a href="/schedule/list_reservations" class="text-decoration-none text-reset d-block h-100">
|
||||
<div class="card border-0 shadow-sm h-100 dashboard-stat-card transition-all glass-card">
|
||||
<div class="card-body p-3">
|
||||
@@ -579,8 +801,8 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 col-xl-3">
|
||||
<a href="/classrooms/list_classrooms" class="text-decoration-none text-reset d-block h-100">
|
||||
<div class="col-md-4 col-xl-4">
|
||||
<a href="/classrooms/list_classrooms?view_mode=virtual" class="text-decoration-none text-reset d-block h-100">
|
||||
<div class="card border-0 shadow-sm h-100 dashboard-stat-card transition-all glass-card">
|
||||
<div class="card-body p-3">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
@@ -600,28 +822,6 @@
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 col-xl-3">
|
||||
<a href="/schedule/add_reservation" class="text-decoration-none text-reset d-block h-100">
|
||||
<div class="card border-0 shadow-sm h-100 dashboard-stat-card transition-all bg-primary bg-opacity-10 border border-primary-subtle">
|
||||
<div class="card-body p-3">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<span class="text-primary small fw-bold text-uppercase">Nueva Solicitud</span>
|
||||
<h4 class="mb-0 fw-bold mt-1 text-primary">Reservar Aula</h4>
|
||||
</div>
|
||||
<div class="bg-primary text-white rounded-circle p-3">
|
||||
<i class="bi bi-plus-lg fs-3"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-center justify-content-between pt-3 mt-2 border-top text-primary small fw-bold">
|
||||
<span>Solicitar espacio para clase</span>
|
||||
<i class="bi bi-arrow-right"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Docente Launchpad -->
|
||||
|
||||
Reference in New Issue
Block a user