Files

223 lines
8.6 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\Docente;
use App\Models\Evaluacion;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Http;
class EvaluacionReporteController extends Controller
{
public function show(Evaluacion $evaluacion)
{
$datos = $this->buildDatos($evaluacion);
$totalSubmissions = $evaluacion->submissions()->count();
return view('evaluacion.reporte', compact('evaluacion', 'datos', 'totalSubmissions'));
}
public function pdf(Evaluacion $evaluacion)
{
$datos = $this->buildDatos($evaluacion);
$totalSubmissions = $evaluacion->submissions()->count();
// Fetch chart images from QuickChart and embed as base64
foreach ($datos as &$item) {
if ($item['tipo'] === 'texto_libre') continue;
if ($item['es_docente']) {
foreach ($item['por_docente'] as &$pd) {
if (isset($pd['chart_config'])) {
$pd['chart_img'] = $this->fetchChartBase64($pd['chart_config']);
}
}
} else {
if (isset($item['chart_config'])) {
$item['chart_img'] = $this->fetchChartBase64($item['chart_config']);
}
}
}
$pdf = Pdf::loadView('evaluacion.reporte_pdf', compact('evaluacion', 'datos', 'totalSubmissions'))
->setPaper('a4', 'portrait');
return $pdf->download('reporte-' . $evaluacion->id . '.pdf');
}
// ─── Data builder ───────────────────────────────────────────────────────────
private function buildDatos(Evaluacion $evaluacion): array
{
$preguntas = $evaluacion->preguntas()
->with(['tipo', 'opciones', 'respuestas.opcion'])
->get();
$datos = [];
foreach ($preguntas as $pregunta) {
$tipoSlug = $pregunta->tipo->slug;
$respuestas = $pregunta->respuestas;
if ($pregunta->es_docente) {
$docenteIds = $respuestas->pluck('docente_id')->unique()->filter();
$porDocente = [];
foreach ($docenteIds as $docenteId) {
$rsp = $respuestas->where('docente_id', $docenteId);
$docente = Docente::with('docentes')->find($docenteId);
$user = $docente?->docentes->first();
$nombre = $user
? trim("{$user->apellidoPaterno} {$user->apellidoMaterno} {$user->name}")
: "Docente #{$docenteId}";
$chart = $this->procesarRespuestas($rsp, $tipoSlug, $pregunta);
$porDocente[] = [
'docente_nombre' => $nombre,
'chart_config' => $chart['config'] ?? null,
'textos' => $chart['textos'] ?? [],
'promedio' => $chart['promedio'] ?? null,
'total' => $rsp->count(),
];
}
$datos[] = [
'pregunta' => $pregunta,
'tipo' => $tipoSlug,
'es_docente' => true,
'por_docente' => $porDocente,
];
} else {
$chart = $this->procesarRespuestas($respuestas, $tipoSlug, $pregunta);
$datos[] = [
'pregunta' => $pregunta,
'tipo' => $tipoSlug,
'es_docente' => false,
'chart_config' => $chart['config'] ?? null,
'textos' => $chart['textos'] ?? [],
'promedio' => $chart['promedio'] ?? null,
'total' => $respuestas->count(),
];
}
}
return $datos;
}
private function procesarRespuestas($respuestas, string $tipoSlug, $pregunta): array
{
switch ($tipoSlug) {
case 'si_no':
$si = $respuestas->where('valor', 'si')->count();
$no = $respuestas->where('valor', 'no')->count();
return ['config' => [
'type' => 'doughnut',
'data' => [
'labels' => ['Sí', 'No'],
'datasets' => [[
'data' => [$si, $no],
'backgroundColor' => ['#1cc88a', '#e74a3b'],
'borderWidth' => 2,
]],
],
'options' => [
'plugins' => [
'legend' => ['position' => 'bottom'],
'datalabels' => ['display' => false],
],
],
]];
case 'opcion_multiple':
$labels = [];
$counts = [];
$colors = ['#4e73df','#1cc88a','#36b9cc','#f6c23e','#e74a3b','#858796','#5a5c69'];
foreach ($pregunta->opciones as $idx => $opcion) {
$labels[] = $opcion->texto;
$counts[] = $respuestas->where('opcion_id', $opcion->id)->count();
}
return ['config' => [
'type' => 'bar',
'data' => [
'labels' => $labels,
'datasets' => [[
'label' => 'Respuestas',
'data' => $counts,
'backgroundColor' => array_slice(array_merge($colors, $colors), 0, count($labels)),
'borderRadius' => 4,
]],
],
'options' => [
'plugins' => ['legend' => ['display' => false]],
'scales' => ['y' => ['beginAtZero' => true, 'ticks' => ['stepSize' => 1]]],
],
]];
case 'escala_5':
case 'escala_10':
$max = $tipoSlug === 'escala_5' ? 5 : 10;
$labels = range(1, $max);
$counts = [];
foreach ($labels as $val) {
$counts[] = $respuestas->filter(fn($r) => (int)$r->valor === $val)->count();
}
$total = $respuestas->count();
$suma = $respuestas->sum(fn($r) => (int)$r->valor);
$prom = $total > 0 ? round($suma / $total, 2) : null;
return [
'config' => [
'type' => 'bar',
'data' => [
'labels' => $labels,
'datasets' => [[
'label' => 'Respuestas',
'data' => $counts,
'backgroundColor' => '#36b9cc',
'borderRadius' => 4,
]],
],
'options' => [
'plugins' => ['legend' => ['display' => false]],
'scales' => ['y' => ['beginAtZero' => true, 'ticks' => ['stepSize' => 1]]],
],
],
'promedio' => $prom,
];
case 'texto_libre':
return ['textos' => $respuestas->pluck('valor')->filter()->values()->toArray()];
default:
return [];
}
}
// ─── QuickChart helper ───────────────────────────────────────────────────────
private function fetchChartBase64(array $config): ?string
{
try {
$response = Http::timeout(15)->post('https://quickchart.io/chart', [
'chart' => $config,
'width' => 500,
'height' => 280,
'backgroundColor' => 'white',
'format' => 'png',
]);
if ($response->successful()) {
return 'data:image/png;base64,' . base64_encode($response->body());
}
} catch (\Throwable) {
// QuickChart no disponible; la imagen simplemente no aparece
}
return null;
}
}