Loading app/Exports/ListasExport.php 0 → 100644 +145 −0 Original line number Diff line number Diff line <?php namespace App\Exports; use App\Models\Lista; use Illuminate\Support\Collection; use Maatwebsite\Excel\Concerns\FromCollection; use Maatwebsite\Excel\Concerns\WithHeadings; class ListasExport implements FromCollection, WithHeadings { protected $extraFields; protected $lista_id; public function __construct($lista_id, $extraFields = []) { $this->lista_id = $lista_id; $this->extraFields = $extraFields; } public function collection() { $lista = Lista::with(['grupos', 'subgrupos', 'contactos'])->find($this->lista_id); $contactos = new Collection(); $contactos = $contactos->merge($lista->contactos); foreach ($lista->grupos as $grupo) { $contactos = $contactos->merge($grupo->contactos); foreach ($grupo->subgrupos as $subgrupo) { $contactos = $contactos->merge($subgrupo->contactos); } } foreach($lista->subgrupos as $subgrupo){ $contactos = $contactos->merge($subgrupo->contactos); } $contactos = $contactos->unique('id'); return $contactos->map(function($contacto){ return $this->formatContactoData($contacto); }); } public function headings(): array { $defaultHeadings = ['Profesión', 'Nombre', 'Apellido Paterno', 'Apellido Materno', 'Cargo', 'Descripción del cargo', 'Grupo', 'Subgrupo']; $extraHeadings = $this->getExtraHeadings(); return array_merge($defaultHeadings, $extraHeadings); } private function formatContactoData($contacto) { $defaultData = [ 'Profesión' => $contacto->profesion->abreviatura ?? 'N/A', 'Nombre' => $contacto->nombre, 'Apellido Paterno' => $contacto->ap_paterno, 'Apellido Materno' => $contacto->ap_materno ?? '', 'Cargo' => $contacto->cargo->nombre ?? 'N/A', 'Descripción del cargo' => $contacto->cargo_desc ?? 'N/A', 'Grupo' => $contacto->grupos->pluck('nombre')[0] ?? 'N/A', 'Subgrupo' => $contacto->subgrupos->pluck('nombre')[0] ?? 'N/A', ]; $extraData = []; $fields = $this->extraFields; if (in_array('todos', $fields)) { $fields = ['domicilio', 'cumpleanos', 'telefonos', 'conyuge', 'email']; } foreach ($fields as $field) { switch ($field) { case 'domicilio': $extraData = array_merge($extraData, [ 'Domicilio Oficial' => $contacto->domicilio_oficial ?? 'N/A', 'Código Postal' => $contacto->codigo_postal ?? 'N/A', 'Localidad Oficial' => $contacto->localidad_oficial ?? 'N/A', 'Municipio Oficial' => $contacto->municipio_oficial ?? 'N/A', 'Estado' => $contacto->estado ?? 'N/A', 'País' => $contacto->pais ?? 'N/A', ]); break; case 'cumpleanos': $extraData['Cumpleaños'] = $contacto->mes_cump && $contacto->dia_cump ? $contacto->mes_cump . '/' . $contacto->dia_cump : 'N/A'; break; case 'telefonos': $extraData = array_merge($extraData, [ 'Número de teléfono' => $contacto->telefonos->pluck('numero')->join(', ') ?? 'N/A', 'Tipo' => $contacto->telefonos->pluck('tipo')->join(', ') ?? 'N/A', 'Estatus' => $contacto->telefonos->pluck('estatus')->join(', ') ?? 'N/A', 'Extensión' => $contacto->telefonos->pluck('ext')->join(', ') ?? 'N/A', 'Observaciones' => $contacto->telefonos->pluck('observaciones')->join(', ') ?? 'N/A', ]); break; case 'conyuge': $extraData['Cónyuge'] = $contacto->pareja ? $contacto->pareja->nombre . ' ' . $contacto->pareja->ap_paterno . ' ' . $contacto->pareja->ap_materno : 'N/A'; break; case 'email': $extraData = array_merge($extraData, [ 'Correo Electrónico' => $contacto->correos->pluck('correo_electronico')->join(', ') ?? 'N/A', 'Tipo de Correo Electrónico' => $contacto->correos->pluck('tipo_correo_electronico')->join(', ') ?? 'N/A', ]); break; } } return array_merge($defaultData, $extraData); } private function getExtraHeadings() { $headings = []; $fields = $this->extraFields; if (in_array('todos', $fields)) { $fields = ['domicilio', 'cumpleanos', 'telefonos', 'conyuge', 'email']; } foreach ($fields as $field) { switch ($field) { case 'domicilio': $headings = array_merge($headings, ['Domicilio Oficial', 'Código Postal', 'Localidad Oficial', 'Municipio Oficial', 'Estado', 'País']); break; case 'cumpleanos': $headings[] = 'Cumpleaños'; break; case 'telefonos': $headings = array_merge($headings, ['Número de teléfono', 'Tipo', 'Estatus', 'Extensión', 'Observaciones']); break; case 'conyuge': $headings[] = 'Cónyuge'; break; case 'email': $headings = array_merge($headings, ['Correo Electrónico', 'Tipo de Correo Electrónico']); break; } } return $headings; } } app/Http/Controllers/ReporteController.php +77 −26 Original line number Diff line number Diff line Loading @@ -10,10 +10,12 @@ use Illuminate\Http\Request; use App\Exports\ContactosExport; use App\Exports\ListasExport; use Barryvdh\DomPDF\Facade\Pdf; use Illuminate\Support\Facades\Storage; use Maatwebsite\Excel\Facades\Excel; use ZipArchive; use Illuminate\Support\Str; class ReporteController extends Controller { Loading Loading @@ -102,11 +104,12 @@ public function export(Request $request) 'mesFin' => $request->input('mesFin'), 'diaFin' => $request->input('diaFin'), ]; try{ $export = new ContactosExport($contactIds, $extraFields, $filters); if($request->archivo == 'excel'){ return Excel::download($export, 'contactos.xlsx'); }else if($request->archivo == 'pdf'){ $pdf = Pdf::loadView('adminGen.contactos.contactos_pdf', ['contactos' => $export->collection()])->setPaper('A1', 'landscape');; $pdf = Pdf::loadView('adminGen.contactos.contactos_pdf', ['contactos' => $export->collection()])->setPaper('A1', 'landscape'); return $pdf->download('contactos.pdf'); }else if($request->archivo == 'ambos'){ $excelPath = storage_path('app/public/contactos.xlsx'); Loading @@ -128,8 +131,12 @@ public function export(Request $request) // Descargar archivo ZIP return response()->download($zipPath)->deleteFileAfterSend(true); }else{ return response()->json(['Error, No seleccionaste un archivo de exportación valido.'], 400); return response()->json(['Error, no seleccionaste un archivo de exportación valido.'], 400); } }catch(\Exception $e){ return response()->json(['message'=> $e->getMessage()], 500); } } public function getSubgrupos(Int $id) Loading @@ -137,4 +144,48 @@ public function getSubgrupos(Int $id) $grupo = Grupos::find($id); return response()->json($grupo->subgrupos); } public function exportListas(Request $request) { try{ if(is_null($request->archivo)){ return response()->json(['Error, No seleccionaste un archivo de exportación valido.'], 400); } $extraFields = $request->input('exportar', []); if(!$extraFields){ return response()->json(['Error, No seleccionaste campos a exportar.'], 400); } $lista_id = $request->input('id'); $export = new ListasExport($lista_id, $extraFields); $uuid = Str::uuid()->toString(); if($request->archivo == 'excel'){ return Excel::download($export, $uuid . '.xlsx'); }else if($request->archivo == 'pdf'){ $pdf = Pdf::loadView('adminGen.contactos.contactos_pdf', ['contactos' => $export->collection()])->setPaper('A1', 'landscape'); return $pdf->download($uuid.'.pdf'); }else if($request->archivo == 'ambos'){ $excelPath = storage_path('app/public/contactos.xlsx'); $pdfPath = storage_path('app/public/contactos.pdf'); Excel::store($export, 'public/contactos.xlsx'); $pdf = Pdf::loadView('adminGen.contactos.contactos_pdf', ['contactos' => $export->collection()])->setPaper('A1', 'landscape'); Storage::put('public/contactos.pdf', $pdf->output()); $zipPath = storage_path('app/public/'.$uuid.'.zip'); $zip = new ZipArchive; if ($zip->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) === TRUE) { $zip->addFile($excelPath, $uuid.'.xlsx'); $zip->addFile($pdfPath, $uuid.'.pdf'); $zip->close(); } return response()->download($zipPath)->deleteFileAfterSend(true); }else{ return response()->json(['message' => 'Error, no seleccionaste un archivo de exportación valido.'], 400); } }catch(\Exception $e){ return response()->json(['message' => $e->getMessage()], 500); } } } app/Models/Subgrupo.php +1 −1 Original line number Diff line number Diff line Loading @@ -34,6 +34,6 @@ public function listas(): BelongsToMany public function contactos(): BelongsToMany { return $this->belongsToMany(Contacto::class, 'contactos_subgrupos', 'contacto_id', 'subgrupo_id'); return $this->belongsToMany(Contacto::class, 'contactos_subgrupos', 'subgrupo_id', 'contacto_id'); } } resources/views/adminGen/listas/show.blade.php +201 −1 Original line number Diff line number Diff line Loading @@ -14,6 +14,58 @@ </ul> <div class="pt-5"> <div class="grid grid-cols-1 lg:grid-cols-3 xl:grid-cols-4 gap-5 mb-5"> <div class="panel lg:col-span-4 xl:col-span-4"> <div class="mb-5"> <h5 class="font-semibold text-lg dark:text-white-light">Exportar datos</h5> </div> <div class="mb-5"> <div class="text-[#515365] dark:text-white-light font-semibold p-4 bg-white rounded-lg shadow"> <form method="GET" action="" class="space-y-4" onsubmit="event.preventDefault(); logData();"> <!-- Contenedor de selects alineados --> <div class="grid grid-cols-2 gap-4 items-center"> <!-- Tipo de archivo a exportar --> <div> <label for="archivo" class="text-gray-700 font-semibold block mb-1">Tipo de archivo:</label> <select id="archivo" class="w-full px-3 py-2 bg-white border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500"> <option value="" disabled selected>Selecciona el formato de archivo a exportar</option> <option value="ambos">Ambos</option> <option value="pdf">PDF</option> <option value="excel">Excel</option> </select> </div> <!-- Campos a exportar --> <div> <label for="exportar" class="text-gray-700 font-semibold block mb-1">Campos:</label> <div class="flex items-center space-x-2"> <select id="exportar" class="w-full px-3 py-2 bg-white border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500"> <option value="" disabled selected>Selecciona los campos a exportar</option> <option value="todos">Todos</option> <option value="conyuge">Cónyuge</option> <option value="domicilio">Domicilio</option> <option value="cumpleanos">Cumpleaños</option> <option value="email">Correo electrónico</option> <option value="telefonos">Teléfonos</option> </select> <button type="button" onclick="agregarEtiqueta('exportar', 'exportarAgregados')" class="bg-blue-500 text-white px-3 py-2 rounded-md shadow hover:bg-blue-600 transition"> Agregar </button> </div> </div> <div id="exportarAgregados" class="flex flex-wrap gap-2 mt-2"></div> </div> <!-- Botón para aplicar filtros --> <div class="flex justify-end"> <button type="submit" class="px-4 py-2 bg-blue-500 text-white font-semibold rounded-md shadow hover:bg-blue-600 transition"> Aplicar Filtros </button> </div> </form> </div> </div> </div> <div class="panel lg:col-span-2 xl:col-span-2"> <div class="mb-5"> <h5 class="font-semibold text-lg dark:text-white-light">Grupos</h5> Loading Loading @@ -93,5 +145,153 @@ class="btn btn-primary"> </a> </div> </div> <div id="loader-container" class="fixed inset-0 flex items-center justify-center bg-gray-500 bg-opacity-75 hidden"> <span id="loader" class="animate-spin border-8 border-gray-300 border-l-[#780005] border-r-[#780005] rounded-full w-14 h-14"></span> </div> </div> <link rel="stylesheet" href="{{ Vite::asset('resources/css/highlight.min.css') }}"> <script src="/assets/js/highlight.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <link rel="stylesheet" href="/assets/css/jquery.toast.css"> <script src="/assets/js/jquery.toast.js"></script> <script> let exportarSeleccion = []; function agregarEtiqueta(selectId, containerId){ const select = document.getElementById(selectId); const selectedOption = select.options[select.selectedIndex]; if(selectedOption && selectedOption.value){ const container = document.getElementById(containerId); const etiquetaId = `${selectId}-${selectedOption.value}`; if(!document.getElementById(etiquetaId)){ switch(selectId){ case 'exportar': exportarSeleccion.push(selectedOption.value); break; default: break; } const etiqueta = document.createElement('div'); etiqueta.id = etiquetaId; etiqueta.classList.add('inline-block', 'bg-gray-200', 'px-4', 'py-2', 'rounded', 'mr-2', 'mt-2'); etiqueta.innerHTML = `${selectedOption.text} <button type="button" onclick="eliminarEtiqueta('${etiquetaId}')" class="text-red-500">x</button>`; const inputHidden = document.createElement('input'); inputHidden.type = 'hidden'; inputHidden.name = `${selectId}[]`; inputHidden.value = selectedOption.value; etiqueta.appendChild(inputHidden); container.appendChild(etiqueta); select,selectedIndex = 0; } } } function eliminarEtiqueta(etiquetaId){ const etiqueta = document.getElementById(etiquetaId); if(etiqueta){ etiqueta.remove(); const [selectId, value] = etiquetaId.split('-'); switch(selectId){ case 'exportar': exportarSeleccion = exportarSeleccion.filter(item => item !== value); break; default: break; } } } function logData(){ const select = document.getElementById('archivo'); const selectedOption = select.options[select.selectedIndex]; const data = { archivo: selectedOption.value, exportar: exportarSeleccion, id: {{$lista->id}}, }; document.getElementById('loader-container').classList.remove('hidden'); document.querySelector('form').classList.add('pointer-events-none'); fetch('/reportes/listas/exportar', { method: 'POST', body: JSON.stringify(data), headers:{ "Content-Type": "application/json; charset=utf-8", "X-CSRF-TOKEN": "{{ csrf_token() }}" } }) .then(response => { if(!response.ok){ return response.json().then(err => { throw err; }); } const contentDisposition = response.headers.get('Content-Disposition'); let filename = "reporte.xlsx"; if(contentDisposition){ const match = contentDisposition.match(/filename="?([^"]+)"?/); if(match && match[1]){ filename = match[1]; } } return response.blob().then(blob => ({blob, filename})); }) .then(({blob, filename}) => { const url = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = filename; document.body.appendChild(link); link.click(); link.remove(); window.URL.revokeObjectURL(url); }) .catch(err => { showToast(err, 'Error.', 'error'); }) .finally(() => { document.getElementById('loader-container').classList.add('hidden'); document.querySelector('form').classList.remove('pointer-events-none'); }); } function showToast(message, heading, icon) { $.toast({ heading: heading, text: message, showHideTransition: 'slide', icon: icon, position: 'top-right', loader: false, hideAfter: 10000, allowToastClose: true, textColor: '#676767', }); } document.addEventListener('DOMContentLoaded', function() { @if(session('success')) // Muestra el mensaje de éxito utilizando showMessage showToast("{{ session('success') }}", 'Exito.', 'success') @endif @if($errors->any()) @foreach($errors->all() as $error) showToast(`{{ $error }}`, 'Error.', 'error'); @endforeach @endif }); </script> </x-layout.default> No newline at end of file Loading
app/Exports/ListasExport.php 0 → 100644 +145 −0 Original line number Diff line number Diff line <?php namespace App\Exports; use App\Models\Lista; use Illuminate\Support\Collection; use Maatwebsite\Excel\Concerns\FromCollection; use Maatwebsite\Excel\Concerns\WithHeadings; class ListasExport implements FromCollection, WithHeadings { protected $extraFields; protected $lista_id; public function __construct($lista_id, $extraFields = []) { $this->lista_id = $lista_id; $this->extraFields = $extraFields; } public function collection() { $lista = Lista::with(['grupos', 'subgrupos', 'contactos'])->find($this->lista_id); $contactos = new Collection(); $contactos = $contactos->merge($lista->contactos); foreach ($lista->grupos as $grupo) { $contactos = $contactos->merge($grupo->contactos); foreach ($grupo->subgrupos as $subgrupo) { $contactos = $contactos->merge($subgrupo->contactos); } } foreach($lista->subgrupos as $subgrupo){ $contactos = $contactos->merge($subgrupo->contactos); } $contactos = $contactos->unique('id'); return $contactos->map(function($contacto){ return $this->formatContactoData($contacto); }); } public function headings(): array { $defaultHeadings = ['Profesión', 'Nombre', 'Apellido Paterno', 'Apellido Materno', 'Cargo', 'Descripción del cargo', 'Grupo', 'Subgrupo']; $extraHeadings = $this->getExtraHeadings(); return array_merge($defaultHeadings, $extraHeadings); } private function formatContactoData($contacto) { $defaultData = [ 'Profesión' => $contacto->profesion->abreviatura ?? 'N/A', 'Nombre' => $contacto->nombre, 'Apellido Paterno' => $contacto->ap_paterno, 'Apellido Materno' => $contacto->ap_materno ?? '', 'Cargo' => $contacto->cargo->nombre ?? 'N/A', 'Descripción del cargo' => $contacto->cargo_desc ?? 'N/A', 'Grupo' => $contacto->grupos->pluck('nombre')[0] ?? 'N/A', 'Subgrupo' => $contacto->subgrupos->pluck('nombre')[0] ?? 'N/A', ]; $extraData = []; $fields = $this->extraFields; if (in_array('todos', $fields)) { $fields = ['domicilio', 'cumpleanos', 'telefonos', 'conyuge', 'email']; } foreach ($fields as $field) { switch ($field) { case 'domicilio': $extraData = array_merge($extraData, [ 'Domicilio Oficial' => $contacto->domicilio_oficial ?? 'N/A', 'Código Postal' => $contacto->codigo_postal ?? 'N/A', 'Localidad Oficial' => $contacto->localidad_oficial ?? 'N/A', 'Municipio Oficial' => $contacto->municipio_oficial ?? 'N/A', 'Estado' => $contacto->estado ?? 'N/A', 'País' => $contacto->pais ?? 'N/A', ]); break; case 'cumpleanos': $extraData['Cumpleaños'] = $contacto->mes_cump && $contacto->dia_cump ? $contacto->mes_cump . '/' . $contacto->dia_cump : 'N/A'; break; case 'telefonos': $extraData = array_merge($extraData, [ 'Número de teléfono' => $contacto->telefonos->pluck('numero')->join(', ') ?? 'N/A', 'Tipo' => $contacto->telefonos->pluck('tipo')->join(', ') ?? 'N/A', 'Estatus' => $contacto->telefonos->pluck('estatus')->join(', ') ?? 'N/A', 'Extensión' => $contacto->telefonos->pluck('ext')->join(', ') ?? 'N/A', 'Observaciones' => $contacto->telefonos->pluck('observaciones')->join(', ') ?? 'N/A', ]); break; case 'conyuge': $extraData['Cónyuge'] = $contacto->pareja ? $contacto->pareja->nombre . ' ' . $contacto->pareja->ap_paterno . ' ' . $contacto->pareja->ap_materno : 'N/A'; break; case 'email': $extraData = array_merge($extraData, [ 'Correo Electrónico' => $contacto->correos->pluck('correo_electronico')->join(', ') ?? 'N/A', 'Tipo de Correo Electrónico' => $contacto->correos->pluck('tipo_correo_electronico')->join(', ') ?? 'N/A', ]); break; } } return array_merge($defaultData, $extraData); } private function getExtraHeadings() { $headings = []; $fields = $this->extraFields; if (in_array('todos', $fields)) { $fields = ['domicilio', 'cumpleanos', 'telefonos', 'conyuge', 'email']; } foreach ($fields as $field) { switch ($field) { case 'domicilio': $headings = array_merge($headings, ['Domicilio Oficial', 'Código Postal', 'Localidad Oficial', 'Municipio Oficial', 'Estado', 'País']); break; case 'cumpleanos': $headings[] = 'Cumpleaños'; break; case 'telefonos': $headings = array_merge($headings, ['Número de teléfono', 'Tipo', 'Estatus', 'Extensión', 'Observaciones']); break; case 'conyuge': $headings[] = 'Cónyuge'; break; case 'email': $headings = array_merge($headings, ['Correo Electrónico', 'Tipo de Correo Electrónico']); break; } } return $headings; } }
app/Http/Controllers/ReporteController.php +77 −26 Original line number Diff line number Diff line Loading @@ -10,10 +10,12 @@ use Illuminate\Http\Request; use App\Exports\ContactosExport; use App\Exports\ListasExport; use Barryvdh\DomPDF\Facade\Pdf; use Illuminate\Support\Facades\Storage; use Maatwebsite\Excel\Facades\Excel; use ZipArchive; use Illuminate\Support\Str; class ReporteController extends Controller { Loading Loading @@ -102,11 +104,12 @@ public function export(Request $request) 'mesFin' => $request->input('mesFin'), 'diaFin' => $request->input('diaFin'), ]; try{ $export = new ContactosExport($contactIds, $extraFields, $filters); if($request->archivo == 'excel'){ return Excel::download($export, 'contactos.xlsx'); }else if($request->archivo == 'pdf'){ $pdf = Pdf::loadView('adminGen.contactos.contactos_pdf', ['contactos' => $export->collection()])->setPaper('A1', 'landscape');; $pdf = Pdf::loadView('adminGen.contactos.contactos_pdf', ['contactos' => $export->collection()])->setPaper('A1', 'landscape'); return $pdf->download('contactos.pdf'); }else if($request->archivo == 'ambos'){ $excelPath = storage_path('app/public/contactos.xlsx'); Loading @@ -128,8 +131,12 @@ public function export(Request $request) // Descargar archivo ZIP return response()->download($zipPath)->deleteFileAfterSend(true); }else{ return response()->json(['Error, No seleccionaste un archivo de exportación valido.'], 400); return response()->json(['Error, no seleccionaste un archivo de exportación valido.'], 400); } }catch(\Exception $e){ return response()->json(['message'=> $e->getMessage()], 500); } } public function getSubgrupos(Int $id) Loading @@ -137,4 +144,48 @@ public function getSubgrupos(Int $id) $grupo = Grupos::find($id); return response()->json($grupo->subgrupos); } public function exportListas(Request $request) { try{ if(is_null($request->archivo)){ return response()->json(['Error, No seleccionaste un archivo de exportación valido.'], 400); } $extraFields = $request->input('exportar', []); if(!$extraFields){ return response()->json(['Error, No seleccionaste campos a exportar.'], 400); } $lista_id = $request->input('id'); $export = new ListasExport($lista_id, $extraFields); $uuid = Str::uuid()->toString(); if($request->archivo == 'excel'){ return Excel::download($export, $uuid . '.xlsx'); }else if($request->archivo == 'pdf'){ $pdf = Pdf::loadView('adminGen.contactos.contactos_pdf', ['contactos' => $export->collection()])->setPaper('A1', 'landscape'); return $pdf->download($uuid.'.pdf'); }else if($request->archivo == 'ambos'){ $excelPath = storage_path('app/public/contactos.xlsx'); $pdfPath = storage_path('app/public/contactos.pdf'); Excel::store($export, 'public/contactos.xlsx'); $pdf = Pdf::loadView('adminGen.contactos.contactos_pdf', ['contactos' => $export->collection()])->setPaper('A1', 'landscape'); Storage::put('public/contactos.pdf', $pdf->output()); $zipPath = storage_path('app/public/'.$uuid.'.zip'); $zip = new ZipArchive; if ($zip->open($zipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) === TRUE) { $zip->addFile($excelPath, $uuid.'.xlsx'); $zip->addFile($pdfPath, $uuid.'.pdf'); $zip->close(); } return response()->download($zipPath)->deleteFileAfterSend(true); }else{ return response()->json(['message' => 'Error, no seleccionaste un archivo de exportación valido.'], 400); } }catch(\Exception $e){ return response()->json(['message' => $e->getMessage()], 500); } } }
app/Models/Subgrupo.php +1 −1 Original line number Diff line number Diff line Loading @@ -34,6 +34,6 @@ public function listas(): BelongsToMany public function contactos(): BelongsToMany { return $this->belongsToMany(Contacto::class, 'contactos_subgrupos', 'contacto_id', 'subgrupo_id'); return $this->belongsToMany(Contacto::class, 'contactos_subgrupos', 'subgrupo_id', 'contacto_id'); } }
resources/views/adminGen/listas/show.blade.php +201 −1 Original line number Diff line number Diff line Loading @@ -14,6 +14,58 @@ </ul> <div class="pt-5"> <div class="grid grid-cols-1 lg:grid-cols-3 xl:grid-cols-4 gap-5 mb-5"> <div class="panel lg:col-span-4 xl:col-span-4"> <div class="mb-5"> <h5 class="font-semibold text-lg dark:text-white-light">Exportar datos</h5> </div> <div class="mb-5"> <div class="text-[#515365] dark:text-white-light font-semibold p-4 bg-white rounded-lg shadow"> <form method="GET" action="" class="space-y-4" onsubmit="event.preventDefault(); logData();"> <!-- Contenedor de selects alineados --> <div class="grid grid-cols-2 gap-4 items-center"> <!-- Tipo de archivo a exportar --> <div> <label for="archivo" class="text-gray-700 font-semibold block mb-1">Tipo de archivo:</label> <select id="archivo" class="w-full px-3 py-2 bg-white border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500"> <option value="" disabled selected>Selecciona el formato de archivo a exportar</option> <option value="ambos">Ambos</option> <option value="pdf">PDF</option> <option value="excel">Excel</option> </select> </div> <!-- Campos a exportar --> <div> <label for="exportar" class="text-gray-700 font-semibold block mb-1">Campos:</label> <div class="flex items-center space-x-2"> <select id="exportar" class="w-full px-3 py-2 bg-white border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500"> <option value="" disabled selected>Selecciona los campos a exportar</option> <option value="todos">Todos</option> <option value="conyuge">Cónyuge</option> <option value="domicilio">Domicilio</option> <option value="cumpleanos">Cumpleaños</option> <option value="email">Correo electrónico</option> <option value="telefonos">Teléfonos</option> </select> <button type="button" onclick="agregarEtiqueta('exportar', 'exportarAgregados')" class="bg-blue-500 text-white px-3 py-2 rounded-md shadow hover:bg-blue-600 transition"> Agregar </button> </div> </div> <div id="exportarAgregados" class="flex flex-wrap gap-2 mt-2"></div> </div> <!-- Botón para aplicar filtros --> <div class="flex justify-end"> <button type="submit" class="px-4 py-2 bg-blue-500 text-white font-semibold rounded-md shadow hover:bg-blue-600 transition"> Aplicar Filtros </button> </div> </form> </div> </div> </div> <div class="panel lg:col-span-2 xl:col-span-2"> <div class="mb-5"> <h5 class="font-semibold text-lg dark:text-white-light">Grupos</h5> Loading Loading @@ -93,5 +145,153 @@ class="btn btn-primary"> </a> </div> </div> <div id="loader-container" class="fixed inset-0 flex items-center justify-center bg-gray-500 bg-opacity-75 hidden"> <span id="loader" class="animate-spin border-8 border-gray-300 border-l-[#780005] border-r-[#780005] rounded-full w-14 h-14"></span> </div> </div> <link rel="stylesheet" href="{{ Vite::asset('resources/css/highlight.min.css') }}"> <script src="/assets/js/highlight.min.js"></script> <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> <link rel="stylesheet" href="/assets/css/jquery.toast.css"> <script src="/assets/js/jquery.toast.js"></script> <script> let exportarSeleccion = []; function agregarEtiqueta(selectId, containerId){ const select = document.getElementById(selectId); const selectedOption = select.options[select.selectedIndex]; if(selectedOption && selectedOption.value){ const container = document.getElementById(containerId); const etiquetaId = `${selectId}-${selectedOption.value}`; if(!document.getElementById(etiquetaId)){ switch(selectId){ case 'exportar': exportarSeleccion.push(selectedOption.value); break; default: break; } const etiqueta = document.createElement('div'); etiqueta.id = etiquetaId; etiqueta.classList.add('inline-block', 'bg-gray-200', 'px-4', 'py-2', 'rounded', 'mr-2', 'mt-2'); etiqueta.innerHTML = `${selectedOption.text} <button type="button" onclick="eliminarEtiqueta('${etiquetaId}')" class="text-red-500">x</button>`; const inputHidden = document.createElement('input'); inputHidden.type = 'hidden'; inputHidden.name = `${selectId}[]`; inputHidden.value = selectedOption.value; etiqueta.appendChild(inputHidden); container.appendChild(etiqueta); select,selectedIndex = 0; } } } function eliminarEtiqueta(etiquetaId){ const etiqueta = document.getElementById(etiquetaId); if(etiqueta){ etiqueta.remove(); const [selectId, value] = etiquetaId.split('-'); switch(selectId){ case 'exportar': exportarSeleccion = exportarSeleccion.filter(item => item !== value); break; default: break; } } } function logData(){ const select = document.getElementById('archivo'); const selectedOption = select.options[select.selectedIndex]; const data = { archivo: selectedOption.value, exportar: exportarSeleccion, id: {{$lista->id}}, }; document.getElementById('loader-container').classList.remove('hidden'); document.querySelector('form').classList.add('pointer-events-none'); fetch('/reportes/listas/exportar', { method: 'POST', body: JSON.stringify(data), headers:{ "Content-Type": "application/json; charset=utf-8", "X-CSRF-TOKEN": "{{ csrf_token() }}" } }) .then(response => { if(!response.ok){ return response.json().then(err => { throw err; }); } const contentDisposition = response.headers.get('Content-Disposition'); let filename = "reporte.xlsx"; if(contentDisposition){ const match = contentDisposition.match(/filename="?([^"]+)"?/); if(match && match[1]){ filename = match[1]; } } return response.blob().then(blob => ({blob, filename})); }) .then(({blob, filename}) => { const url = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = url; link.download = filename; document.body.appendChild(link); link.click(); link.remove(); window.URL.revokeObjectURL(url); }) .catch(err => { showToast(err, 'Error.', 'error'); }) .finally(() => { document.getElementById('loader-container').classList.add('hidden'); document.querySelector('form').classList.remove('pointer-events-none'); }); } function showToast(message, heading, icon) { $.toast({ heading: heading, text: message, showHideTransition: 'slide', icon: icon, position: 'top-right', loader: false, hideAfter: 10000, allowToastClose: true, textColor: '#676767', }); } document.addEventListener('DOMContentLoaded', function() { @if(session('success')) // Muestra el mensaje de éxito utilizando showMessage showToast("{{ session('success') }}", 'Exito.', 'success') @endif @if($errors->any()) @foreach($errors->all() as $error) showToast(`{{ $error }}`, 'Error.', 'error'); @endforeach @endif }); </script> </x-layout.default> No newline at end of file