Modificación del de vista de dopcumentos del alumno
This commit is contained in:
@@ -18,7 +18,9 @@
|
||||
"Bash(php -l app/Http/Controllers/GrupoController.php)",
|
||||
"Bash(php -l app/Models/Tarea.php)",
|
||||
"Bash(php -l app/Models/Entrega.php)",
|
||||
"Bash(php -l app/Livewire/GrupoDocente.php)"
|
||||
"Bash(php -l app/Livewire/GrupoDocente.php)",
|
||||
"Bash(composer require *)",
|
||||
"Bash(Select-String -Pattern \"entrega|Entrega\" -Context 0,0)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,9 +51,7 @@ class AlumnoController extends Controller
|
||||
|
||||
})
|
||||
->get();
|
||||
}
|
||||
|
||||
if ($user->hasRole('Control escolar')) {
|
||||
}else{
|
||||
$plantelesUsuario = $user->plantelUsuarios->pluck('id');
|
||||
|
||||
$alumnos = Alumno::with(['alumnos.plantelUsuarios','statusAlumno'])
|
||||
@@ -65,6 +63,8 @@ class AlumnoController extends Controller
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return view('alumno.index', compact('alumnos'));
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ use App\Models\Tarea;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class EntregaController extends Controller
|
||||
{
|
||||
@@ -25,12 +26,23 @@ class EntregaController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
$cicloActual = Campan::where('status', 1)->first();
|
||||
// Ciclo más alto del alumno = semestre en curso
|
||||
$maxCiclo = DB::table('alumno_grupo')
|
||||
->join('grupos', 'grupos.id', '=', 'alumno_grupo.grupo_id')
|
||||
->where('alumno_grupo.alumno_id', $alumno->id)
|
||||
->max('grupos.ciclo');
|
||||
|
||||
// Solo grupos del ciclo activo
|
||||
$gruposActuales = $alumno->grupos()
|
||||
->when($cicloActual, fn($q) => $q->where('ciclo', $cicloActual->id))
|
||||
->pluck('grupos.id');
|
||||
// Campan para mostrar el nombre en la vista (busca por id = ciclo, o cae al activo)
|
||||
$cicloActual = $maxCiclo ? Campan::find($maxCiclo) ?? Campan::where('status', 1)->first() : null;
|
||||
|
||||
// Grupos del alumno en ese ciclo
|
||||
$gruposActuales = $maxCiclo
|
||||
? DB::table('alumno_grupo')
|
||||
->join('grupos', 'grupos.id', '=', 'alumno_grupo.grupo_id')
|
||||
->where('alumno_grupo.alumno_id', $alumno->id)
|
||||
->where('grupos.ciclo', $maxCiclo)
|
||||
->pluck('alumno_grupo.grupo_id')
|
||||
: collect();
|
||||
|
||||
$todasTareas = Tarea::whereIn('grupo_id', $gruposActuales)
|
||||
->with(['material', 'grupo'])
|
||||
@@ -59,15 +71,21 @@ class EntregaController extends Controller
|
||||
public function store(Request $request, Tarea $tarea)
|
||||
{
|
||||
$request->validate([
|
||||
'archivo' => 'nullable|file|max:20480',
|
||||
'archivo' => 'nullable|file|max:2048',
|
||||
'texto' => 'nullable|string|max:5000',
|
||||
]);
|
||||
|
||||
if (!$request->hasFile('archivo') && !filled($request->texto)) {
|
||||
return back()->withErrors(['entrega' => 'Debes escribir un texto o adjuntar un archivo.']);
|
||||
return redirect()->route('mis.tareas')
|
||||
->withErrors(['entrega' => 'Debes escribir un texto o adjuntar un archivo.']);
|
||||
}
|
||||
|
||||
$alumno = Alumno::whereHas('alumnos', fn($q) => $q->where('id', Auth::id()))->firstOrFail();
|
||||
$alumno = Alumno::whereHas('alumnos', fn($q) => $q->where('id', Auth::id()))->first();
|
||||
|
||||
if (!$alumno) {
|
||||
return redirect()->route('mis.tareas')
|
||||
->with('error', 'No se encontró un perfil de alumno para tu cuenta.');
|
||||
}
|
||||
|
||||
$entrega = Entrega::where('tarea_id', $tarea->id)
|
||||
->where('alumno_id', $alumno->id)
|
||||
@@ -82,12 +100,12 @@ class EntregaController extends Controller
|
||||
}
|
||||
|
||||
if ($entrega->status !== 'sin_subir') {
|
||||
return back()->with('error', 'Ya entregaste esta tarea y no puedes volver a subirla.');
|
||||
return redirect()->route('mis.tareas')
|
||||
->with('error', 'Ya entregaste esta tarea y no puedes volver a subirla.');
|
||||
}
|
||||
|
||||
$path = null;
|
||||
$path = $entrega->archivo;
|
||||
if ($request->hasFile('archivo')) {
|
||||
// Almacena en disco local (privado) igual que el FileController espera
|
||||
$path = $request->file('archivo')->store("entregas/{$tarea->id}");
|
||||
}
|
||||
|
||||
@@ -97,6 +115,7 @@ class EntregaController extends Controller
|
||||
'status' => 'pendiente',
|
||||
]);
|
||||
|
||||
return back()->with('info', 'Tarea enviada correctamente. Queda pendiente de calificación.');
|
||||
return redirect()->route('mis.tareas')
|
||||
->with('info', 'Tarea enviada correctamente. Queda pendiente de calificación.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
@@ -98,14 +98,37 @@ class EvaluacionResponderController extends Controller
|
||||
if ($tipoSlug === 'alumno' && $preguntas->where('es_docente', true)->count() > 0) {
|
||||
$alumno = Alumno::whereHas('alumnos', fn($q) => $q->where('id', Auth::id()))->first();
|
||||
if ($alumno) {
|
||||
$gruposIds = $alumno->grupos()->pluck('grupos.id');
|
||||
$docentesParaEvaluar = Docente::whereHas('grupos', fn($q) => $q->whereIn('grupos.id', $gruposIds))
|
||||
// Ciclo más alto del alumno = semestre actual
|
||||
$cicloActual = DB::table('alumno_grupo')
|
||||
->join('grupos', 'grupos.id', '=', 'alumno_grupo.grupo_id')
|
||||
->where('alumno_grupo.alumno_id', $alumno->id)
|
||||
->max('grupos.ciclo');
|
||||
|
||||
if ($cicloActual) {
|
||||
// Grupos del alumno en ese ciclo
|
||||
$gruposIds = DB::table('alumno_grupo')
|
||||
->join('grupos', 'grupos.id', '=', 'alumno_grupo.grupo_id')
|
||||
->where('alumno_grupo.alumno_id', $alumno->id)
|
||||
->where('grupos.ciclo', $cicloActual)
|
||||
->pluck('alumno_grupo.grupo_id')
|
||||
->toArray();
|
||||
|
||||
// Docentes asignados a esos grupos cuya materia tenga el mismo ciclo que el grupo
|
||||
$docenteIds = DB::table('docente_grupo')
|
||||
->join('materials', 'materials.id', '=', 'docente_grupo.materia_id')
|
||||
->whereIn('docente_grupo.grupo_id', $gruposIds)
|
||||
->where('materials.ciclo', $cicloActual)
|
||||
->distinct()
|
||||
->pluck('docente_grupo.docente_id')
|
||||
->toArray();
|
||||
|
||||
$docentesParaEvaluar = Docente::whereIn('id', $docenteIds)
|
||||
->with('docentes')
|
||||
->get()
|
||||
->unique('id')
|
||||
->values();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return view('evaluacion.responder', compact(
|
||||
'evaluacion', 'preguntas', 'docentesParaEvaluar', 'tipoSlug', 'yaRespondida'
|
||||
|
||||
@@ -27,7 +27,7 @@ class GrupoController extends Controller
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
if ($user->hasRole('Admin')) {
|
||||
if ($user->hasRole('Administrador')) {
|
||||
$grupos = Grupo::all();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ProspectoController extends Controller
|
||||
{
|
||||
//
|
||||
}
|
||||
@@ -59,6 +59,22 @@ class GrupoDocente extends Component
|
||||
->get();
|
||||
}
|
||||
|
||||
private function refreshMateriasSelect(): void
|
||||
{
|
||||
$grupo = $this->grupo;
|
||||
$materiasAsignadas = DB::table('docente_grupo')
|
||||
->where('grupo_id', $grupo->id)
|
||||
->pluck('materia_id')
|
||||
->toArray();
|
||||
|
||||
$this->materiasSelect = Material::whereHas('carreraMaterial', function ($query) use ($grupo) {
|
||||
$query->where('carreras.id', $grupo->plan->carrera);
|
||||
})
|
||||
->where('ciclo', $grupo->ciclo)
|
||||
->when(!empty($materiasAsignadas), fn($q) => $q->whereNotIn('id', $materiasAsignadas))
|
||||
->get();
|
||||
}
|
||||
|
||||
public function guardar()
|
||||
{
|
||||
$this->validate([
|
||||
@@ -71,6 +87,7 @@ class GrupoDocente extends Component
|
||||
]);
|
||||
|
||||
$this->reset(['docente_id', 'materia_id']);
|
||||
$this->refreshMateriasSelect();
|
||||
$this->dispatch('close-modal-docente');
|
||||
$this->dispatch('swal',
|
||||
icon: 'success', title: '¡Listo!',
|
||||
@@ -96,6 +113,8 @@ class GrupoDocente extends Component
|
||||
|
||||
$this->grupo->docentes()->wherePivot('materia_id', $materiaId)->detach($docenteId);
|
||||
|
||||
$this->refreshMateriasSelect();
|
||||
|
||||
$this->dispatch('swal',
|
||||
icon: 'success', title: 'Eliminado',
|
||||
text: 'Docente y sus tareas removidos correctamente',
|
||||
|
||||
@@ -31,7 +31,7 @@ class Anuncio extends Model
|
||||
'all' => 'Todos',
|
||||
'Alumno' => 'Alumnos',
|
||||
'Docente' => 'Docentes',
|
||||
'Admin' => 'Administradores',
|
||||
'Administrador' => 'Administradores',
|
||||
'Control escolar' => 'Control escolar',
|
||||
'Coordinación académica' => 'Coordinación académica',
|
||||
'Programador' => 'Programadores',
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"barryvdh/laravel-dompdf": "^3.1",
|
||||
"laravel/cashier-paddle": "^2.6",
|
||||
"laravel/framework": "^12.0",
|
||||
"laravel/jetstream": "^5.4",
|
||||
|
||||
Generated
+523
-1
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "28550ccb2083e2f7896811098a56fc72",
|
||||
"content-hash": "a61dc0d9947c0fec7f5e1704c31eb732",
|
||||
"packages": [
|
||||
{
|
||||
"name": "bacon/bacon-qr-code",
|
||||
@@ -61,6 +61,83 @@
|
||||
},
|
||||
"time": "2025-11-19T17:15:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "barryvdh/laravel-dompdf",
|
||||
"version": "v3.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/barryvdh/laravel-dompdf.git",
|
||||
"reference": "ee3b72b19ccdf57d0243116ecb2b90261344dedc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/ee3b72b19ccdf57d0243116ecb2b90261344dedc",
|
||||
"reference": "ee3b72b19ccdf57d0243116ecb2b90261344dedc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"dompdf/dompdf": "^3.0",
|
||||
"illuminate/support": "^9|^10|^11|^12|^13.0",
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"larastan/larastan": "^2.7|^3.0",
|
||||
"orchestra/testbench": "^7|^8|^9.16|^10|^11.0",
|
||||
"phpro/grumphp": "^2.5",
|
||||
"squizlabs/php_codesniffer": "^3.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"aliases": {
|
||||
"PDF": "Barryvdh\\DomPDF\\Facade\\Pdf",
|
||||
"Pdf": "Barryvdh\\DomPDF\\Facade\\Pdf"
|
||||
},
|
||||
"providers": [
|
||||
"Barryvdh\\DomPDF\\ServiceProvider"
|
||||
]
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-master": "3.0-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Barryvdh\\DomPDF\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Barry vd. Heuvel",
|
||||
"email": "barryvdh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "A DOMPDF Wrapper for Laravel",
|
||||
"keywords": [
|
||||
"dompdf",
|
||||
"laravel",
|
||||
"pdf"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/barryvdh/laravel-dompdf/issues",
|
||||
"source": "https://github.com/barryvdh/laravel-dompdf/tree/v3.1.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://fruitcake.nl",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/barryvdh",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-21T08:51:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "brick/math",
|
||||
"version": "0.14.1",
|
||||
@@ -612,6 +689,161 @@
|
||||
],
|
||||
"time": "2024-02-05T11:56:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dompdf/dompdf",
|
||||
"version": "v3.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/dompdf/dompdf.git",
|
||||
"reference": "f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/dompdf/dompdf/zipball/f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496",
|
||||
"reference": "f11ead23a8a76d0ff9bbc6c7c8fd7e05ca328496",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"dompdf/php-font-lib": "^1.0.0",
|
||||
"dompdf/php-svg-lib": "^1.0.0",
|
||||
"ext-dom": "*",
|
||||
"ext-mbstring": "*",
|
||||
"masterminds/html5": "^2.0",
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-gd": "*",
|
||||
"ext-json": "*",
|
||||
"ext-zip": "*",
|
||||
"mockery/mockery": "^1.3",
|
||||
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11",
|
||||
"squizlabs/php_codesniffer": "^3.5",
|
||||
"symfony/process": "^4.4 || ^5.4 || ^6.2 || ^7.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-gd": "Needed to process images",
|
||||
"ext-gmagick": "Improves image processing performance",
|
||||
"ext-imagick": "Improves image processing performance",
|
||||
"ext-zlib": "Needed for pdf stream compression"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Dompdf\\": "src/"
|
||||
},
|
||||
"classmap": [
|
||||
"lib/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-2.1"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "The Dompdf Community",
|
||||
"homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md"
|
||||
}
|
||||
],
|
||||
"description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter",
|
||||
"homepage": "https://github.com/dompdf/dompdf",
|
||||
"support": {
|
||||
"issues": "https://github.com/dompdf/dompdf/issues",
|
||||
"source": "https://github.com/dompdf/dompdf/tree/v3.1.5"
|
||||
},
|
||||
"time": "2026-03-03T13:54:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dompdf/php-font-lib",
|
||||
"version": "1.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/dompdf/php-font-lib.git",
|
||||
"reference": "a6e9a688a2a80016ac080b97be73d3e10c444c9a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/a6e9a688a2a80016ac080b97be73d3e10c444c9a",
|
||||
"reference": "a6e9a688a2a80016ac080b97be73d3e10c444c9a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
"php": "^7.1 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11 || ^12"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"FontLib\\": "src/FontLib"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-2.1-or-later"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "The FontLib Community",
|
||||
"homepage": "https://github.com/dompdf/php-font-lib/blob/master/AUTHORS.md"
|
||||
}
|
||||
],
|
||||
"description": "A library to read, parse, export and make subsets of different types of font files.",
|
||||
"homepage": "https://github.com/dompdf/php-font-lib",
|
||||
"support": {
|
||||
"issues": "https://github.com/dompdf/php-font-lib/issues",
|
||||
"source": "https://github.com/dompdf/php-font-lib/tree/1.0.2"
|
||||
},
|
||||
"time": "2026-01-20T14:10:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dompdf/php-svg-lib",
|
||||
"version": "1.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/dompdf/php-svg-lib.git",
|
||||
"reference": "8259ffb930817e72b1ff1caef5d226501f3dfeb1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/8259ffb930817e72b1ff1caef5d226501f3dfeb1",
|
||||
"reference": "8259ffb930817e72b1ff1caef5d226501f3dfeb1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
"php": "^7.1 || ^8.0",
|
||||
"sabberworm/php-css-parser": "^8.4 || ^9.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^7.5 || ^8 || ^9 || ^10 || ^11"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Svg\\": "src/Svg"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-3.0-or-later"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "The SvgLib Community",
|
||||
"homepage": "https://github.com/dompdf/php-svg-lib/blob/master/AUTHORS.md"
|
||||
}
|
||||
],
|
||||
"description": "A library to read, parse and export to PDF SVG files.",
|
||||
"homepage": "https://github.com/dompdf/php-svg-lib",
|
||||
"support": {
|
||||
"issues": "https://github.com/dompdf/php-svg-lib/issues",
|
||||
"source": "https://github.com/dompdf/php-svg-lib/tree/1.0.2"
|
||||
},
|
||||
"time": "2026-01-02T16:01:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dragonmantank/cron-expression",
|
||||
"version": "v3.6.0",
|
||||
@@ -2728,6 +2960,73 @@
|
||||
],
|
||||
"time": "2026-01-23T05:41:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "masterminds/html5",
|
||||
"version": "2.10.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Masterminds/html5-php.git",
|
||||
"reference": "fcf91eb64359852f00d921887b219479b4f21251"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251",
|
||||
"reference": "fcf91eb64359852f00d921887b219479b4f21251",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Masterminds\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Matt Butcher",
|
||||
"email": "technosophos@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Matt Farina",
|
||||
"email": "matt@mattfarina.com"
|
||||
},
|
||||
{
|
||||
"name": "Asmir Mustafic",
|
||||
"email": "goetas@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "An HTML5 parser and serializer.",
|
||||
"homepage": "http://masterminds.github.io/html5-php",
|
||||
"keywords": [
|
||||
"HTML5",
|
||||
"dom",
|
||||
"html",
|
||||
"parser",
|
||||
"querypath",
|
||||
"serializer",
|
||||
"xml"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Masterminds/html5-php/issues",
|
||||
"source": "https://github.com/Masterminds/html5-php/tree/2.10.0"
|
||||
},
|
||||
"time": "2025-07-25T09:04:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mobiledetect/mobiledetectlib",
|
||||
"version": "4.8.09",
|
||||
@@ -5121,6 +5420,86 @@
|
||||
],
|
||||
"time": "2024-06-11T12:45:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sabberworm/php-css-parser",
|
||||
"version": "v9.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/MyIntervals/PHP-CSS-Parser.git",
|
||||
"reference": "88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949",
|
||||
"reference": "88dbd0f7f91abbfe4402d0a3071e9ff4d81ed949",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-iconv": "*",
|
||||
"php": "^7.2.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
|
||||
"thecodingmachine/safe": "^1.3 || ^2.5 || ^3.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-parallel-lint/php-parallel-lint": "1.4.0",
|
||||
"phpstan/extension-installer": "1.4.3",
|
||||
"phpstan/phpstan": "1.12.32 || 2.1.32",
|
||||
"phpstan/phpstan-phpunit": "1.4.2 || 2.0.8",
|
||||
"phpstan/phpstan-strict-rules": "1.6.2 || 2.0.7",
|
||||
"phpunit/phpunit": "8.5.52",
|
||||
"rawr/phpunit-data-provider": "3.3.1",
|
||||
"rector/rector": "1.2.10 || 2.2.8",
|
||||
"rector/type-perfect": "1.0.0 || 2.1.0",
|
||||
"squizlabs/php_codesniffer": "4.0.1",
|
||||
"thecodingmachine/phpstan-safe-rule": "1.2.0 || 1.4.1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-mbstring": "for parsing UTF-8 CSS"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "9.4.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/Rule/Rule.php",
|
||||
"src/RuleSet/RuleContainer.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Sabberworm\\CSS\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Raphael Schweikert"
|
||||
},
|
||||
{
|
||||
"name": "Oliver Klee",
|
||||
"email": "github@oliverklee.de"
|
||||
},
|
||||
{
|
||||
"name": "Jake Hotson",
|
||||
"email": "jake.github@qzdesign.co.uk"
|
||||
}
|
||||
],
|
||||
"description": "Parser for CSS Files written in PHP",
|
||||
"homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser",
|
||||
"keywords": [
|
||||
"css",
|
||||
"parser",
|
||||
"stylesheet"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues",
|
||||
"source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v9.3.0"
|
||||
},
|
||||
"time": "2026-03-03T17:31:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spatie/laravel-permission",
|
||||
"version": "6.24.0",
|
||||
@@ -7964,6 +8343,149 @@
|
||||
],
|
||||
"time": "2025-10-27T20:36:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "thecodingmachine/safe",
|
||||
"version": "v3.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thecodingmachine/safe.git",
|
||||
"reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thecodingmachine/safe/zipball/705683a25bacf0d4860c7dea4d7947bfd09eea19",
|
||||
"reference": "705683a25bacf0d4860c7dea4d7947bfd09eea19",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"php-parallel-lint/php-parallel-lint": "^1.4",
|
||||
"phpstan/phpstan": "^2",
|
||||
"phpunit/phpunit": "^10",
|
||||
"squizlabs/php_codesniffer": "^3.2"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"lib/special_cases.php",
|
||||
"generated/apache.php",
|
||||
"generated/apcu.php",
|
||||
"generated/array.php",
|
||||
"generated/bzip2.php",
|
||||
"generated/calendar.php",
|
||||
"generated/classobj.php",
|
||||
"generated/com.php",
|
||||
"generated/cubrid.php",
|
||||
"generated/curl.php",
|
||||
"generated/datetime.php",
|
||||
"generated/dir.php",
|
||||
"generated/eio.php",
|
||||
"generated/errorfunc.php",
|
||||
"generated/exec.php",
|
||||
"generated/fileinfo.php",
|
||||
"generated/filesystem.php",
|
||||
"generated/filter.php",
|
||||
"generated/fpm.php",
|
||||
"generated/ftp.php",
|
||||
"generated/funchand.php",
|
||||
"generated/gettext.php",
|
||||
"generated/gmp.php",
|
||||
"generated/gnupg.php",
|
||||
"generated/hash.php",
|
||||
"generated/ibase.php",
|
||||
"generated/ibmDb2.php",
|
||||
"generated/iconv.php",
|
||||
"generated/image.php",
|
||||
"generated/imap.php",
|
||||
"generated/info.php",
|
||||
"generated/inotify.php",
|
||||
"generated/json.php",
|
||||
"generated/ldap.php",
|
||||
"generated/libxml.php",
|
||||
"generated/lzf.php",
|
||||
"generated/mailparse.php",
|
||||
"generated/mbstring.php",
|
||||
"generated/misc.php",
|
||||
"generated/mysql.php",
|
||||
"generated/mysqli.php",
|
||||
"generated/network.php",
|
||||
"generated/oci8.php",
|
||||
"generated/opcache.php",
|
||||
"generated/openssl.php",
|
||||
"generated/outcontrol.php",
|
||||
"generated/pcntl.php",
|
||||
"generated/pcre.php",
|
||||
"generated/pgsql.php",
|
||||
"generated/posix.php",
|
||||
"generated/ps.php",
|
||||
"generated/pspell.php",
|
||||
"generated/readline.php",
|
||||
"generated/rnp.php",
|
||||
"generated/rpminfo.php",
|
||||
"generated/rrd.php",
|
||||
"generated/sem.php",
|
||||
"generated/session.php",
|
||||
"generated/shmop.php",
|
||||
"generated/sockets.php",
|
||||
"generated/sodium.php",
|
||||
"generated/solr.php",
|
||||
"generated/spl.php",
|
||||
"generated/sqlsrv.php",
|
||||
"generated/ssdeep.php",
|
||||
"generated/ssh2.php",
|
||||
"generated/stream.php",
|
||||
"generated/strings.php",
|
||||
"generated/swoole.php",
|
||||
"generated/uodbc.php",
|
||||
"generated/uopz.php",
|
||||
"generated/url.php",
|
||||
"generated/var.php",
|
||||
"generated/xdiff.php",
|
||||
"generated/xml.php",
|
||||
"generated/xmlrpc.php",
|
||||
"generated/yaml.php",
|
||||
"generated/yaz.php",
|
||||
"generated/zip.php",
|
||||
"generated/zlib.php"
|
||||
],
|
||||
"classmap": [
|
||||
"lib/DateTime.php",
|
||||
"lib/DateTimeImmutable.php",
|
||||
"lib/Exceptions/",
|
||||
"generated/Exceptions/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "PHP core functions that throw exceptions instead of returning FALSE on error",
|
||||
"support": {
|
||||
"issues": "https://github.com/thecodingmachine/safe/issues",
|
||||
"source": "https://github.com/thecodingmachine/safe/tree/v3.4.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/OskarStark",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/shish",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/silasjoisten",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/staabm",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-04T18:08:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "tijsverkoyen/css-to-inline-styles",
|
||||
"version": "v2.4.0",
|
||||
|
||||
@@ -11,7 +11,7 @@ class RoleSeeder extends Seeder
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$role1 = Role::create(['name'=>'Admin']);
|
||||
$role1 = Role::create(['name'=>'Administrador']);
|
||||
$role2 = Role::create(['name'=>'Programador']);
|
||||
$role3 = Role::create(['name'=>'Promotor']);
|
||||
$role4 = Role::create(['name'=>'Alumno']);
|
||||
@@ -74,6 +74,11 @@ class RoleSeeder extends Seeder
|
||||
Permission::create(['name'=>'alumno.edit','description'=>'Editar alumnos'])->syncRoles([$role1,$role3,$role5]);
|
||||
Permission::create(['name'=>'alumno.destroy','description'=>'Eliminar alumnos'])->syncRoles([$role1]);
|
||||
|
||||
Permission::create(['name'=>'prospecto.index','description'=>'Ver prospectos'])->syncRoles([$role1,$role3]);
|
||||
Permission::create(['name'=>'prospecto.create','description'=>'Crear prospectos'])->syncRoles([$role1,$role3]);
|
||||
Permission::create(['name'=>'prospecto.edit','description'=>'Editar prospectos'])->syncRoles([$role1,$role3]);
|
||||
Permission::create(['name'=>'prospecto.destroy','description'=>'Eliminar prospectos'])->syncRoles([$role1]);
|
||||
|
||||
Permission::create(['name'=>'area.index','description'=>'Ver areas'])->syncRoles([$role1]);
|
||||
Permission::create(['name'=>'area.create','description'=>'Crear areas'])->syncRoles([$role1]);
|
||||
Permission::create(['name'=>'area.edit','description'=>'Editar areas'])->syncRoles([$role1]);
|
||||
@@ -98,6 +103,7 @@ class RoleSeeder extends Seeder
|
||||
Permission::create(['name'=>'plane.create','description'=>'Crear planes de pago'])->syncRoles([$role1]);
|
||||
Permission::create(['name'=>'plane.edit','description'=>'Editar planes de pago'])->syncRoles([$role1]);
|
||||
Permission::create(['name'=>'plane.destroy','description'=>'Eliminar planes de pago'])->syncRoles([$role1]);
|
||||
Permission::create(['name'=>'pagar','description'=>'Pagar'])->syncRoles([$role4]);
|
||||
|
||||
Permission::create(['name'=>'concepto.index','description'=>'Ver conceptos'])->syncRoles([$role1]);
|
||||
Permission::create(['name'=>'concepto.create','description'=>'Crear conceptos'])->syncRoles([$role1]);
|
||||
@@ -126,7 +132,7 @@ class RoleSeeder extends Seeder
|
||||
Permission::create(['name'=>'pago.edit','description'=>'Editar pagos'])->syncRoles([$role1]);
|
||||
Permission::create(['name'=>'pago.destroy','description'=>'Eliminar pagos'])->syncRoles([$role1,$role3]);
|
||||
|
||||
Permission::create(['name'=>'grupo.index','description'=>'Ver grupos'])->syncRoles([$role1,$role4,$role5,$role6,$role7]);
|
||||
Permission::create(['name'=>'grupo.index','description'=>'Ver grupos'])->syncRoles([$role1,$role5,$role6,$role7]);
|
||||
Permission::create(['name'=>'grupo.create','description'=>'Crear grupos'])->syncRoles([$role1,$role5]);
|
||||
Permission::create(['name'=>'grupo.edit','description'=>'Editar grupos'])->syncRoles([$role1,$role5,$role6]);
|
||||
Permission::create(['name'=>'grupo.destroy','description'=>'Eliminar grupos'])->syncRoles([$role1,$role5]);
|
||||
@@ -141,6 +147,23 @@ class RoleSeeder extends Seeder
|
||||
Permission::create(['name'=>'documentoTipo.edit','description'=>'Editar documentación'])->syncRoles([$role1]);
|
||||
Permission::create(['name'=>'documentoTipo.destroy','description'=>'Eliminar documentación'])->syncRoles([$role1]);
|
||||
|
||||
Permission::create(['name'=>'evaluaciones.index','description'=>'Ver evaluaciones'])->syncRoles([$role1,$role7,$role4]);
|
||||
Permission::create(['name'=>'evaluaciones.create','description'=>'Crear evaluaciones'])->syncRoles([$role1]);
|
||||
Permission::create(['name'=>'evaluaciones.edit','description'=>'Editar evaluaciones'])->syncRoles([$role1]);
|
||||
Permission::create(['name'=>'evaluaciones.destroy','description'=>'Eliminar evaluaciones'])->syncRoles([$role1]);
|
||||
Permission::create(['name'=>'evaluaciones.responder','description'=>'responder evaluaciones'])->syncRoles([$role4,$role7]);
|
||||
|
||||
Permission::create(['name'=>'anuncios.index','description'=>'Ver anuncios'])->syncRoles([$role1]);
|
||||
Permission::create(['name'=>'anuncios.create','description'=>'Crear anuncios'])->syncRoles([$role1]);
|
||||
Permission::create(['name'=>'anuncios.edit','description'=>'Editar anuncios'])->syncRoles([$role1]);
|
||||
Permission::create(['name'=>'anuncios.destroy','description'=>'Eliminar anuncios'])->syncRoles([$role1]);
|
||||
|
||||
Permission::create(['name'=>'tareas.index','description'=>'Ver tareas'])->syncRoles([$role7]);
|
||||
Permission::create(['name'=>'tareas.create','description'=>'Crear tareas'])->syncRoles([$role7]);
|
||||
Permission::create(['name'=>'tareas.edit','description'=>'Editar tareas'])->syncRoles([$role7]);
|
||||
Permission::create(['name'=>'tareas.destroy','description'=>'Eliminar tareas'])->syncRoles([$role7]);
|
||||
Permission::create(['name'=>'tareas.entrega','description'=>'Entregar tareas'])->syncRoles([$role4]);
|
||||
|
||||
Permission::create(['name'=>'comunidad','description'=>'Comunidad'])->syncRoles([$role1]);
|
||||
Permission::create(['name'=>'amigos','description'=>'Amistades'])->syncRoles([$role1]);
|
||||
Permission::create(['name'=>'mensajes','description'=>'Mensajería'])->syncRoles([$role1]);
|
||||
|
||||
@@ -23,7 +23,7 @@ class UserSeeder extends Seeder
|
||||
'password' => bcrypt('6686'),
|
||||
'code'=>1,
|
||||
'status'=>1
|
||||
])->assignRole('Admin');
|
||||
])->assignRole('Administrador');
|
||||
|
||||
$user->plantelUsuarios()->sync(3);
|
||||
|
||||
|
||||
@@ -27,7 +27,138 @@
|
||||
<input class="btn btn-primary" type="submit" value="Actualizar">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-lg-8">
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
<div class="d-sm-flex align-items-center justify-content-between">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Expediente del alumno</h6>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
|
||||
<div>
|
||||
|
||||
@php
|
||||
$nivel = $alumno->nivelRel ?? null;
|
||||
|
||||
$tipos = $nivel
|
||||
? $nivel->documentosRequeridos
|
||||
: collect();
|
||||
|
||||
$documentos = collect($alumno?->documentos)->keyBy('tipo');
|
||||
@endphp
|
||||
|
||||
@foreach($tipos as $tipo)
|
||||
|
||||
@php
|
||||
$doc = $documentos[$tipo->slug] ?? null;
|
||||
@endphp
|
||||
|
||||
<div class="mb-3">
|
||||
|
||||
@if($doc)
|
||||
|
||||
@if($doc->status == 1)
|
||||
<div class="alert alert-success d-sm-flex align-items-center justify-content-between">
|
||||
<strong>{{ strtoupper($tipo->name) }} : Validado</strong>
|
||||
|
||||
<button
|
||||
onclick="verDocumento('{{ url('documento/ver/'.$doc->id) }}', {{ $doc->id }})"
|
||||
class="btn btn-sm btn-primary mt-2">
|
||||
<i class="fa-duotone fa-solid fa-eye"></i> Ver documento
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@elseif($doc->status == 2)
|
||||
<div class="alert alert-danger d-sm-flex align-items-center justify-content-between">
|
||||
<strong>{{ strtoupper($tipo->name) }} : Rechazado</strong>
|
||||
|
||||
<button
|
||||
onclick="verDocumento('{{ url('documento/ver/'.$doc->id) }}', {{ $doc->id }})"
|
||||
class="btn btn-sm btn-primary mt-2">
|
||||
<i class="fa-duotone fa-solid fa-eye"></i> Ver documento
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@else
|
||||
|
||||
<div class="alert alert-warning d-sm-flex align-items-center justify-content-between">
|
||||
|
||||
<strong>{{ strtoupper($tipo->name) }} : Pendiente de revisión</strong>
|
||||
|
||||
<button
|
||||
onclick="verDocumento('{{ url('documento/ver/'.$doc->id) }}', {{ $doc->id }})"
|
||||
class="btn btn-sm btn-primary mt-2">
|
||||
<i class="fa-duotone fa-solid fa-eye"></i> Ver documento
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
@endif
|
||||
|
||||
|
||||
|
||||
@else
|
||||
<div class="alert alert-danger">
|
||||
<strong>{{ strtoupper($tipo->name) }} : Faltante</strong>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4">
|
||||
<div class="card shadow mb-4 ">
|
||||
<div class="card-header py-3">
|
||||
<div class="d-sm-flex align-items-center justify-content-between">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Asignación de beca</h6>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="visorModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-xl">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Vista previa</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<iframe id="visorFrame" width="100%" height="600px" style="border:none;"></iframe>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
@@ -11,22 +11,23 @@
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
<div class="d-sm-flex align-items-center justify-content-between">
|
||||
@hasrole('Promotor')
|
||||
<h6 class="m-0 font-weight-bold text-primary">Prospectos</h6>
|
||||
@endrole
|
||||
|
||||
@hasrole('Control escolar')
|
||||
<h6 class="m-0 font-weight-bold text-primary">Alumnos</h6>
|
||||
@endrole
|
||||
@can('alumno.create')
|
||||
@if (Auth::user()->roles->contains('name', 'Promotor'))
|
||||
<h6 class="m-0 font-weight-bold text-primary">Prospectos</h6>
|
||||
<button onclick="Livewire.dispatch('create-prospecto')" class="d-sm-inline-block btn btn-sm btn-primary shadow-sm"><i class="fas fa-download fa-sm text-white-50"></i> Agregar</button>
|
||||
@endcan
|
||||
|
||||
@else
|
||||
<h6 class="m-0 font-weight-bold text-primary">Alumnos</h6>
|
||||
|
||||
@endif
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-body row">
|
||||
|
||||
@hasrole('Promotor')
|
||||
@if (Auth::user()->roles->contains('name', 'Promotor'))
|
||||
<div class="col-sm-2 overflow-auto" style="height: 80vh">
|
||||
<div class="list-group">
|
||||
@forelse ($alumnos as $alumno)
|
||||
@@ -64,14 +65,16 @@
|
||||
</div>
|
||||
|
||||
@livewire('modal-prospecto')
|
||||
@endrole
|
||||
|
||||
@hasrole('Control escolar')
|
||||
|
||||
@else
|
||||
|
||||
|
||||
<table id="tcont" class="table table-striped table-bordered nowrap table-hover" style="width:100%;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<th>Foto</th>
|
||||
<th>Alumno</th>
|
||||
<th>Campus</th>
|
||||
<th>Status</th>
|
||||
@@ -86,10 +89,18 @@
|
||||
|
||||
<td>{{ $alumno->id }}</td>
|
||||
|
||||
|
||||
<td class="text-center">
|
||||
@foreach($alumno->alumnos as $user)
|
||||
<img src="{{ $user?->profile_photo_url }}"
|
||||
class="rounded-circle mr-3"
|
||||
style="width:48px; height:48px; object-fit:cover; border:2px solid #36b9cc;" onclick="verFoto('{{ $user?->profile_photo_url }}','{{ $user->name }} {{ $user->apellidoPaterno }}')">
|
||||
@endforeach
|
||||
</td>
|
||||
<td>
|
||||
@foreach($alumno->alumnos as $user)
|
||||
<a href="{{ route('alumno.show', $alumno->id) }}">
|
||||
{{ $user->name }}
|
||||
{{ $user->name }} {{ $user->apellidoPaterno }} {{ $user->apellidoMaterno }}
|
||||
</a>
|
||||
@endforeach
|
||||
</td>
|
||||
@@ -118,24 +129,20 @@
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td class="row mx-auto">
|
||||
<td>
|
||||
|
||||
@can('alumno.edit')
|
||||
<div class="col-sm-6 col-md-6">
|
||||
<a class="btn btn-primary" href="{{ route('alumno.edit',$alumno->id) }}">
|
||||
Edit
|
||||
</a>
|
||||
</div>
|
||||
@endcan
|
||||
|
||||
@can('alumno.destroy')
|
||||
<div class="col-sm-6 col-md-6">
|
||||
<form class="delete-form" action="{{ route('alumno.destroy',$alumno->id) }}" method="POST">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<input type="submit" value="DELETE" class="btn btn-danger">
|
||||
</form>
|
||||
</div>
|
||||
@endcan
|
||||
|
||||
</td>
|
||||
@@ -151,8 +158,7 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@endrole
|
||||
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -192,7 +198,6 @@ function verDocumento(url, docId) {
|
||||
|
||||
Livewire.dispatch('set-documento', { id: docId });
|
||||
|
||||
// 🔥 guardar instancia global
|
||||
visorModalInstance = new bootstrap.Modal(
|
||||
document.getElementById('visorModal')
|
||||
);
|
||||
@@ -208,12 +213,21 @@ document.addEventListener('livewire:init', () => {
|
||||
visorModalInstance.hide();
|
||||
}
|
||||
|
||||
// 🔥 limpiar iframe
|
||||
document.getElementById('visorFrame').src = "";
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function verFoto(url,nombre){
|
||||
Swal.fire({
|
||||
text: nombre,
|
||||
imageUrl: url,
|
||||
imageWidth: 400,
|
||||
imageHeight: 400,
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@endsection
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
</div>
|
||||
|
||||
@elseif($tipoSlug === 'escala_5')
|
||||
<div class="d-flex flex-wrap" style="gap:.5rem;">
|
||||
<div class="d-flex flex-wrap escala-grupo" style="gap:.5rem;">
|
||||
@for($k = 1; $k <= 5; $k++)
|
||||
<div class="form-check form-check-inline mr-0">
|
||||
<input type="radio"
|
||||
@@ -67,7 +67,7 @@
|
||||
value="{{ $k }}"
|
||||
class="form-check-input d-none escala-input"
|
||||
{{ $pregunta->requerida ? 'required' : '' }}>
|
||||
<label class="btn btn-outline-primary px-3 py-2"
|
||||
<label class="btn btn-outline-primary px-3 py-2 escala-label"
|
||||
for="{{ $fieldId }}_{{ $k }}">{{ $k }}</label>
|
||||
</div>
|
||||
@endfor
|
||||
@@ -75,7 +75,7 @@
|
||||
</div>
|
||||
|
||||
@elseif($tipoSlug === 'escala_10')
|
||||
<div class="d-flex flex-wrap" style="gap:.5rem;">
|
||||
<div class="d-flex flex-wrap escala-grupo" style="gap:.5rem;">
|
||||
@for($k = 1; $k <= 10; $k++)
|
||||
<div class="form-check form-check-inline mr-0">
|
||||
<input type="radio"
|
||||
@@ -84,10 +84,20 @@
|
||||
value="{{ $k }}"
|
||||
class="form-check-input d-none escala-input"
|
||||
{{ $pregunta->requerida ? 'required' : '' }}>
|
||||
<label class="btn btn-outline-primary px-3 py-2"
|
||||
<label class="btn btn-outline-primary px-3 py-2 escala-label"
|
||||
for="{{ $fieldId }}_{{ $k }}">{{ $k }}</label>
|
||||
</div>
|
||||
@endfor
|
||||
<small class="text-muted align-self-center ml-2">1 = Muy malo 10 = Excelente</small>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@once
|
||||
<style>
|
||||
.escala-input:checked + .escala-label {
|
||||
background-color: #4e73df;
|
||||
border-color: #4e73df;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
@endonce
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
@extends('layouts.landing')
|
||||
|
||||
@section('title', 'Reporte — ' . $evaluacion->titulo)
|
||||
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
|
||||
{{-- Header --}}
|
||||
<div class="d-sm-flex align-items-center justify-content-between mb-4">
|
||||
<div>
|
||||
<h5 class="m-0 font-weight-bold text-primary">
|
||||
<i class="fas fa-chart-bar mr-1"></i> {{ $evaluacion->titulo }}
|
||||
</h5>
|
||||
<small class="text-muted">Reporte de resultados</small>
|
||||
</div>
|
||||
<div class="d-flex flex-wrap" style="gap:.4rem;">
|
||||
<a href="{{ route('evaluacion.reporte.pdf', $evaluacion) }}"
|
||||
class="btn btn-sm btn-danger shadow-sm">
|
||||
<i class="fas fa-file-pdf mr-1"></i> Exportar PDF
|
||||
</a>
|
||||
<a href="{{ route('evaluacion.show', $evaluacion) }}"
|
||||
class="btn btn-sm btn-secondary shadow-sm">
|
||||
<i class="fas fa-arrow-left mr-1"></i> Regresar
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Tarjetas de resumen --}}
|
||||
<div class="row mb-4">
|
||||
<div class="col-xl-3 col-md-6 mb-3">
|
||||
<div class="card border-left-primary shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">Participantes</div>
|
||||
<div class="h4 mb-0 font-weight-bold text-gray-800">{{ $totalSubmissions }}</div>
|
||||
</div>
|
||||
<div class="col-auto"><i class="fas fa-users fa-2x text-gray-300"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6 mb-3">
|
||||
<div class="card border-left-info shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-info text-uppercase mb-1">Preguntas</div>
|
||||
<div class="h4 mb-0 font-weight-bold text-gray-800">{{ count($datos) }}</div>
|
||||
</div>
|
||||
<div class="col-auto"><i class="fas fa-list-ol fa-2x text-gray-300"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6 mb-3">
|
||||
<div class="card border-left-success shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">Estado</div>
|
||||
<div class="h4 mb-0 font-weight-bold text-gray-800">{{ ucfirst($evaluacion->status) }}</div>
|
||||
</div>
|
||||
<div class="col-auto"><i class="fas fa-clipboard-check fa-2x text-gray-300"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 col-md-6 mb-3">
|
||||
<div class="card border-left-warning shadow h-100 py-2">
|
||||
<div class="card-body">
|
||||
<div class="row no-gutters align-items-center">
|
||||
<div class="col mr-2">
|
||||
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">Dirigida a</div>
|
||||
<div class="h4 mb-0 font-weight-bold text-gray-800">{{ $evaluacion->tipo?->nombre }}</div>
|
||||
</div>
|
||||
<div class="col-auto"><i class="fas fa-tag fa-2x text-gray-300"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Sin respuestas --}}
|
||||
@if($totalSubmissions === 0)
|
||||
<div class="alert alert-info text-center">
|
||||
<i class="fas fa-info-circle fa-2x mb-2 d-block"></i>
|
||||
Esta evaluación aún no tiene respuestas registradas.
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{-- Preguntas --}}
|
||||
@foreach($datos as $i => $item)
|
||||
@php $pregunta = $item['pregunta']; @endphp
|
||||
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3 d-flex align-items-center justify-content-between flex-wrap" style="gap:.5rem;">
|
||||
<h6 class="m-0 font-weight-bold text-primary">
|
||||
{{ $i + 1 }}. {{ $pregunta->texto }}
|
||||
@if($pregunta->es_docente)
|
||||
<span class="badge badge-info ml-1">
|
||||
<i class="fas fa-chalkboard-teacher mr-1"></i>Por docente
|
||||
</span>
|
||||
@endif
|
||||
@if($pregunta->requerida)
|
||||
<span class="text-danger ml-1" title="Obligatoria">*</span>
|
||||
@endif
|
||||
</h6>
|
||||
<div class="d-flex align-items-center" style="gap:.5rem;">
|
||||
<span class="badge badge-light border">{{ $pregunta->tipo?->nombre }}</span>
|
||||
@if(!$item['es_docente'] && isset($item['promedio']))
|
||||
<span class="badge badge-primary px-3">
|
||||
Promedio: {{ $item['promedio'] }}
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
{{-- Texto libre --}}
|
||||
@if($item['tipo'] === 'texto_libre')
|
||||
|
||||
@if(!$item['es_docente'])
|
||||
@forelse($item['textos'] as $txt)
|
||||
<div class="alert alert-light border mb-2 py-2 px-3">
|
||||
<i class="fas fa-quote-left text-muted mr-2 small"></i>{{ $txt }}
|
||||
</div>
|
||||
@empty
|
||||
<p class="text-muted mb-0"><em>Sin respuestas registradas.</em></p>
|
||||
@endforelse
|
||||
@else
|
||||
@foreach($item['por_docente'] as $pd)
|
||||
<div class="mb-4">
|
||||
<h6 class="font-weight-bold text-info mb-2">
|
||||
<i class="fas fa-chalkboard-teacher mr-1"></i>{{ $pd['docente_nombre'] }}
|
||||
<small class="text-muted font-weight-normal">({{ $pd['total'] }} respuesta(s))</small>
|
||||
</h6>
|
||||
@forelse($pd['textos'] as $txt)
|
||||
<div class="alert alert-light border mb-2 py-2 px-3">
|
||||
<i class="fas fa-quote-left text-muted mr-2 small"></i>{{ $txt }}
|
||||
</div>
|
||||
@empty
|
||||
<p class="text-muted small"><em>Sin respuestas.</em></p>
|
||||
@endforelse
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
|
||||
{{-- Gráfica única --}}
|
||||
@elseif(!$item['es_docente'])
|
||||
@if($item['total'] > 0)
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-8">
|
||||
<canvas id="chart-{{ $i }}"
|
||||
height="{{ in_array($item['tipo'], ['si_no']) ? 200 : 160 }}">
|
||||
</canvas>
|
||||
</div>
|
||||
<div class="col-lg-4 text-center">
|
||||
<p class="mb-2 text-muted">
|
||||
<i class="fas fa-poll mr-1"></i>
|
||||
<strong>{{ $item['total'] }}</strong> respuesta(s)
|
||||
</p>
|
||||
@if(isset($item['promedio']))
|
||||
<div class="h4 font-weight-bold text-primary mb-0">
|
||||
{{ $item['promedio'] }}
|
||||
</div>
|
||||
<small class="text-muted">promedio</small>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<p class="text-muted"><em>Sin respuestas registradas.</em></p>
|
||||
@endif
|
||||
|
||||
{{-- Gráficas por docente --}}
|
||||
@else
|
||||
@if(empty($item['por_docente']))
|
||||
<p class="text-muted"><em>Sin respuestas registradas.</em></p>
|
||||
@else
|
||||
<div class="row">
|
||||
@foreach($item['por_docente'] as $di => $pd)
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card border h-100">
|
||||
<div class="card-header py-2 bg-light d-flex align-items-center justify-content-between">
|
||||
<span class="font-weight-bold text-info small">
|
||||
<i class="fas fa-chalkboard-teacher mr-1"></i>{{ $pd['docente_nombre'] }}
|
||||
</span>
|
||||
@if(isset($pd['promedio']))
|
||||
<span class="badge badge-primary">Prom: {{ $pd['promedio'] }}</span>
|
||||
@endif
|
||||
</div>
|
||||
<div class="card-body py-2">
|
||||
@if($pd['total'] > 0)
|
||||
<canvas id="chart-{{ $i }}-{{ $di }}" height="200"></canvas>
|
||||
<p class="text-center text-muted small mt-2 mb-0">
|
||||
{{ $pd['total'] }} respuesta(s)
|
||||
</p>
|
||||
@else
|
||||
<p class="text-muted text-center small py-3"><em>Sin respuestas.</em></p>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('scripts')
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
|
||||
<script>
|
||||
Chart.defaults.font.family = "'Nunito', sans-serif";
|
||||
Chart.defaults.font.size = 13;
|
||||
|
||||
@foreach($datos as $i => $item)
|
||||
@if($item['tipo'] !== 'texto_libre' && $item['total'] > 0)
|
||||
@if(!$item['es_docente'] && isset($item['chart_config']))
|
||||
new Chart(
|
||||
document.getElementById('chart-{{ $i }}'),
|
||||
@json($item['chart_config'])
|
||||
);
|
||||
@elseif($item['es_docente'])
|
||||
@foreach($item['por_docente'] as $di => $pd)
|
||||
@if(isset($pd['chart_config']) && $pd['total'] > 0)
|
||||
new Chart(
|
||||
document.getElementById('chart-{{ $i }}-{{ $di }}'),
|
||||
@json($pd['chart_config'])
|
||||
);
|
||||
@endif
|
||||
@endforeach
|
||||
@endif
|
||||
@endif
|
||||
@endforeach
|
||||
</script>
|
||||
@endsection
|
||||
@@ -0,0 +1,355 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Reporte — {{ $evaluacion->titulo }}</title>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
body {
|
||||
font-family: DejaVu Sans, Arial, sans-serif;
|
||||
font-size: 11px;
|
||||
color: #333;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* ── Header ── */
|
||||
.header {
|
||||
border-bottom: 3px solid #4e73df;
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
.header h1 {
|
||||
font-size: 17px;
|
||||
color: #4e73df;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.header .meta {
|
||||
font-size: 10px;
|
||||
color: #666;
|
||||
}
|
||||
.header .descripcion {
|
||||
font-size: 11px;
|
||||
color: #555;
|
||||
margin-top: 4px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* ── Summary boxes ── */
|
||||
.summary-row {
|
||||
width: 100%;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
.summary-row td {
|
||||
width: 25%;
|
||||
padding: 8px 6px;
|
||||
border: 1px solid #e3e6f0;
|
||||
background: #f8f9fc;
|
||||
text-align: center;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.summary-row .label {
|
||||
font-size: 9px;
|
||||
color: #666;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .5px;
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
}
|
||||
.summary-row .value {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #4e73df;
|
||||
}
|
||||
|
||||
/* ── Pregunta block ── */
|
||||
.pregunta-block {
|
||||
margin-bottom: 22px;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
.pregunta-header {
|
||||
background: #4e73df;
|
||||
color: white;
|
||||
padding: 6px 10px;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
border-radius: 4px 4px 0 0;
|
||||
}
|
||||
.pregunta-body {
|
||||
border: 1px solid #d1d3e2;
|
||||
border-top: none;
|
||||
padding: 10px;
|
||||
border-radius: 0 0 4px 4px;
|
||||
background: #fff;
|
||||
}
|
||||
.badge-info {
|
||||
background: #36b9cc;
|
||||
color: white;
|
||||
padding: 1px 6px;
|
||||
border-radius: 3px;
|
||||
font-size: 9px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* ── Stats ── */
|
||||
.stat-line {
|
||||
font-size: 10px;
|
||||
color: #666;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.promedio {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #4e73df;
|
||||
}
|
||||
.promedio-label {
|
||||
font-size: 10px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* ── Chart image ── */
|
||||
.chart-img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 480px;
|
||||
margin: 6px auto;
|
||||
}
|
||||
.chart-error {
|
||||
color: #aaa;
|
||||
font-size: 10px;
|
||||
text-align: center;
|
||||
padding: 15px;
|
||||
border: 1px dashed #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* ── Texto libre ── */
|
||||
.texto-libre-item {
|
||||
background: #f8f9fc;
|
||||
border-left: 3px solid #4e73df;
|
||||
padding: 5px 10px;
|
||||
margin-bottom: 5px;
|
||||
font-size: 10px;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
/* ── Docente section ── */
|
||||
.docente-header {
|
||||
background: #e8f7fa;
|
||||
border-left: 4px solid #36b9cc;
|
||||
padding: 5px 8px;
|
||||
margin-bottom: 6px;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
color: #2c8fa0;
|
||||
}
|
||||
.docente-block {
|
||||
margin-bottom: 14px;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
.two-col-table { width: 100%; }
|
||||
.two-col-table td { width: 50%; vertical-align: top; padding: 0 5px; }
|
||||
.two-col-table td:first-child { padding-left: 0; }
|
||||
.two-col-table td:last-child { padding-right: 0; }
|
||||
|
||||
/* ── Footer ── */
|
||||
.footer {
|
||||
margin-top: 30px;
|
||||
border-top: 1px solid #e3e6f0;
|
||||
padding-top: 8px;
|
||||
text-align: center;
|
||||
font-size: 9px;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.no-data { color: #aaa; font-size: 10px; font-style: italic; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
{{-- ENCABEZADO --}}
|
||||
<div class="header">
|
||||
<h1><span style="color:#4e73df;">▮</span> {{ $evaluacion->titulo }}</h1>
|
||||
<div class="meta">
|
||||
<strong>Tipo:</strong> {{ $evaluacion->tipo?->nombre }}
|
||||
|
|
||||
<strong>Estado:</strong> {{ ucfirst($evaluacion->status) }}
|
||||
|
|
||||
<strong>Participantes:</strong> {{ $totalSubmissions }}
|
||||
|
|
||||
<strong>Generado:</strong> {{ now()->format('d/m/Y H:i') }}
|
||||
@if($evaluacion->fecha_inicio || $evaluacion->fecha_fin)
|
||||
|
|
||||
<strong>Vigencia:</strong>
|
||||
{{ $evaluacion->fecha_inicio?->format('d/m/Y') ?? '—' }}
|
||||
al
|
||||
{{ $evaluacion->fecha_fin?->format('d/m/Y') ?? '—' }}
|
||||
@endif
|
||||
</div>
|
||||
@if($evaluacion->descripcion)
|
||||
<div class="descripcion">{{ $evaluacion->descripcion }}</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{{-- RESUMEN --}}
|
||||
<table class="summary-row" cellspacing="4" cellpadding="0">
|
||||
<tr>
|
||||
<td>
|
||||
<span class="label">Participantes</span>
|
||||
<span class="value" style="color:#4e73df;">{{ $totalSubmissions }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="label">Preguntas</span>
|
||||
<span class="value" style="color:#36b9cc;">{{ count($datos) }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="label">Estado</span>
|
||||
<span class="value" style="font-size:13px; color:#1cc88a;">{{ ucfirst($evaluacion->status) }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="label">Tipo</span>
|
||||
<span class="value" style="font-size:13px; color:#f6c23e;">{{ $evaluacion->tipo?->nombre }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@if($totalSubmissions === 0)
|
||||
<p class="no-data" style="text-align:center; padding:20px;">
|
||||
Esta evaluación aún no tiene respuestas registradas.
|
||||
</p>
|
||||
@endif
|
||||
|
||||
{{-- PREGUNTAS --}}
|
||||
@foreach($datos as $i => $item)
|
||||
@php $pregunta = $item['pregunta']; @endphp
|
||||
|
||||
<div class="pregunta-block">
|
||||
|
||||
<div class="pregunta-header">
|
||||
{{ $i + 1 }}. {{ $pregunta->texto }}
|
||||
@if($pregunta->es_docente)
|
||||
<span class="badge-info">Por docente</span>
|
||||
@endif
|
||||
<span style="float:right; font-weight:normal; font-size:9px;">
|
||||
{{ $pregunta->tipo?->nombre }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="pregunta-body">
|
||||
|
||||
{{-- Texto libre --}}
|
||||
@if($item['tipo'] === 'texto_libre')
|
||||
|
||||
@if(!$item['es_docente'])
|
||||
@forelse($item['textos'] as $txt)
|
||||
<div class="texto-libre-item">{{ $txt }}</div>
|
||||
@empty
|
||||
<p class="no-data">Sin respuestas registradas.</p>
|
||||
@endforelse
|
||||
@else
|
||||
@foreach($item['por_docente'] as $pd)
|
||||
<div class="docente-block">
|
||||
<div class="docente-header">
|
||||
{{ $pd['docente_nombre'] }}
|
||||
<span style="font-weight:normal; font-size:9px; color:#666;">
|
||||
— {{ $pd['total'] }} respuesta(s)
|
||||
</span>
|
||||
</div>
|
||||
@forelse($pd['textos'] as $txt)
|
||||
<div class="texto-libre-item">{{ $txt }}</div>
|
||||
@empty
|
||||
<p class="no-data">Sin respuestas.</p>
|
||||
@endforelse
|
||||
</div>
|
||||
@endforeach
|
||||
@endif
|
||||
|
||||
{{-- Gráfica única --}}
|
||||
@elseif(!$item['es_docente'])
|
||||
|
||||
@if($item['total'] > 0)
|
||||
<table style="width:100%;" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td style="width:70%; vertical-align:middle;">
|
||||
@if(isset($item['chart_img']))
|
||||
<img src="{{ $item['chart_img'] }}" class="chart-img" alt="Gráfica">
|
||||
@else
|
||||
<div class="chart-error">Gráfica no disponible</div>
|
||||
@endif
|
||||
</td>
|
||||
<td style="width:30%; vertical-align:middle; text-align:center; padding-left:10px;">
|
||||
<div class="stat-line">Respuestas</div>
|
||||
<div class="promedio" style="font-size:24px;">{{ $item['total'] }}</div>
|
||||
@if(isset($item['promedio']))
|
||||
<div style="margin-top:10px;">
|
||||
<div class="stat-line">Promedio</div>
|
||||
<div class="promedio">{{ $item['promedio'] }}</div>
|
||||
<div class="promedio-label">/ {{ str_contains($item['tipo'], '10') ? '10' : '5' }}</div>
|
||||
</div>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@else
|
||||
<p class="no-data">Sin respuestas registradas.</p>
|
||||
@endif
|
||||
|
||||
{{-- Gráficas por docente (tabla 2 columnas) --}}
|
||||
@else
|
||||
|
||||
@if(empty($item['por_docente']))
|
||||
<p class="no-data">Sin respuestas registradas.</p>
|
||||
@else
|
||||
@php
|
||||
$chunks = array_chunk($item['por_docente'], 2);
|
||||
@endphp
|
||||
@foreach($chunks as $pair)
|
||||
<table class="two-col-table" cellpadding="0" cellspacing="0" style="margin-bottom:10px;">
|
||||
<tr>
|
||||
@foreach($pair as $pd)
|
||||
<td>
|
||||
<div class="docente-block">
|
||||
<div class="docente-header">
|
||||
{{ $pd['docente_nombre'] }}
|
||||
@if(isset($pd['promedio']))
|
||||
·
|
||||
<span style="font-size:9px; color:#36b9cc;">
|
||||
Prom: {{ $pd['promedio'] }}
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
@if($pd['total'] > 0)
|
||||
@if(isset($pd['chart_img']))
|
||||
<img src="{{ $pd['chart_img'] }}" style="width:100%; display:block;" alt="Gráfica">
|
||||
@else
|
||||
<div class="chart-error">Gráfica no disponible</div>
|
||||
@endif
|
||||
<p class="stat-line" style="text-align:center; margin-top:4px;">
|
||||
{{ $pd['total'] }} respuesta(s)
|
||||
</p>
|
||||
@else
|
||||
<p class="no-data">Sin respuestas.</p>
|
||||
@endif
|
||||
</div>
|
||||
</td>
|
||||
@endforeach
|
||||
@if(count($pair) === 1)
|
||||
<td></td>
|
||||
@endif
|
||||
</tr>
|
||||
</table>
|
||||
@endforeach
|
||||
@endif
|
||||
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
|
||||
<div class="footer">
|
||||
Reporte generado el {{ now()->format('d/m/Y \a \l\a\s H:i') }} — Sistema Educativo
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -79,7 +79,7 @@
|
||||
@php
|
||||
$user = $docente->docentes->first();
|
||||
$fotoUrl = $user?->profile_photo_url;
|
||||
$nombreDocente = $user?->name ?? 'Docente';
|
||||
$nombreDocente = trim("{$user?->apellidoPaterno} {$user?->apellidoMaterno} {$user?->name}") ?: 'Docente';
|
||||
@endphp
|
||||
|
||||
<div class="card shadow-sm mb-4 border-left-info">
|
||||
@@ -138,8 +138,8 @@
|
||||
|
||||
<div class="card shadow-sm mb-4">
|
||||
<div class="card-body text-center">
|
||||
<button type="submit" class="btn btn-success btn-lg px-5"
|
||||
onclick="return confirm('¿Estás seguro de enviar la evaluación? No podrás cambiar tus respuestas.')">
|
||||
<button type="button" class="btn btn-success btn-lg px-5"
|
||||
onclick="confirmarEnvioEvaluacion()">
|
||||
<i class="fas fa-paper-plane mr-2"></i> Enviar evaluación
|
||||
</button>
|
||||
</div>
|
||||
@@ -149,3 +149,24 @@
|
||||
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('scripts')
|
||||
<script>
|
||||
function confirmarEnvioEvaluacion() {
|
||||
Swal.fire({
|
||||
title: '¿Enviar evaluación?',
|
||||
html: 'Una vez enviada <strong>no podrás modificar tus respuestas</strong>.',
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Sí, enviar',
|
||||
cancelButtonText: 'Cancelar',
|
||||
confirmButtonColor: '#1cc88a',
|
||||
cancelButtonColor: '#6c757d',
|
||||
}).then(result => {
|
||||
if (result.isConfirmed) {
|
||||
document.getElementById('form-evaluacion').submit();
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@endsection
|
||||
|
||||
@@ -17,8 +17,11 @@
|
||||
<h5 class="m-0 font-weight-bold text-primary">
|
||||
<i class="fas fa-clipboard-list mr-1"></i> {{ $evaluacion->titulo }}
|
||||
</h5>
|
||||
<div>
|
||||
<a href="{{ route('evaluacion.edit', $evaluacion) }}" class="btn btn-sm btn-primary mr-1">
|
||||
<div class="d-flex flex-wrap" style="gap:.4rem;">
|
||||
<a href="{{ route('evaluacion.reporte.show', $evaluacion) }}" class="btn btn-sm btn-info">
|
||||
<i class="fas fa-chart-bar"></i> Reporte
|
||||
</a>
|
||||
<a href="{{ route('evaluacion.edit', $evaluacion) }}" class="btn btn-sm btn-primary">
|
||||
<i class="fas fa-edit"></i> Editar
|
||||
</a>
|
||||
<a href="{{ route('evaluacion.index') }}" class="btn btn-sm btn-secondary">
|
||||
|
||||
@@ -1,240 +1,166 @@
|
||||
|
||||
<ul class="navbar-nav bg-primary sidebar sidebar-dark accordion" id="accordionSidebar">
|
||||
|
||||
<ul class="navbar-nav bg-primary sidebar sidebar-dark accordion" id="accordionSidebar">
|
||||
<!-- Sidebar - Brand -->
|
||||
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="">
|
||||
<!-- Brand -->
|
||||
<a class="sidebar-brand d-flex align-items-center justify-content-center" href="{{ route('dashboard') }}">
|
||||
<div class="sidebar-brand-icon">
|
||||
<img src="https://alumnos.sistemasecuiep.com/logo.png" alt="SECUIEP Logo" style="width: 100px; height: auto;">
|
||||
<img src="https://alumnos.sistemasecuiep.com/logo.png" alt="SECUIEP" style="width:100px;height:auto;">
|
||||
</div>
|
||||
</a>
|
||||
<!-- Divider -->
|
||||
|
||||
<hr class="sidebar-divider my-0">
|
||||
|
||||
<!-- Nav Item - Dashboard -->
|
||||
<!-- Dashboard -->
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="{{ route('dashboard') }}">
|
||||
<i class="fas fa-fw fa-tachometer-alt"></i>
|
||||
<span>Inicio</span></a>
|
||||
</li>
|
||||
<!-- Divider -->
|
||||
<hr class="sidebar-divider">
|
||||
<!-- Heading -->
|
||||
<div class="sidebar-heading" style="color:white">Modulos</div>
|
||||
|
||||
@hasrole('Admin')
|
||||
<li class="nav-item">
|
||||
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#Administrador"
|
||||
aria-expanded="true" aria-controls="Administrador">
|
||||
<i class="fas fa-star" style="color:rgb(255, 153, 0);"></i>
|
||||
<span>Administrador</span>
|
||||
<span>Inicio</span>
|
||||
</a>
|
||||
<div id="Administrador" class="collapse" aria-labelledby="headingUtilities"
|
||||
data-parent="#accordionSidebar">
|
||||
</li>
|
||||
|
||||
<hr class="sidebar-divider">
|
||||
<div class="sidebar-heading">Módulos</div>
|
||||
|
||||
<!-- Herramientas del rol (collapse) -->
|
||||
<li class="nav-item">
|
||||
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#menuHerramientas"
|
||||
aria-expanded="false" aria-controls="menuHerramientas">
|
||||
<i class="fas fa-star" style="color:rgb(255,153,0)"></i>
|
||||
<span>{{ Auth::user()->getRoleNames()->first() }}</span>
|
||||
</a>
|
||||
<div id="menuHerramientas" class="collapse" data-parent="#accordionSidebar">
|
||||
<div class="bg-white py-2 collapse-inner rounded">
|
||||
<h6 class="collapse-header">Herramientas:</h6>
|
||||
|
||||
@can('plantel.index')
|
||||
<a class="collapse-item" href="{{ route('plantel.index') }}" style="color:#85888e">Planteles</a>
|
||||
<a class="collapse-item" href="{{ route('plantel.index') }}">Planteles</a>
|
||||
@endcan
|
||||
|
||||
@can('carrera.index')
|
||||
<a class="collapse-item" href="{{ route('carrera.index') }}" style="color:#85888e">Carreras</a>
|
||||
<a class="collapse-item" href="{{ route('carrera.index') }}">Carreras</a>
|
||||
@endcan
|
||||
|
||||
@can('duration.index')
|
||||
<a class="collapse-item" href="{{ route('duration.index') }}" style="color:#85888e">Duraciones</a>
|
||||
<a class="collapse-item" href="{{ route('duration.index') }}">Duraciones</a>
|
||||
@endcan
|
||||
|
||||
@can('plan.index')
|
||||
<a class="collapse-item" href="{{ route('plan.index') }}" style="color:#85888e">Planes de estudio</a>
|
||||
<a class="collapse-item" href="{{ route('plan.index') }}">Planes de estudio</a>
|
||||
@endcan
|
||||
|
||||
@can('nivel.index')
|
||||
<a class="collapse-item" href="{{ route('nivel.index') }}" style="color:#85888e">Niveles</a>
|
||||
<a class="collapse-item" href="{{ route('nivel.index') }}">Niveles</a>
|
||||
@endcan
|
||||
|
||||
@can('documentoTipo.index')
|
||||
<a class="collapse-item" href="{{ route('documentoTipo.index') }}" style="color:#85888e">Documentación</a>
|
||||
<a class="collapse-item" href="{{ route('documentoTipo.index') }}">Documentación</a>
|
||||
@endcan
|
||||
|
||||
@can('permission.index')
|
||||
<a class="collapse-item" href="{{ route('permission.index') }}" style="color:#85888e">Permisos</a>
|
||||
<a class="collapse-item" href="{{ route('permission.index') }}">Permisos</a>
|
||||
@endcan
|
||||
|
||||
@can('role.index')
|
||||
<a class="collapse-item" href="{{ route('role.index') }}" style="color:#85888e">Roles</a>
|
||||
<a class="collapse-item" href="{{ route('role.index') }}">Roles</a>
|
||||
@endcan
|
||||
|
||||
@can('user.index')
|
||||
<a class="collapse-item" href="{{ route('user.index') }}" style="color:#85888e">Usuarios</a>
|
||||
<a class="collapse-item" href="{{ route('user.index') }}">Usuarios</a>
|
||||
@endcan
|
||||
|
||||
@can('area.index')
|
||||
<a class="collapse-item" href="{{ route('area.index') }}" style="color:#85888e">Areas</a>
|
||||
<a class="collapse-item" href="{{ route('area.index') }}">Áreas</a>
|
||||
@endcan
|
||||
|
||||
@can('campan.index')
|
||||
<a class="collapse-item" href="{{ route('campan.index') }}" style="color:#85888e">Campañas</a>
|
||||
<a class="collapse-item" href="{{ route('campan.index') }}">Campañas</a>
|
||||
@endcan
|
||||
|
||||
@can('turno.index')
|
||||
<a class="collapse-item" href="{{ route('turno.index') }}" style="color:#85888e">Turnos</a>
|
||||
<a class="collapse-item" href="{{ route('turno.index') }}">Turnos</a>
|
||||
@endcan
|
||||
|
||||
@can('medio.index')
|
||||
<a class="collapse-item" href="{{ route('medio.index') }}" style="color:#85888e">Medios de contacto</a>
|
||||
<a class="collapse-item" href="{{ route('medio.index') }}">Medios de contacto</a>
|
||||
@endcan
|
||||
|
||||
@can('plane.index')
|
||||
<a class="collapse-item" href="{{ route('plane.index') }}" style="color:#85888e">Planes de pago</a>
|
||||
@can('plane.create')
|
||||
<a class="collapse-item" href="{{ route('plane.index') }}">Planes de pago</a>
|
||||
@endcan
|
||||
|
||||
@can('concepto.index')
|
||||
<a class="collapse-item" href="{{ route('concepto.index') }}" style="color:#85888e">Conceptos</a>
|
||||
<a class="collapse-item" href="{{ route('concepto.index') }}">Conceptos</a>
|
||||
@endcan
|
||||
|
||||
@can('mail.index')
|
||||
<a class="collapse-item" href="{{ route('mail.index') }}" style="color:#85888e">Mail</a>
|
||||
<a class="collapse-item" href="{{ route('mail.index') }}">Mail</a>
|
||||
@endcan
|
||||
|
||||
@can('areacode.index')
|
||||
<a class="collapse-item" href="{{ route('areacode.index') }}" style="color:#85888e">Códigos QR</a>
|
||||
<a class="collapse-item" href="{{ route('areacode.index') }}">Códigos QR</a>
|
||||
@endcan
|
||||
|
||||
@can('horario.index')
|
||||
<a class="collapse-item" href="{{ route('horario.index') }}" style="color:#85888e">Horarios</a>
|
||||
<a class="collapse-item" href="{{ route('horario.index') }}">Horarios</a>
|
||||
@endcan
|
||||
|
||||
<a class="collapse-item" href="{{ route('anuncio.index') }}" style="color:#85888e">
|
||||
<i class="fas fa-bullhorn mr-1"></i> Anuncios
|
||||
</a>
|
||||
|
||||
<a class="collapse-item" href="{{ route('evaluacion.index') }}" style="color:#85888e">
|
||||
<i class="fas fa-clipboard-list mr-1"></i> Evaluaciones
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@endrole
|
||||
|
||||
@hasrole('Promotor')
|
||||
<li class="nav-item">
|
||||
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#Promocion"
|
||||
aria-expanded="true" aria-controls="Promocion">
|
||||
<i class="fas fa-fw fa-bullhorn" style="color: #e8e8e8;"></i>
|
||||
<span>Promoción</span>
|
||||
</a>
|
||||
<div id="Promocion" class="collapse" aria-labelledby="Promocion" data-parent="#accordionSidebar">
|
||||
<div class="bg-white py-2 collapse-inner rounded">
|
||||
<h6 class="collapse-header">Herramientas</h6>
|
||||
|
||||
@can('alumno.index')
|
||||
<a class="collapse-item" href="{{ route('alumno.index') }}" style="color:#85888e">Prospectos</a>
|
||||
@can('anuncios.index')
|
||||
<a class="collapse-item" href="{{ route('anuncio.index') }}">Anuncios</a>
|
||||
@endcan
|
||||
<a class="collapse-item" href="difusion.php" style="color:#85888e">Difusión</a>
|
||||
<a class="collapse-item" href="informes.php" style="color:#85888e">Informes</a>
|
||||
<a class="collapse-item" href="referencias.php" style="color:#85888e">Referencias</a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@endrole
|
||||
|
||||
@hasrole('Control escolar')
|
||||
<li class="nav-item">
|
||||
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#ControlEscolar"
|
||||
aria-expanded="true" aria-controls="ControlEscolar">
|
||||
<i class="fas fa-fw fa-bullhorn" style="color: #e8e8e8;"></i>
|
||||
<span>Control Escolar</span>
|
||||
</a>
|
||||
<div id="ControlEscolar" class="collapse" aria-labelledby="ControlEscolar" data-parent="#accordionSidebar">
|
||||
<div class="bg-white py-2 collapse-inner rounded">
|
||||
<h6 class="collapse-header">Herramientas</h6>
|
||||
@can('evaluaciones.index')
|
||||
<a class="collapse-item" href="{{ route('evaluacion.index') }}">Evaluaciones</a>
|
||||
@endcan
|
||||
|
||||
@can('alumno.index')
|
||||
<a class="collapse-item" href="{{ route('alumno.index') }}" style="color:#85888e">Alumnos</a>
|
||||
<a class="collapse-item" href="{{ route('alumno.index') }}">Alumnos</a>
|
||||
@endcan
|
||||
|
||||
@can('grupo.index')
|
||||
<a class="collapse-item" href="{{ route('grupo.index') }}" style="color:#85888e">Grupos</a>
|
||||
<a class="collapse-item" href="{{ route('grupo.index') }}">Grupos</a>
|
||||
@endcan
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@endrole
|
||||
|
||||
@hasrole('Coordinación académica')
|
||||
<li class="nav-item">
|
||||
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#CoordinacionAcademica"
|
||||
aria-expanded="true" aria-controls="CoordinacionAcademica">
|
||||
<i class="fas fa-fw fa-bullhorn" style="color: #e8e8e8;"></i>
|
||||
<span>Coordinación académica</span>
|
||||
</a>
|
||||
<div id="CoordinacionAcademica" class="collapse" aria-labelledby="CoordinacionAcademica" data-parent="#accordionSidebar">
|
||||
<div class="bg-white py-2 collapse-inner rounded">
|
||||
<h6 class="collapse-header">Herramientas</h6>
|
||||
|
||||
@can('docente.index')
|
||||
<a class="collapse-item" href="{{ route('docente.index') }}" style="color:#85888e">Docentes</a>
|
||||
@endcan
|
||||
|
||||
@can('grupo.index')
|
||||
<a class="collapse-item" href="{{ route('grupo.index') }}" style="color:#85888e">Grupos</a>
|
||||
<a class="collapse-item" href="{{ route('docente.index') }}">Docentes</a>
|
||||
@endcan
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@endrole
|
||||
|
||||
@hasrole(['Alumno'])
|
||||
<hr class="sidebar-divider">
|
||||
<div class="sidebar-heading">Adicionales</div>
|
||||
|
||||
@can('pago.index')
|
||||
@can('pagar')
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ route('pago.index') }}">
|
||||
<i class="fas fa-money-bill-alt" style="color: #e8e8e8;"></i>
|
||||
<span>Mis pagos</span></a>
|
||||
<i class="fas fa-fw fa-money-bill-alt"></i>
|
||||
<span>Mis pagos</span>
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
|
||||
@can('tareas.entrega')
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ route('mis.tareas') }}">
|
||||
<i class="fas fa-fw fa-tasks" style="color: #e8e8e8;"></i>
|
||||
<i class="fas fa-fw fa-tasks"></i>
|
||||
<span>Mis Tareas</span>
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
|
||||
@can('evaluaciones.responder')
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ route('evaluacion.mis_evaluaciones') }}">
|
||||
<i class="fa-duotone fa-regular fa-clipboard-list" style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);"></i>
|
||||
<span>Encuestas</span></a>
|
||||
<i class="fas fa-fw fa-clipboard-list"></i>
|
||||
<span>Encuestas</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@endrole
|
||||
|
||||
@hasrole(['Docente'])
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ route('grupo.index') }}">
|
||||
<i class="fa-duotone fa-regular fa-user-group" style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);"></i>
|
||||
<span>Mis grupos</span></a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ route('evaluacion.mis_evaluaciones') }}">
|
||||
<i class="fa-duotone fa-regular fa-clipboard-list " style="--fa-primary-color: rgb(255, 255, 255); --fa-secondary-color: rgb(255, 255, 255);"></i>
|
||||
<span>Encuestas</span></a>
|
||||
</li>
|
||||
@endrole
|
||||
|
||||
|
||||
<!-- Divider -->
|
||||
<hr class="sidebar-divider">
|
||||
<!-- Heading -->
|
||||
<div class="sidebar-heading" style="color:white">Adicionales</div>
|
||||
@endcan
|
||||
|
||||
@can('comunidad')
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ route('feed') }}">
|
||||
<i class="fas fa-fw fa-stream" style="color:#e8e8e8"></i>
|
||||
<i class="fas fa-fw fa-stream"></i>
|
||||
<span>Comunidad</span>
|
||||
</a>
|
||||
</li>
|
||||
@@ -243,7 +169,7 @@
|
||||
@can('amigos')
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ route('friendships.index') }}">
|
||||
<i class="fas fa-fw fa-user-friends" style="color:#e8e8e8"></i>
|
||||
<i class="fas fa-fw fa-user-friends"></i>
|
||||
<span>Amigos</span>
|
||||
</a>
|
||||
</li>
|
||||
@@ -252,7 +178,7 @@
|
||||
@can('mensajes')
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{ route('chat.index') }}">
|
||||
<i class="fas fa-fw fa-comment-dots" style="color:#e8e8e8"></i>
|
||||
<i class="fas fa-fw fa-comment-dots"></i>
|
||||
<span>Mensajes</span>
|
||||
</a>
|
||||
</li>
|
||||
@@ -260,35 +186,33 @@
|
||||
|
||||
@can('asistencia')
|
||||
<li class="nav-item">
|
||||
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapseUtilities"
|
||||
aria-expanded="true" aria-controls="collapseUtilities">
|
||||
<i class="fas fa-id-badge" style="color: #e8e8e8;"></i>
|
||||
<a class="nav-link collapsed" href="#" data-toggle="collapse" data-target="#collapseAsistencia"
|
||||
aria-expanded="false" aria-controls="collapseAsistencia">
|
||||
<i class="fas fa-fw fa-id-badge"></i>
|
||||
<span>Asistencia</span>
|
||||
</a>
|
||||
<div id="collapseUtilities" class="collapse" aria-labelledby="headingUtilities"
|
||||
data-parent="#accordionSidebar">
|
||||
<div id="collapseAsistencia" class="collapse" data-parent="#accordionSidebar">
|
||||
<div class="bg-white py-2 collapse-inner rounded">
|
||||
<h6 class="collapse-header">Herramientas:</h6>
|
||||
<a class="collapse-item" href="{{ route('code.index') }}" style="color:gray">Escanear</a>
|
||||
<a class="collapse-item" href="{{ route('registros') }}" style="color:gray">Registros</a>
|
||||
<a class="collapse-item" href="{{ route('code.index') }}">Escanear</a>
|
||||
<a class="collapse-item" href="{{ route('registros') }}">Registros</a>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
@endcan
|
||||
|
||||
|
||||
|
||||
<!-- Nav Item - notes -->
|
||||
@can('note.index')
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{{route('note.index')}}">
|
||||
<i class="fas fa-fw fa-sticky-note" style="color: #e8e8e8;"></i>
|
||||
<span>Notas</span></a>
|
||||
<a class="nav-link" href="{{ route('note.index') }}">
|
||||
<i class="fas fa-fw fa-sticky-note"></i>
|
||||
<span>Notas</span>
|
||||
</a>
|
||||
</li>
|
||||
@endcan
|
||||
|
||||
<!-- Sidebar Toggler (Sidebar) -->
|
||||
<!-- Sidebar Toggler -->
|
||||
<div class="text-center d-none d-md-inline">
|
||||
<button class="rounded-circle border-0" id="sidebarToggle"></button>
|
||||
</div>
|
||||
|
||||
</ul>
|
||||
|
||||
@@ -17,3 +17,22 @@
|
||||
<!-- <script src="{{asset('assets/vendor/chart.js/Chart.min.js')}}"></script>
|
||||
<script src="{{asset('assets/js/demo/chart-area-demo.js')}}"></script>
|
||||
<script src="{{asset('assets/js/demo/chart-pie-demo.js')}}"></script> -->
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
function verDocumento(url) {
|
||||
document.getElementById('visorFrame').src = url + '?t=' + new Date().getTime();
|
||||
|
||||
var modal = new bootstrap.Modal(document.getElementById('visorModal'));
|
||||
modal.show();
|
||||
}
|
||||
|
||||
document.getElementById('visorModal').addEventListener('hidden.bs.modal', function () {
|
||||
document.getElementById('visorFrame').src = '';
|
||||
});
|
||||
function updateFileName(input, targetId) {
|
||||
const fileName = input.files[0]?.name || 'Ningún archivo seleccionado';
|
||||
document.getElementById(targetId).textContent = fileName;
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -9,27 +9,42 @@
|
||||
@endphp
|
||||
|
||||
<div class="mb-2">
|
||||
<strong>{{ strtoupper($tipo->name) }}</strong> :
|
||||
|
||||
@if($doc)
|
||||
|
||||
@if($doc->status == 1)
|
||||
<span class="badge bg-success">✔ Validado</span>
|
||||
@elseif($doc->status == 2)
|
||||
<span class="badge bg-danger">✘ Rechazado</span>
|
||||
@else
|
||||
<span class="badge bg-warning">Pendiente</span>
|
||||
@endif
|
||||
<div class="alert alert-success d-sm-flex align-items-center justify-content-between">
|
||||
<strong>{{ strtoupper($tipo->name) }} : Validado</strong>
|
||||
|
||||
<button
|
||||
onclick="verDocumento('{{ url('documento/ver/'.$doc->id) }}', {{ $doc->id }})"
|
||||
class="btn btn-sm btn-primary ms-2"
|
||||
>
|
||||
Ver
|
||||
class="btn btn-sm btn-primary mt-2">
|
||||
<i class="fa-duotone fa-solid fa-eye"></i> Ver documento
|
||||
</button>
|
||||
</div>
|
||||
@elseif($doc->status == 2)
|
||||
<div class="alert alert-danger">
|
||||
<strong>{{ strtoupper($tipo->name) }} : Rechazado</strong>
|
||||
</div>
|
||||
|
||||
@else
|
||||
<span class="text-danger">✘ Faltante</span>
|
||||
<div class="alert alert-warning d-sm-flex align-items-center justify-content-between" >
|
||||
|
||||
<strong>{{ strtoupper($tipo->name) }} : Pendiente de revisión</strong>
|
||||
|
||||
<button
|
||||
onclick="verDocumento('{{ url('documento/ver/'.$doc->id) }}', {{ $doc->id }})"
|
||||
class="btn btn-sm btn-primary mt-2">
|
||||
<i class="fa-duotone fa-solid fa-eye"></i> Ver documento
|
||||
</button>
|
||||
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@else
|
||||
<div class="alert alert-danger">
|
||||
<strong>{{ strtoupper($tipo->name) }} : Faltante</strong>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
|
||||
@@ -84,10 +84,9 @@
|
||||
<i class="fas fa-chevron-down"></i>
|
||||
</button>
|
||||
<button type="button"
|
||||
wire:click="removePregunta({{ $i }})"
|
||||
class="btn btn-outline-danger"
|
||||
title="Eliminar"
|
||||
onclick="return confirm('¿Eliminar esta pregunta?')">
|
||||
onclick="confirmarEliminarPregunta({{ $i }}, this)">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
@@ -410,3 +409,25 @@
|
||||
</div>{{-- fin columna lateral --}}
|
||||
</div>{{-- fin row --}}
|
||||
</div>
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
function confirmarEliminarPregunta(index, el) {
|
||||
Swal.fire({
|
||||
title: '¿Eliminar pregunta?',
|
||||
text: 'Esta acción no se puede deshacer.',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Sí, eliminar',
|
||||
cancelButtonText: 'Cancelar',
|
||||
confirmButtonColor: '#e74a3b',
|
||||
cancelButtonColor: '#6c757d',
|
||||
}).then(result => {
|
||||
if (result.isConfirmed) {
|
||||
const wireEl = el.closest('[wire\\:id]');
|
||||
Livewire.find(wireEl.getAttribute('wire:id')).call('removePregunta', index);
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
@@ -169,28 +169,7 @@
|
||||
|
||||
});
|
||||
|
||||
function verDocumento(url) {
|
||||
document.getElementById('visorFrame').src = url + '?t=' + new Date().getTime();
|
||||
|
||||
var modal = new bootstrap.Modal(document.getElementById('visorModal'));
|
||||
modal.show();
|
||||
}
|
||||
|
||||
// 🔥 limpiar iframe al cerrar
|
||||
document.getElementById('visorModal').addEventListener('hidden.bs.modal', function () {
|
||||
document.getElementById('visorFrame').src = '';
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function updateFileName(input, targetId) {
|
||||
const fileName = input.files[0]?.name || 'Ningún archivo seleccionado';
|
||||
document.getElementById(targetId).textContent = fileName;
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<script>
|
||||
Livewire.on('saved', () => {
|
||||
Swal.fire({
|
||||
icon: 'success',
|
||||
|
||||
@@ -18,9 +18,13 @@
|
||||
<button type="button" class="close" data-dismiss="alert"><span>×</span></button>
|
||||
</div>
|
||||
@endif
|
||||
@if ($errors->has('entrega'))
|
||||
@if ($errors->any())
|
||||
<div class="alert alert-warning alert-dismissible fade show">
|
||||
<strong>{{ $errors->first('entrega') }}</strong>
|
||||
<ul class="mb-0">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
<button type="button" class="close" data-dismiss="alert"><span>×</span></button>
|
||||
</div>
|
||||
@endif
|
||||
@@ -195,7 +199,7 @@
|
||||
<div class="card-header d-flex justify-content-between align-items-center"
|
||||
data-toggle="collapse"
|
||||
data-target="#entr-mat-{{ $materialId }}"
|
||||
aria-expanded="false"
|
||||
aria-expanded="true"
|
||||
style="cursor:pointer; user-select:none;">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="fas fa-book-open mr-2 text-success"></i>
|
||||
@@ -223,7 +227,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="entr-mat-{{ $materialId }}" class="collapse">
|
||||
<div id="entr-mat-{{ $materialId }}" class="collapse show">
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm table-hover mb-0">
|
||||
|
||||
@@ -18,6 +18,7 @@ use App\Http\Controllers\ConceptoController;
|
||||
use App\Http\Controllers\DocenteController;
|
||||
use App\Http\Controllers\EntregaController;
|
||||
use App\Http\Controllers\EvaluacionController;
|
||||
use App\Http\Controllers\EvaluacionReporteController;
|
||||
use App\Http\Controllers\EvaluacionResponderController;
|
||||
use App\Http\Controllers\TareaController;
|
||||
use App\Http\Controllers\DocumentoController;
|
||||
@@ -92,6 +93,8 @@ Route::middleware(['auth:sanctum',config('jetstream.auth_session'),'verified',
|
||||
// Evaluaciones (administración)
|
||||
Route::resource('/evaluacion', EvaluacionController::class);
|
||||
Route::patch('/evaluacion/{evaluacion}/status', [EvaluacionController::class, 'toggleStatus'])->name('evaluacion.toggleStatus');
|
||||
Route::get('/evaluacion/{evaluacion}/reporte', [EvaluacionReporteController::class, 'show'])->name('evaluacion.reporte.show');
|
||||
Route::get('/evaluacion/{evaluacion}/reporte/pdf', [EvaluacionReporteController::class, 'pdf'])->name('evaluacion.reporte.pdf');
|
||||
|
||||
// Evaluaciones (responder — docentes y alumnos)
|
||||
Route::get('/mis-evaluaciones', [EvaluacionResponderController::class, 'misEvaluaciones'])->name('evaluacion.mis_evaluaciones');
|
||||
|
||||
Reference in New Issue
Block a user