200 lines
7.8 KiB
PHP
200 lines
7.8 KiB
PHP
<?php
|
|
/**
|
|
* index.php — Página de reportes y respaldo
|
|
*/
|
|
require_once __DIR__ . '/../../config/config.php';
|
|
require_once __DIR__ . '/../../controllers/AuthController.php';
|
|
require_once __DIR__ . '/../../models/Oficio.php';
|
|
|
|
AuthController::requerirAuth();
|
|
$esAdmin = AuthController::esAdmin();
|
|
$model = new OficioModel();
|
|
|
|
// Datos para el reporte
|
|
$db = getDB();
|
|
$resumenEstados = $db->query(
|
|
"SELECT estado, COUNT(*) as total FROM oficios WHERE deleted_at IS NULL GROUP BY estado"
|
|
)->fetchAll();
|
|
|
|
$resumenResponsables = $db->query(
|
|
"SELECT CONCAT(u.nombre,' ',u.apellido) AS nombre, COUNT(o.id) AS total,
|
|
SUM(CASE WHEN o.estado='respondido' THEN 1 ELSE 0 END) AS respondidos,
|
|
SUM(CASE WHEN o.estado NOT IN('respondido','archivado') AND o.fecha_vencimiento < CURDATE() THEN 1 ELSE 0 END) AS vencidos
|
|
FROM oficios o JOIN usuarios u ON u.id=o.responsable_id
|
|
WHERE o.deleted_at IS NULL GROUP BY o.responsable_id
|
|
ORDER BY total DESC LIMIT 10"
|
|
)->fetchAll();
|
|
|
|
$pageTitle = 'Reportes y Respaldo';
|
|
$activeNav = 'reportes';
|
|
|
|
include __DIR__ . '/../../views/layout/header.php';
|
|
include __DIR__ . '/../../views/layout/sidebar.php';
|
|
include __DIR__ . '/../../views/layout/topbar.php';
|
|
?>
|
|
<div class="page-content">
|
|
|
|
<div class="breadcrumb">
|
|
<a href="<?= APP_URL ?>/dashboard.php"><i class="fa-solid fa-house"></i></a>
|
|
<i class="fa-solid fa-chevron-right sep"></i>
|
|
<span>Reportes</span>
|
|
</div>
|
|
|
|
<div class="page-header">
|
|
<div class="page-header-content">
|
|
<h1>Reportes y Respaldo</h1>
|
|
<p>Exportación de datos, informes en PDF y respaldo de base de datos</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid-3 mb-4">
|
|
|
|
<!-- Reporte PDF general -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<i class="fa-solid fa-file-pdf text-danger"></i>
|
|
<span class="card-title">Reporte de Oficios (PDF)</span>
|
|
</div>
|
|
<div class="card-body">
|
|
<p style="font-size:.83rem;color:var(--text-muted);margin-bottom:1rem">
|
|
Genera un informe completo de todos los oficios con filtros aplicados, en formato PDF.
|
|
</p>
|
|
<form method="GET" action="<?= APP_URL ?>/controllers/ReporteController.php" target="_blank">
|
|
<input type="hidden" name="action" value="pdf_listado">
|
|
<div class="form-group">
|
|
<label class="form-label">Mes</label>
|
|
<input type="month" class="form-control" name="mes" value="<?= date('Y-m') ?>">
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">Estado</label>
|
|
<select class="form-control" name="estado">
|
|
<option value="">Todos</option>
|
|
<option value="recibido">Recibido</option>
|
|
<option value="en_proceso">En Proceso</option>
|
|
<option value="respondido">Respondido</option>
|
|
<option value="vencido">Vencido</option>
|
|
</select>
|
|
</div>
|
|
<button type="submit" class="btn btn-danger w-100">
|
|
<i class="fa-solid fa-file-pdf"></i> Generar PDF
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Exportar Excel/CSV -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<i class="fa-solid fa-file-excel text-success"></i>
|
|
<span class="card-title">Exportar a Excel/CSV</span>
|
|
</div>
|
|
<div class="card-body">
|
|
<p style="font-size:.83rem;color:var(--text-muted);margin-bottom:1rem">
|
|
Descarga los oficios en formato Excel o CSV para análisis externo.
|
|
</p>
|
|
<div class="d-flex gap-2 flex-wrap">
|
|
<a href="<?= APP_URL ?>/controllers/ReporteController.php?action=export_csv" class="btn btn-success w-100 mb-2">
|
|
<i class="fa-solid fa-file-csv"></i> Descargar CSV
|
|
</a>
|
|
<a href="<?= APP_URL ?>/controllers/ReporteController.php?action=export_excel" class="btn btn-success w-100">
|
|
<i class="fa-solid fa-file-excel"></i> Descargar Excel
|
|
</a>
|
|
</div>
|
|
<p style="font-size:.75rem;color:var(--text-muted);margin-top:.75rem">
|
|
<i class="fa-solid fa-upload"></i>
|
|
<a href="<?= APP_URL ?>/views/reportes/carga_masiva.php" style="color:var(--primary)">
|
|
Cargar masiva de oficios (Excel/CSV)
|
|
</a>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Respaldo de BD (solo admin) -->
|
|
<?php if ($esAdmin): ?>
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<i class="fa-solid fa-database text-primary"></i>
|
|
<span class="card-title">Respaldo Base de Datos</span>
|
|
</div>
|
|
<div class="card-body">
|
|
<p style="font-size:.83rem;color:var(--text-muted);margin-bottom:1rem">
|
|
Descarga un respaldo completo de la base de datos en formato SQL.
|
|
</p>
|
|
<a href="<?= APP_URL ?>/controllers/ReporteController.php?action=backup_sql"
|
|
class="btn btn-primary w-100"
|
|
data-confirm="¿Generar respaldo de la base de datos? Puede tomar unos segundos.">
|
|
<i class="fa-solid fa-download"></i> Descargar Respaldo SQL
|
|
</a>
|
|
<div class="alert alert-warning" style="margin-top:1rem;font-size:.78rem;padding:.625rem">
|
|
<i class="fa-solid fa-triangle-exclamation"></i>
|
|
Guarde el respaldo en un lugar seguro. Contiene datos sensibles.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
</div>
|
|
|
|
<!-- Resumen por estado -->
|
|
<div class="grid-2 mb-4">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<i class="fa-solid fa-chart-pie text-primary"></i>
|
|
<span class="card-title">Resumen por Estado</span>
|
|
</div>
|
|
<div class="card-body" style="padding:0">
|
|
<table class="table">
|
|
<thead><tr><th>Estado</th><th>Total</th><th>%</th></tr></thead>
|
|
<tbody>
|
|
<?php
|
|
$total_gral = array_sum(array_column($resumenEstados, 'total'));
|
|
$badgeClass = ['recibido'=>'badge-primary','en_proceso'=>'badge-warning','respondido'=>'badge-success','vencido'=>'badge-danger','archivado'=>'badge-secondary'];
|
|
foreach ($resumenEstados as $r):
|
|
$pct = $total_gral > 0 ? round($r['total']/$total_gral*100,1) : 0;
|
|
?>
|
|
<tr>
|
|
<td><span class="badge <?= $badgeClass[$r['estado']]??'badge-secondary' ?>"><?= ucfirst(str_replace('_',' ',$r['estado'])) ?></span></td>
|
|
<td class="fw-600"><?= $r['total'] ?></td>
|
|
<td>
|
|
<div style="display:flex;align-items:center;gap:.5rem">
|
|
<div style="flex:1;height:6px;background:var(--border);border-radius:99px;overflow:hidden">
|
|
<div style="width:<?= $pct ?>%;height:100%;background:var(--primary);border-radius:99px"></div>
|
|
</div>
|
|
<?= $pct ?>%
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Rendimiento por responsable -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<i class="fa-solid fa-users text-primary"></i>
|
|
<span class="card-title">Rendimiento por Responsable</span>
|
|
</div>
|
|
<div class="card-body" style="padding:0">
|
|
<table class="table">
|
|
<thead><tr><th>Responsable</th><th>Total</th><th>Respondidos</th><th>Vencidos</th></tr></thead>
|
|
<tbody>
|
|
<?php foreach ($resumenResponsables as $r): ?>
|
|
<tr>
|
|
<td class="fw-600"><?= htmlspecialchars($r['nombre']) ?></td>
|
|
<td><?= $r['total'] ?></td>
|
|
<td><span class="badge badge-success"><?= $r['respondidos'] ?></span></td>
|
|
<td><?= $r['vencidos'] > 0 ? "<span class='badge badge-danger'>{$r['vencidos']}</span>" : '<span class="badge badge-secondary">0</span>' ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<?php include __DIR__ . '/../../views/layout/footer.php'; ?>
|