72 changed files with 3180 additions and 388 deletions
@ -0,0 +1,24 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Exports; |
||||
|
|
||||
|
use App\Models\Chofer; |
||||
|
use Maatwebsite\Excel\Concerns\FromCollection; |
||||
|
use Maatwebsite\Excel\Concerns\WithHeadings; |
||||
|
|
||||
|
class ChoferesExport implements FromCollection, WithHeadings |
||||
|
{ |
||||
|
public function collection() |
||||
|
{ |
||||
|
return Chofer::select('id', 'nombre', 'tipo_licencia')->get(); |
||||
|
} |
||||
|
|
||||
|
public function headings(): array |
||||
|
{ |
||||
|
return [ |
||||
|
'ID', |
||||
|
'Nombre', |
||||
|
'Tipo de Licencia', |
||||
|
]; |
||||
|
} |
||||
|
} |
@ -0,0 +1,44 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Exports; |
||||
|
|
||||
|
use App\Models\Puesto; |
||||
|
use Maatwebsite\Excel\Concerns\FromCollection; |
||||
|
use Maatwebsite\Excel\Concerns\WithHeadings; |
||||
|
|
||||
|
class PuestosExport implements FromCollection, WithHeadings |
||||
|
{ |
||||
|
protected $puestos; |
||||
|
|
||||
|
// Permite pasar una colección personalizada si lo deseas |
||||
|
public function __construct($puestos = null) |
||||
|
{ |
||||
|
$this->puestos = $puestos; |
||||
|
} |
||||
|
|
||||
|
public function collection() |
||||
|
{ |
||||
|
// Obtén los puestos |
||||
|
$puestos = $this->puestos ?: Puesto::where('eliminado', 0)->get(['nombre']); |
||||
|
|
||||
|
// Construye la colección con número consecutivo |
||||
|
$data = []; |
||||
|
$contador = 1; |
||||
|
foreach ($puestos as $puesto) { |
||||
|
$data[] = [ |
||||
|
'ID' => $contador++, |
||||
|
'Nombre del Puesto' => $puesto->nombre, |
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
return collect($data); |
||||
|
} |
||||
|
|
||||
|
public function headings(): array |
||||
|
{ |
||||
|
return [ |
||||
|
'ID', |
||||
|
'Nombre del Puesto', |
||||
|
]; |
||||
|
} |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Http\Controllers; |
||||
|
|
||||
|
use Illuminate\Http\Request; |
||||
|
|
||||
|
class AdminController extends Controller |
||||
|
{ |
||||
|
public function dashboard() |
||||
|
{ |
||||
|
return view('admin.dashboard'); |
||||
|
} |
||||
|
} |
@ -0,0 +1,97 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Http\Controllers; |
||||
|
|
||||
|
use App\Models\Chofer; |
||||
|
use Illuminate\Http\Request; |
||||
|
use PDF; |
||||
|
use App\Exports\ChoferesExport; |
||||
|
use Maatwebsite\Excel\Facades\Excel; |
||||
|
|
||||
|
class ChoferController extends Controller |
||||
|
{ |
||||
|
/** |
||||
|
* Display a listing of the resource. |
||||
|
*/ |
||||
|
public function index() |
||||
|
{ |
||||
|
$choferes = Chofer::all(); |
||||
|
return view('choferes', compact('choferes')); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Show the form for creating a new resource. |
||||
|
*/ |
||||
|
public function create() |
||||
|
{ |
||||
|
return view('choferesCrearEditar', ['chofer' => null]); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Store a newly created resource in storage. |
||||
|
*/ |
||||
|
public function store(Request $request) |
||||
|
{ |
||||
|
$request->validate([ |
||||
|
'nombre' => 'required|string|max:255', |
||||
|
'tipo_licencia' => 'required|string|max:255', |
||||
|
]); |
||||
|
|
||||
|
Chofer::create($request->all()); |
||||
|
return redirect()->route('choferes.index')->with('success', 'Chofer creado exitosamente.'); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Display the specified resource. |
||||
|
*/ |
||||
|
public function show(Chofer $chofer) |
||||
|
{ |
||||
|
// |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Show the form for editing the specified resource. |
||||
|
*/ |
||||
|
public function edit($id) |
||||
|
{ |
||||
|
$chofer = Chofer::findOrFail($id); |
||||
|
return view('choferesCrearEditar', compact('chofer')); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Update the specified resource in storage. |
||||
|
*/ |
||||
|
public function update(Request $request, $id) |
||||
|
{ |
||||
|
$request->validate([ |
||||
|
'nombre' => 'required|string|max:255', |
||||
|
'tipo_licencia' => 'required|string|max:255', |
||||
|
]); |
||||
|
|
||||
|
$chofer = Chofer::findOrFail($id); |
||||
|
$chofer->update($request->all()); |
||||
|
return redirect()->route('choferes.index')->with('success', 'Chofer actualizado exitosamente.'); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Remove the specified resource from storage. |
||||
|
*/ |
||||
|
public function destroy($id) |
||||
|
{ |
||||
|
$chofer = Chofer::findOrFail($id); |
||||
|
$chofer->delete(); |
||||
|
return redirect()->route('choferes.index')->with('success', 'Chofer eliminado exitosamente.'); |
||||
|
} |
||||
|
|
||||
|
public function exportExcel() |
||||
|
{ |
||||
|
return \Maatwebsite\Excel\Facades\Excel::download(new \App\Exports\ChoferesExport, 'choferes.xlsx'); |
||||
|
} |
||||
|
|
||||
|
public function exportPDF() |
||||
|
{ |
||||
|
$choferes = \App\Models\Chofer::all(); |
||||
|
$pdf = \PDF::loadView('exports.choferes-pdf', ['choferes' => $choferes]); |
||||
|
return $pdf->download('choferes.pdf'); |
||||
|
} |
||||
|
} |
@ -0,0 +1,129 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Http\Controllers; |
||||
|
|
||||
|
use App\Models\despartamento; |
||||
|
use Illuminate\Http\Request; |
||||
|
use App\Exports\DespartamentosExport; |
||||
|
use Maatwebsite\Excel\Facades\Excel; |
||||
|
use PDF; |
||||
|
|
||||
|
class DespartamentoController extends Controller |
||||
|
{ |
||||
|
/** |
||||
|
* Display a listing of the resource. |
||||
|
*/ |
||||
|
public function index(Request $request) |
||||
|
{ |
||||
|
$busqueda = $request->busqueda; |
||||
|
|
||||
|
if ($busqueda) { |
||||
|
// Busca en la columna 'nombre' de la tabla 'despartamentos' |
||||
|
$despartamentos = despartamento::where('nombre', 'LIKE', "%{$busqueda}%")->where('eliminado', 0)->get(); |
||||
|
|
||||
|
if ($despartamentos->isEmpty()) { |
||||
|
return redirect()->route('despartamento.index') |
||||
|
->with('error', 'No existe ningún departamento con el nombre "' . $busqueda . '". Por favor, inténtalo de nuevo.'); |
||||
|
} |
||||
|
} else { |
||||
|
// Si no hay búsqueda, mostrar todos los departamentos |
||||
|
$despartamentos = despartamento::where('eliminado', 0)->get(); |
||||
|
} |
||||
|
|
||||
|
return view('despartamentos', ['despartamentos' => $despartamentos]); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Show the form for creating a new resource. |
||||
|
*/ |
||||
|
public function create() |
||||
|
{ |
||||
|
return view('despartamentosCrearEditar', ['despartamento' => null]); // No se necesita pasar departamentos |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Store a newly created resource in storage. |
||||
|
*/ |
||||
|
public function store(Request $request) |
||||
|
{ |
||||
|
// Valida la entrada |
||||
|
$request->validate([ |
||||
|
'departamento' => 'required|string|max:255|unique:despartamentos,departamento', // Asegúrate de que 'departamento' sea único |
||||
|
], [ |
||||
|
'departamento.required' => 'El campo departamento es obligatorio.', |
||||
|
'departamento.string' => 'El campo departamento debe ser una cadena de texto.', |
||||
|
'departamento.max' => 'El campo departamento no puede tener más de 255 caracteres.', |
||||
|
'departamento.unique' => 'Ya existe un departamento con ese nombre.', |
||||
|
]); |
||||
|
|
||||
|
// Crea un nuevo departamento |
||||
|
$despartamento = new despartamento(); |
||||
|
$despartamento->departamento = $request->departamento; // Asigna el nombre ingresado por el usuario |
||||
|
$despartamento->eliminado = 0; // Departamento como activo por defecto |
||||
|
$despartamento->save(); |
||||
|
|
||||
|
return redirect()->route('despartamentos.index')->with('success', 'Departamento creado exitosamente.'); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Show the form for editing the specified resource. |
||||
|
*/ |
||||
|
public function edit($id) |
||||
|
{ |
||||
|
$despartamento = despartamento::findOrFail($id); // Busca el departamento por ID |
||||
|
return view('despartamentosCrearEditar', ['despartamento' => $despartamento]); // Pasa el departamento a la vista |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Update the specified resource in storage. |
||||
|
*/ |
||||
|
public function update(Request $request, $id) |
||||
|
{ |
||||
|
$request->validate([ |
||||
|
'departamento' => 'required|string|max:255|unique:despartamentos,departamento', // Asegúrate de que 'departamento' sea único |
||||
|
], [ |
||||
|
'departamento.required' => 'El campo departamento es obligatorio.', |
||||
|
'departamento.string' => 'El campo departamento debe ser una cadena de texto.', |
||||
|
'departamento.max' => 'El campo departamento no puede tener más de 255 caracteres.', |
||||
|
'departamento.unique' => 'Ya existe un departamento con ese nombre, por favor elige otro.', |
||||
|
]); |
||||
|
|
||||
|
$despartamento = despartamento::findOrFail($id); // Encuentra el departamento por ID |
||||
|
|
||||
|
// Verifica si el nombre del departamento ha cambiado |
||||
|
if ($despartamento->departamento !== $request->departamento) { |
||||
|
$despartamento->departamento = $request->departamento; // Actualiza el nombre del departamento |
||||
|
} |
||||
|
|
||||
|
$despartamento->eliminado = 0; // Cambia el estado a activo si se está editando |
||||
|
$despartamento->save(); // Guarda los cambios |
||||
|
|
||||
|
return redirect()->route('despartamentos.index')->with('success', 'Departamento actualizado correctamente.'); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Remove the specified resource from storage. |
||||
|
*/ |
||||
|
public function destroy($id) |
||||
|
{ |
||||
|
$despartamento = despartamento::findOrFail($id); |
||||
|
\App\Models\User::where('departamento_id', $id)->update(['departamento_id' => null]); |
||||
|
$despartamento->eliminado = 1; |
||||
|
$despartamento->save(); |
||||
|
|
||||
|
return redirect()->route('despartamentos.index') |
||||
|
->with('success', 'Departamento eliminado exitosamente. Los usuarios afectados necesitan ser reasignados.'); |
||||
|
} |
||||
|
|
||||
|
public function exportExcel() |
||||
|
{ |
||||
|
return Excel::download(new DespartamentosExport, 'despartamentos.xlsx'); |
||||
|
} |
||||
|
|
||||
|
public function exportPDF() |
||||
|
{ |
||||
|
$departamentos = despartamento::where('eliminado', 0)->get(); |
||||
|
$pdf = PDF::loadView('exports.departamentos', ['departamentos' => $departamentos]); |
||||
|
return $pdf->download('departamentos.pdf'); |
||||
|
} |
||||
|
} |
@ -0,0 +1,128 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Http\Controllers; |
||||
|
|
||||
|
use App\Models\Puesto; |
||||
|
use Illuminate\Http\Request; |
||||
|
use App\Exports\PuestosExport; |
||||
|
use Maatwebsite\Excel\Facades\Excel; |
||||
|
use PDF; |
||||
|
|
||||
|
class PuestoController extends Controller |
||||
|
{ |
||||
|
public function index(Request $request) |
||||
|
{ |
||||
|
$busqueda = $request->busqueda; |
||||
|
|
||||
|
if ($busqueda) { |
||||
|
$puestos = Puesto::where('nombre', 'LIKE', "%{$busqueda}%") |
||||
|
->where('eliminado', 0) |
||||
|
->get(); |
||||
|
|
||||
|
if ($puestos->isEmpty()) { |
||||
|
return redirect()->route('puestos.index') |
||||
|
->with('error', 'No existe ningún puesto con el nombre "' . $busqueda . '". Por favor, inténtalo de nuevo.'); |
||||
|
} |
||||
|
} else { |
||||
|
$puestos = Puesto::where('eliminado', 0)->get(); |
||||
|
} |
||||
|
|
||||
|
return view('puestos', ['puestos' => $puestos]); |
||||
|
} |
||||
|
|
||||
|
public function create() |
||||
|
{ |
||||
|
return view('puestosCrearEditar', ['puesto' => null]); |
||||
|
} |
||||
|
|
||||
|
public function store(Request $request) |
||||
|
{ |
||||
|
$validated = $request->validate([ |
||||
|
'nombre' => ['required', 'string', 'max:255'], |
||||
|
], [ |
||||
|
'nombre.required' => 'El campo nombre es obligatorio.', |
||||
|
'nombre.string' => 'El campo nombre debe ser una cadena de texto.', |
||||
|
'nombre.max' => 'El campo nombre no debe exceder 255 caracteres.', |
||||
|
]); |
||||
|
$puesto = new Puesto($validated); |
||||
|
$puesto->eliminado = 0; |
||||
|
$puesto->save(); |
||||
|
|
||||
|
return redirect()->route('puestos.index') |
||||
|
->with('success', 'Puesto creado exitosamente'); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public function edit($id) |
||||
|
{ |
||||
|
$puesto = Puesto::findOrFail($id); |
||||
|
return view('puestosCrearEditar', ['puesto' => $puesto]); |
||||
|
} |
||||
|
|
||||
|
public function update(Request $request, $id) |
||||
|
{ |
||||
|
$validated = $request->validate([ |
||||
|
'nombre' => ['required', 'string', 'max:255'], |
||||
|
], [ |
||||
|
'nombre.required' => 'El campo nombre es obligatorio.', |
||||
|
'nombre.string' => 'El campo nombre debe ser una cadena de texto.', |
||||
|
'nombre.max' => 'El campo nombre no debe exceder 255 caracteres.', |
||||
|
]); |
||||
|
|
||||
|
$puesto = Puesto::findOrFail($id); |
||||
|
$puesto->update($validated); |
||||
|
|
||||
|
return redirect()->route('puestos.index') |
||||
|
->with('success', 'Puesto actualizado exitosamente'); |
||||
|
} |
||||
|
|
||||
|
public function destroy($id) |
||||
|
{ |
||||
|
$puesto = Puesto::findOrFail($id); |
||||
|
\App\Models\User::where('puesto_id', $id)->update(['puesto_id' => null]); |
||||
|
$puesto->eliminado = 1; |
||||
|
$puesto->save(); |
||||
|
|
||||
|
return redirect()->route('puestos.index') |
||||
|
->with('success', 'Puesto eliminado exitosamente. Los usuarios afectados necesitan ser reasignados.'); |
||||
|
} |
||||
|
|
||||
|
public function exportExcel() |
||||
|
{ |
||||
|
return Excel::download(new PuestosExport, 'puestos.xlsx'); |
||||
|
} |
||||
|
|
||||
|
public function exportPDF() |
||||
|
{ |
||||
|
$puestos = Puesto::where('eliminado', 0)->get(); |
||||
|
$pdf = PDF::loadView('exports.puestos', ['puestos' => $puestos]); |
||||
|
return $pdf->download('puestos.pdf'); |
||||
|
} |
||||
|
|
||||
|
public function export($format) |
||||
|
{ |
||||
|
$puestos = Puesto::where('eliminado', 0) |
||||
|
->orderBy('updated_at', 'desc') |
||||
|
->get(); |
||||
|
|
||||
|
switch($format) { |
||||
|
case 'excel': |
||||
|
return Excel::download(new PuestosExport($puestos), 'puestos.xlsx'); |
||||
|
case 'pdf': |
||||
|
$pdf = PDF::loadView('exports.puestos', ['puestos' => $puestos]); |
||||
|
return $pdf->download('puestos.pdf'); |
||||
|
default: |
||||
|
return redirect()->back()->with('error', 'Formato no soportado'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public function toggleStatus($id) |
||||
|
{ |
||||
|
$puesto = Puesto::findOrFail($id); |
||||
|
$puesto->eliminado = !$puesto->eliminado; |
||||
|
$puesto->save(); |
||||
|
|
||||
|
return redirect()->route('puestos.index') |
||||
|
->with('success', 'Estado del puesto actualizado correctamente'); |
||||
|
} |
||||
|
} |
@ -0,0 +1,49 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Http\Controllers; |
||||
|
|
||||
|
use Illuminate\Http\Request; |
||||
|
use App\Models\SolicitudVehiculo; |
||||
|
|
||||
|
class SolicitudVehiculoController extends Controller |
||||
|
{ |
||||
|
public function __construct() |
||||
|
{ |
||||
|
$this->middleware(['auth', 'profesor']); |
||||
|
} |
||||
|
|
||||
|
public function index() |
||||
|
{ |
||||
|
$solicitudes = SolicitudVehiculo::where('user_id', auth()->id())->get(); |
||||
|
return view('profesor.solicitudes.index', compact('solicitudes')); |
||||
|
} |
||||
|
|
||||
|
public function create() |
||||
|
{ |
||||
|
return view('profesor.solicitudes.create'); |
||||
|
} |
||||
|
|
||||
|
public function store(Request $request) |
||||
|
{ |
||||
|
$request->validate([ |
||||
|
'fecha_solicitud' => 'required|date', |
||||
|
'hora_salida' => 'required', |
||||
|
'hora_regreso' => 'required', |
||||
|
'destino' => 'required|string', |
||||
|
'motivo' => 'required|string', |
||||
|
]); |
||||
|
|
||||
|
$solicitud = new SolicitudVehiculo(); |
||||
|
$solicitud->user_id = auth()->id(); |
||||
|
$solicitud->fecha_solicitud = $request->fecha_solicitud; |
||||
|
$solicitud->hora_salida = $request->hora_salida; |
||||
|
$solicitud->hora_regreso = $request->hora_regreso; |
||||
|
$solicitud->destino = $request->destino; |
||||
|
$solicitud->motivo = $request->motivo; |
||||
|
$solicitud->estado = 'pendiente'; |
||||
|
$solicitud->save(); |
||||
|
|
||||
|
return redirect()->route('profesor.solicitudes.index') |
||||
|
->with('success', 'Solicitud creada exitosamente'); |
||||
|
} |
||||
|
} |
@ -0,0 +1,65 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Http\Controllers; |
||||
|
|
||||
|
use App\Models\tipo; |
||||
|
use Illuminate\Http\Request; |
||||
|
|
||||
|
class TipoController extends Controller |
||||
|
{ |
||||
|
/** |
||||
|
* Display a listing of the resource. |
||||
|
*/ |
||||
|
public function index() |
||||
|
{ |
||||
|
// |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Show the form for creating a new resource. |
||||
|
*/ |
||||
|
public function create() |
||||
|
{ |
||||
|
// |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Store a newly created resource in storage. |
||||
|
*/ |
||||
|
public function store(Request $request) |
||||
|
{ |
||||
|
// |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Display the specified resource. |
||||
|
*/ |
||||
|
public function show(tipo $tipo) |
||||
|
{ |
||||
|
// |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Show the form for editing the specified resource. |
||||
|
*/ |
||||
|
public function edit(tipo $tipo) |
||||
|
{ |
||||
|
// |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Update the specified resource in storage. |
||||
|
*/ |
||||
|
public function update(Request $request, tipo $tipo) |
||||
|
{ |
||||
|
// |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Remove the specified resource from storage. |
||||
|
*/ |
||||
|
public function destroy(tipo $tipo) |
||||
|
{ |
||||
|
// |
||||
|
} |
||||
|
} |
@ -0,0 +1,54 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Http\Controllers; |
||||
|
|
||||
|
use Illuminate\Http\Request; |
||||
|
use App\Models\Prestamo; |
||||
|
|
||||
|
class UserDashboardController extends Controller |
||||
|
{ |
||||
|
public function __construct() |
||||
|
{ |
||||
|
$this->middleware('auth'); |
||||
|
} |
||||
|
|
||||
|
public function index() |
||||
|
{ |
||||
|
// Permitir acceso solo a tipo 2 (Usuario normal) |
||||
|
if (auth()->user()->tipos_id != 2) { |
||||
|
return redirect('/')->with('error', 'No tienes permiso para acceder a esta sección'); |
||||
|
} |
||||
|
|
||||
|
return view('user-dashboard.index'); |
||||
|
} |
||||
|
|
||||
|
public function prestamosAceptados() |
||||
|
{ |
||||
|
// Mostrar todos los préstamos aceptados a cualquier usuario tipo 2 |
||||
|
$prestamos = Prestamo::where('estado', 'aceptado')->with('choferAsignado')->get(); |
||||
|
|
||||
|
return view('user-dashboard.prestamos-aceptados', compact('prestamos')); |
||||
|
} |
||||
|
|
||||
|
public function detallePrestamo($id) |
||||
|
{ |
||||
|
$prestamo = Prestamo::findOrFail($id); |
||||
|
return view('user-dashboard.detalle-prestamo', compact('prestamo')); |
||||
|
} |
||||
|
|
||||
|
public function cuestionario(Request $request) |
||||
|
{ |
||||
|
$prestamo = null; |
||||
|
if ($request->has('prestamo_id')) { |
||||
|
$prestamo = \App\Models\Prestamo::find($request->prestamo_id); |
||||
|
} |
||||
|
return view('user-dashboard.cuestionario', compact('prestamo')); |
||||
|
} |
||||
|
|
||||
|
public function pdfPrestamo($id) |
||||
|
{ |
||||
|
$prestamo = \App\Models\Prestamo::with('choferAsignado')->findOrFail($id); |
||||
|
$pdf = \PDF::loadView('exports.prestamo-individual-pdf', compact('prestamo')); |
||||
|
return $pdf->download('reporte_prestamo_'.$prestamo->id.'.pdf'); |
||||
|
} |
||||
|
} |
@ -0,0 +1,23 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Http\Middleware; |
||||
|
|
||||
|
use Closure; |
||||
|
use Illuminate\Http\Request; |
||||
|
use Symfony\Component\HttpFoundation\Response; |
||||
|
|
||||
|
class AdminOrServiciosRole |
||||
|
{ |
||||
|
/** |
||||
|
* Handle an incoming request. |
||||
|
* |
||||
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next |
||||
|
*/ |
||||
|
public function handle($request, Closure $next) |
||||
|
{ |
||||
|
if (!auth()->check() || !in_array(auth()->user()->rol, ['admin', 'servicios'])) { |
||||
|
return redirect()->route('dashboard')->with('error', 'No tienes permisos para acceder a esta sección.'); |
||||
|
} |
||||
|
return $next($request); |
||||
|
} |
||||
|
} |
@ -0,0 +1,20 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Http\Middleware; |
||||
|
|
||||
|
use Closure; |
||||
|
use Illuminate\Http\Request; |
||||
|
use Symfony\Component\HttpFoundation\Response; |
||||
|
|
||||
|
class CheckAdminRole |
||||
|
{ |
||||
|
public function handle(Request $request, Closure $next): Response |
||||
|
{ |
||||
|
if (!auth()->check() || auth()->user()->tipos_id !== 1) { |
||||
|
return redirect()->route('dashboard') |
||||
|
->with('error', 'No tienes permisos de administrador para acceder a esta sección.'); |
||||
|
} |
||||
|
|
||||
|
return $next($request); |
||||
|
} |
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Http\Middleware; |
||||
|
|
||||
|
use Closure; |
||||
|
use Illuminate\Http\Request; |
||||
|
use Symfony\Component\HttpFoundation\Response; |
||||
|
|
||||
|
class CheckProfesorRole |
||||
|
{ |
||||
|
public function handle(Request $request, Closure $next): Response |
||||
|
{ |
||||
|
if (!auth()->check() || auth()->user()->rol !== 'profesor') { |
||||
|
return redirect('/')->with('error', 'No tienes permiso para acceder a esta sección.'); |
||||
|
} |
||||
|
|
||||
|
return $next($request); |
||||
|
} |
||||
|
} |
@ -0,0 +1,19 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Http\Middleware; |
||||
|
|
||||
|
use Closure; |
||||
|
use Illuminate\Http\Request; |
||||
|
use Symfony\Component\HttpFoundation\Response; |
||||
|
|
||||
|
class CheckServiciosRole |
||||
|
{ |
||||
|
public function handle(Request $request, Closure $next): Response |
||||
|
{ |
||||
|
if (!auth()->check() || auth()->user()->tipos_id !== 4) { |
||||
|
return redirect('/')->with('error', 'No tienes permisos de servicios para acceder a esta sección.'); |
||||
|
} |
||||
|
|
||||
|
return $next($request); |
||||
|
} |
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Models; |
||||
|
|
||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
|
use Illuminate\Database\Eloquent\Model; |
||||
|
|
||||
|
class Chofer extends Model |
||||
|
{ |
||||
|
use HasFactory; |
||||
|
|
||||
|
protected $table = 'choferes'; |
||||
|
protected $fillable = [ |
||||
|
'nombre', |
||||
|
'tipo_licencia', |
||||
|
]; |
||||
|
|
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Models; |
||||
|
|
||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
|
use Illuminate\Database\Eloquent\Model; |
||||
|
|
||||
|
class SolicitudVehiculo extends Model |
||||
|
{ |
||||
|
use HasFactory; |
||||
|
|
||||
|
protected $fillable = [ |
||||
|
'user_id', |
||||
|
'fecha_solicitud', |
||||
|
'hora_salida', |
||||
|
'hora_regreso', |
||||
|
'destino', |
||||
|
'motivo', |
||||
|
'estado' |
||||
|
]; |
||||
|
|
||||
|
public function user() |
||||
|
{ |
||||
|
return $this->belongsTo(User::class); |
||||
|
} |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace App\Models; |
||||
|
|
||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory; |
||||
|
use Illuminate\Database\Eloquent\Model; |
||||
|
|
||||
|
class tipo extends Model |
||||
|
{ |
||||
|
use HasFactory; |
||||
|
protected $table = 'tipos'; |
||||
|
protected $fillable = ['nombre']; |
||||
|
} |
@ -0,0 +1,23 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace Database\Factories; |
||||
|
|
||||
|
use Illuminate\Database\Eloquent\Factories\Factory; |
||||
|
|
||||
|
/** |
||||
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\tipo> |
||||
|
*/ |
||||
|
class TipoFactory extends Factory |
||||
|
{ |
||||
|
/** |
||||
|
* Define the model's default state. |
||||
|
* |
||||
|
* @return array<string, mixed> |
||||
|
*/ |
||||
|
public function definition(): array |
||||
|
{ |
||||
|
return [ |
||||
|
// |
||||
|
]; |
||||
|
} |
||||
|
} |
@ -0,0 +1,34 @@ |
|||||
|
<?php |
||||
|
|
||||
|
use Illuminate\Database\Migrations\Migration; |
||||
|
use Illuminate\Database\Schema\Blueprint; |
||||
|
use Illuminate\Support\Facades\Schema; |
||||
|
|
||||
|
return new class extends Migration |
||||
|
{ |
||||
|
/** |
||||
|
* Run the migrations. |
||||
|
*/ |
||||
|
public function up(): void |
||||
|
{ |
||||
|
Schema::create('tipos', function (Blueprint $table) { |
||||
|
$table->id(); |
||||
|
$table->string('nombre'); |
||||
|
$table->timestamps(); |
||||
|
|
||||
|
}); |
||||
|
DB::table('tipos')->insert(['nombre'=> 'Administrador']); |
||||
|
DB::table('tipos')->insert(['nombre'=> 'Usuario']); |
||||
|
DB::table('tipos')->insert(['nombre'=> 'Jefe de Departamento']); |
||||
|
DB::table('tipos')->insert(['nombre'=> 'Servicios Generales']); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Reverse the migrations. |
||||
|
*/ |
||||
|
public function down(): void |
||||
|
{ |
||||
|
Schema::dropIfExists('tipos'); |
||||
|
} |
||||
|
}; |
@ -0,0 +1,31 @@ |
|||||
|
<?php |
||||
|
|
||||
|
use Illuminate\Database\Migrations\Migration; |
||||
|
use Illuminate\Database\Schema\Blueprint; |
||||
|
use Illuminate\Support\Facades\Schema; |
||||
|
use Illuminate\Support\Facades\DB; |
||||
|
use Illuminate\Support\Facades\Hash; |
||||
|
|
||||
|
return new class extends Migration |
||||
|
{ |
||||
|
public function up() |
||||
|
{ |
||||
|
// Verificar si el usuario ya existe |
||||
|
$user = DB::table('users')->where('email', 'usuarios@usuariosgmail.com')->first(); |
||||
|
|
||||
|
if (!$user) { |
||||
|
DB::table('users')->insert([ |
||||
|
'name' => 'Usuario Dashboard', |
||||
|
'email' => 'usuarios@usuariosgmail.com', |
||||
|
'password' => Hash::make('usuario123'), |
||||
|
'created_at' => now(), |
||||
|
'updated_at' => now(), |
||||
|
]); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public function down() |
||||
|
{ |
||||
|
DB::table('users')->where('email', 'usuarios@usuariosgmail.com')->delete(); |
||||
|
} |
||||
|
}; |
@ -0,0 +1,28 @@ |
|||||
|
<?php |
||||
|
|
||||
|
use Illuminate\Database\Migrations\Migration; |
||||
|
use Illuminate\Database\Schema\Blueprint; |
||||
|
use Illuminate\Support\Facades\Schema; |
||||
|
|
||||
|
return new class extends Migration |
||||
|
{ |
||||
|
public function up(): void |
||||
|
{ |
||||
|
Schema::create('solicitud_vehiculos', function (Blueprint $table) { |
||||
|
$table->id(); |
||||
|
$table->foreignId('user_id')->constrained()->onDelete('cascade'); |
||||
|
$table->date('fecha_solicitud'); |
||||
|
$table->time('hora_salida'); |
||||
|
$table->time('hora_regreso'); |
||||
|
$table->string('destino'); |
||||
|
$table->text('motivo'); |
||||
|
$table->enum('estado', ['pendiente', 'aprobada', 'rechazada'])->default('pendiente'); |
||||
|
$table->timestamps(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public function down(): void |
||||
|
{ |
||||
|
Schema::dropIfExists('solicitud_vehiculos'); |
||||
|
} |
||||
|
}; |
@ -0,0 +1,29 @@ |
|||||
|
<?php |
||||
|
|
||||
|
use Illuminate\Database\Migrations\Migration; |
||||
|
use Illuminate\Database\Schema\Blueprint; |
||||
|
use Illuminate\Support\Facades\Schema; |
||||
|
|
||||
|
return new class extends Migration |
||||
|
{ |
||||
|
/** |
||||
|
* Run the migrations. |
||||
|
*/ |
||||
|
public function up() |
||||
|
{ |
||||
|
Schema::create('choferes', function (Blueprint $table) { |
||||
|
$table->id(); |
||||
|
$table->string('nombre'); |
||||
|
$table->string('tipo_licencia'); |
||||
|
$table->timestamps(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Reverse the migrations. |
||||
|
*/ |
||||
|
public function down(): void |
||||
|
{ |
||||
|
Schema::dropIfExists('choferes'); |
||||
|
} |
||||
|
}; |
@ -0,0 +1,25 @@ |
|||||
|
<?php |
||||
|
|
||||
|
use Illuminate\Database\Migrations\Migration; |
||||
|
use Illuminate\Database\Schema\Blueprint; |
||||
|
use Illuminate\Support\Facades\Schema; |
||||
|
|
||||
|
return new class extends Migration |
||||
|
{ |
||||
|
/** |
||||
|
* Run the migrations. |
||||
|
*/ |
||||
|
public function up() |
||||
|
{ |
||||
|
Schema::table('prestamos', function (Blueprint $table) { |
||||
|
$table->foreignId('chofer_id')->nullable()->constrained('choferes')->onDelete('set null'); |
||||
|
}); |
||||
|
} |
||||
|
public function down() |
||||
|
{ |
||||
|
Schema::table('prestamos', function (Blueprint $table) { |
||||
|
$table->dropForeign(['chofer_id']); |
||||
|
$table->dropColumn('chofer_id'); |
||||
|
}); |
||||
|
} |
||||
|
}; |
@ -0,0 +1,22 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace Database\Seeders; |
||||
|
|
||||
|
use Illuminate\Database\Seeder; |
||||
|
use App\Models\User; |
||||
|
use Illuminate\Support\Facades\Hash; |
||||
|
|
||||
|
class ProfesorSeeder extends Seeder |
||||
|
{ |
||||
|
public function run(): void |
||||
|
{ |
||||
|
User::create([ |
||||
|
'name' => 'Profesor', |
||||
|
'email' => 'profesor@profesor.com', |
||||
|
'password' => Hash::make('12345678'), |
||||
|
'rol' => 'profesor', |
||||
|
'apellido' => 'Ejemplo', |
||||
|
'telefono' => '1234567890', |
||||
|
]); |
||||
|
} |
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
<?php |
||||
|
|
||||
|
namespace Database\Seeders; |
||||
|
|
||||
|
use Illuminate\Database\Seeder; |
||||
|
use App\Models\User; |
||||
|
use Illuminate\Support\Facades\Hash; |
||||
|
|
||||
|
class ServiciosSeeder extends Seeder |
||||
|
{ |
||||
|
public function run(): void |
||||
|
{ |
||||
|
User::updateOrCreate( |
||||
|
[ 'email' => 'jorge@jorge.com' ], |
||||
|
[ |
||||
|
'name' => 'Jorge', |
||||
|
'apellido' => 'Servicios', |
||||
|
'telefono' => '1234567890', |
||||
|
'password' => Hash::make('servicios123'), |
||||
|
'tipos_id' => 4, |
||||
|
'puesto_id' => 1, |
||||
|
'departamento_id' => 1 |
||||
|
] |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,85 @@ |
|||||
|
body.user-dashboard-bg { |
||||
|
background: linear-gradient(120deg, #4158D0 0%, #5068c8 46%, #70e7ff 100%); |
||||
|
min-height: 100vh; |
||||
|
} |
||||
|
|
||||
|
.user-dashboard-header { |
||||
|
font-size: 2.2rem; |
||||
|
font-weight: 900; |
||||
|
color: #fff; |
||||
|
letter-spacing: 1px; |
||||
|
margin-top: 32px; |
||||
|
margin-left: 60px; |
||||
|
margin-bottom: 30px; |
||||
|
text-shadow: 0 2px 8px rgba(65,88,208,0.15); |
||||
|
text-align: left; |
||||
|
} |
||||
|
|
||||
|
.user-dashboard-card { |
||||
|
background: #fff; |
||||
|
border-radius: 24px; |
||||
|
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.15); |
||||
|
padding: 48px 32px; |
||||
|
max-width: 480px; |
||||
|
margin: 60px auto; |
||||
|
text-align: center; |
||||
|
} |
||||
|
|
||||
|
.user-dashboard-title { |
||||
|
font-size: 2.5rem; |
||||
|
font-weight: 800; |
||||
|
color: #2d3748; |
||||
|
margin-bottom: 18px; |
||||
|
} |
||||
|
|
||||
|
.user-dashboard-desc { |
||||
|
color: #6b7280; |
||||
|
font-size: 1.2rem; |
||||
|
margin-bottom: 32px; |
||||
|
} |
||||
|
|
||||
|
.user-dashboard-btn { |
||||
|
background: #4158D0; |
||||
|
color: #fff; |
||||
|
border: none; |
||||
|
border-radius: 8px; |
||||
|
padding: 14px 36px; |
||||
|
font-size: 1.1rem; |
||||
|
font-weight: 600; |
||||
|
box-shadow: 0 2px 8px rgba(65,88,208,0.15); |
||||
|
transition: background 0.2s; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
.user-dashboard-btn:hover { |
||||
|
background: #C850C0; |
||||
|
color: #fff; |
||||
|
} |
||||
|
|
||||
|
.user-dashboard-logout { |
||||
|
position: absolute; |
||||
|
top: 32px; |
||||
|
right: 60px; |
||||
|
z-index: 10; |
||||
|
} |
||||
|
.user-dashboard-logout-btn { |
||||
|
background: #e53e3e; |
||||
|
color: #fff; |
||||
|
border: none; |
||||
|
border-radius: 8px; |
||||
|
padding: 10px 22px; |
||||
|
font-size: 1rem; |
||||
|
font-weight: 600; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
gap: 8px; |
||||
|
box-shadow: 0 2px 8px rgba(229,62,62,0.15); |
||||
|
transition: background 0.2s; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
.user-dashboard-logout-btn:hover { |
||||
|
background: #c53030; |
||||
|
color: #fff; |
||||
|
} |
||||
|
.user-dashboard-logout-btn i { |
||||
|
font-size: 1.2rem; |
||||
|
} |
@ -0,0 +1,95 @@ |
|||||
|
@extends('layouts.dashboard') |
||||
|
|
||||
|
@section('content') |
||||
|
<div class="container mx-auto px-4 py-6"> |
||||
|
@if(session('success')) |
||||
|
<div id="success-message" class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative mb-4" role="alert"> |
||||
|
<span class="block sm:inline">{{ session('success') }}</span> |
||||
|
</div> |
||||
|
@endif |
||||
|
@if(session('error')) |
||||
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4" role="alert"> |
||||
|
<span class="block sm:inline">{{ session('error') }}</span> |
||||
|
</div> |
||||
|
@endif |
||||
|
<div class="bg-white rounded-lg shadow-lg"> |
||||
|
<div class="p-4 border-b border-gray-200 flex justify-between items-center"> |
||||
|
<h2 class="text-2xl font-bold">Gestión de Choferes</h2> |
||||
|
<div class="flex items-center gap-4"> |
||||
|
<a href="{{ route('choferes.excel') }}" class="text-green-600 hover:text-green-800 text-2xl" title="Exportar Excel"> |
||||
|
<i class="fas fa-file-excel"></i> |
||||
|
</a> |
||||
|
<a href="{{ route('choferes.pdf') }}" class="text-red-600 hover:text-red-800 text-2xl" title="Exportar PDF"> |
||||
|
<i class="fas fa-file-pdf"></i> |
||||
|
</a> |
||||
|
<a href="{{ route('choferes.create') }}" class="text-blue-600 hover:text-blue-800 text-2xl" title="Agregar Chofer"> |
||||
|
<i class="fas fa-plus"></i> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="p-4 border-b border-gray-200 bg-gray-50"> |
||||
|
<form action="{{ route('choferes.index') }}" method="GET" class="flex gap-2"> |
||||
|
<div class="relative w-full sm:w-64"> |
||||
|
<input type="text" name="busqueda" placeholder="Buscar chofer..." value="{{ request('busqueda') }}" class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> |
||||
|
<div class="absolute left-3 top-2.5 text-gray-400"> |
||||
|
<i class="fas fa-search"></i> |
||||
|
</div> |
||||
|
</div> |
||||
|
<button type="submit" class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600">Buscar/Actualizar</button> |
||||
|
@if(request('busqueda')) |
||||
|
<a href="{{ route('choferes.index') }}" class="px-4 py-2 bg-gray-500 text-white rounded-lg hover:bg-gray-600">Limpiar</a> |
||||
|
@endif |
||||
|
</form> |
||||
|
</div> |
||||
|
<div class="overflow-x-auto"> |
||||
|
<table class="min-w-full divide-y divide-gray-200"> |
||||
|
<thead class="bg-gray-50"> |
||||
|
<tr> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Nombre</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tipo de Licencia</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Acciones</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody class="bg-white divide-y divide-gray-200"> |
||||
|
@foreach($choferes as $chofer) |
||||
|
<tr class="hover:bg-gray-50"> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ $chofer->id }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"> |
||||
|
<i class="fas fa-id-card text-blue-500 mr-2"></i> |
||||
|
{{ $chofer->nombre }} |
||||
|
</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $chofer->tipo_licencia }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium"> |
||||
|
<div class="flex space-x-2"> |
||||
|
<a href="{{ route('choferes.edit', $chofer->id) }}" class="text-blue-600 hover:text-blue-900"><i class="fas fa-edit"></i></a> |
||||
|
<form action="{{ route('choferes.destroy', $chofer->id) }}" method="POST" class="inline"> |
||||
|
@csrf |
||||
|
@method('DELETE') |
||||
|
<button type="submit" class="text-red-600 hover:text-red-900" onclick="return confirm('¿Estás seguro de que deseas eliminar este chofer?')"> |
||||
|
<i class="fas fa-trash"></i> |
||||
|
</button> |
||||
|
</form> |
||||
|
</div> |
||||
|
</td> |
||||
|
</tr> |
||||
|
@endforeach |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<script> |
||||
|
// Desaparecer el mensaje después de 3 segundos |
||||
|
setTimeout(function() { |
||||
|
var message = document.getElementById('success-message'); |
||||
|
if (message) { |
||||
|
message.style.transition = 'opacity 0.5s ease'; |
||||
|
message.style.opacity = '0'; |
||||
|
setTimeout(function() { |
||||
|
message.remove(); |
||||
|
}, 500); |
||||
|
} |
||||
|
}, 3000); |
||||
|
</script> |
||||
|
@endsection |
@ -0,0 +1,62 @@ |
|||||
|
{{-- Start of Selection --}} |
||||
|
@extends('layouts.dashboard') |
||||
|
|
||||
|
@section('content') |
||||
|
<div class="container mx-auto px-4 py-6"> |
||||
|
<div class="max-w-lg mx-auto"> |
||||
|
<div class="bg-white rounded-lg shadow-lg overflow-hidden"> |
||||
|
<div class="p-6"> |
||||
|
<div class="flex items-center justify-between mb-6"> |
||||
|
<h2 class="text-2xl font-bold text-gray-800"> |
||||
|
{{ isset($chofer) ? 'Editar Chofer' : 'Nuevo Chofer' }} |
||||
|
</h2> |
||||
|
<div class="h-10 w-10 bg-blue-100 rounded-full flex items-center justify-center"> |
||||
|
<i class="fas fa-id-card text-blue-600"></i> |
||||
|
</div> |
||||
|
</div> |
||||
|
@if($errors->any()) |
||||
|
<div class="mb-6 bg-red-50 border-l-4 border-red-500 p-4 rounded-r-lg"> |
||||
|
<div class="flex items-center"> |
||||
|
<i class="fas fa-exclamation-circle text-red-500 mr-3"></i> |
||||
|
<div class="text-red-700"> |
||||
|
<ul> |
||||
|
@foreach($errors->all() as $error) |
||||
|
<li>{{ $error }}</li> |
||||
|
@endforeach |
||||
|
</ul> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
@endif |
||||
|
<form action="{{ isset($chofer) ? route('choferes.update', $chofer->id) : route('choferes.store') }}" method="POST"> |
||||
|
@csrf |
||||
|
@if(isset($chofer)) |
||||
|
@method('PUT') |
||||
|
@endif |
||||
|
<div class="space-y-6"> |
||||
|
<div> |
||||
|
<label for="nombre" class="block text-sm font-medium text-gray-700 mb-2">Nombre del Chofer</label> |
||||
|
<div class="relative"> |
||||
|
<i class="fas fa-user absolute left-3 top-2.5 text-gray-400"></i> |
||||
|
<input type="text" name="nombre" id="nombre" class="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500" required placeholder="Ingresa el nombre del chofer" value="{{ old('nombre', $chofer->nombre ?? '') }}"> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div> |
||||
|
<label for="tipo_licencia" class="block text-sm font-medium text-gray-700 mb-2">Tipo de Licencia</label> |
||||
|
<div class="relative"> |
||||
|
<i class="fas fa-id-badge absolute left-3 top-2.5 text-gray-400"></i> |
||||
|
<input type="text" name="tipo_licencia" id="tipo_licencia" class="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500" required placeholder="Ingresa el tipo de licencia" value="{{ old('tipo_licencia', $chofer->tipo_licencia ?? '') }}"> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="flex justify-end space-x-2 pt-4 border-t border-gray-200"> |
||||
|
<a href="{{ route('choferes.index') }}" class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">Cancelar</a> |
||||
|
<button type="submit" class="px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500">{{ isset($chofer) ? 'Actualizar' : 'Guardar' }}</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</form> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
@endsection |
||||
|
{{-- End of Selection --}} |
@ -0,0 +1,55 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<title>Choferes</title> |
||||
|
<style> |
||||
|
body { |
||||
|
font-family: Arial, sans-serif; |
||||
|
} |
||||
|
table { |
||||
|
width: 100%; |
||||
|
border-collapse: collapse; |
||||
|
margin-top: 20px; |
||||
|
} |
||||
|
th, td { |
||||
|
border: 1px solid #ddd; |
||||
|
padding: 8px; |
||||
|
text-align: left; |
||||
|
} |
||||
|
th { |
||||
|
background-color: #f2f2f2; |
||||
|
} |
||||
|
.header { |
||||
|
text-align: center; |
||||
|
margin-bottom: 30px; |
||||
|
} |
||||
|
</style> |
||||
|
</head> |
||||
|
<body> |
||||
|
<div class="header"> |
||||
|
<h1>Reporte de Choferes</h1> |
||||
|
<p>Fecha de generación: {{ date('d/m/Y H:i:s') }}</p> |
||||
|
</div> |
||||
|
|
||||
|
<table> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>ID</th> |
||||
|
<th>Nombre</th> |
||||
|
<th>Tipo de Licencia</th> |
||||
|
<th>Fecha de Creación</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
@foreach($choferes as $chofer) |
||||
|
<tr> |
||||
|
<td>{{ $chofer->id }}</td> |
||||
|
<td>{{ $chofer->nombre }}</td> |
||||
|
<td>{{ $chofer->tipo_licencia }}</td> |
||||
|
<td>{{ $chofer->created_at->format('d/m/Y') }}</td> |
||||
|
</tr> |
||||
|
@endforeach |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</body> |
||||
|
</html> |
@ -0,0 +1,66 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<title>Reporte de Préstamo</title> |
||||
|
<style> |
||||
|
body { font-family: Arial, sans-serif; font-size: 12px; } |
||||
|
.header { text-align: center; margin-bottom: 20px; } |
||||
|
.reporte-table { |
||||
|
width: 100%; |
||||
|
border-collapse: collapse; |
||||
|
margin: 0 auto 20px auto; |
||||
|
} |
||||
|
.reporte-table th, .reporte-table td { |
||||
|
border: 1px solid #333; |
||||
|
padding: 8px 6px; |
||||
|
text-align: center; |
||||
|
} |
||||
|
.reporte-table th { |
||||
|
background: #e3e8f0; |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
.firmas { |
||||
|
margin-top: 40px; |
||||
|
width: 100%; |
||||
|
text-align: center; |
||||
|
} |
||||
|
.firmas td { |
||||
|
padding: 30px 10px 0 10px; |
||||
|
} |
||||
|
</style> |
||||
|
</head> |
||||
|
<body> |
||||
|
<div class="header"> |
||||
|
<h2>REPORTE DE PRÉSTAMO</h2> |
||||
|
<p>Fecha de generación: {{ now()->format('d/m/Y H:i') }}</p> |
||||
|
</div> |
||||
|
<table class="reporte-table"> |
||||
|
<tr> |
||||
|
<th>Solicitante</th> |
||||
|
<th>Destino</th> |
||||
|
<th>Fecha Salida</th> |
||||
|
<th>Fecha Llegada</th> |
||||
|
<th>Motivo</th> |
||||
|
<th>Personas</th> |
||||
|
<th>Chofer</th> |
||||
|
<th>Estado</th> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td>{{ $prestamo->nombre_solicitante }}</td> |
||||
|
<td>{{ $prestamo->destino }}</td> |
||||
|
<td>{{ \Carbon\Carbon::parse($prestamo->fecha_hora_salida)->format('d/m/Y H:i') }}</td> |
||||
|
<td>{{ \Carbon\Carbon::parse($prestamo->fecha_hora_llegada)->format('d/m/Y H:i') }}</td> |
||||
|
<td>{{ $prestamo->motivo }}</td> |
||||
|
<td>{{ $prestamo->numero_personas }}</td> |
||||
|
<td>{{ $prestamo->choferAsignado ? $prestamo->choferAsignado->nombre : 'Sin chofer' }}</td> |
||||
|
<td>{{ ucfirst($prestamo->estado) }}</td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
<table class="firmas"> |
||||
|
<tr> |
||||
|
<td>_________________________<br>Solicitante</td> |
||||
|
<td>_________________________<br>Vo. Bo.</td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
</body> |
||||
|
</html> |
@ -0,0 +1,79 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<title>Reporte General de Préstamos</title> |
||||
|
<style> |
||||
|
body { font-family: Arial, sans-serif; font-size: 11px; } |
||||
|
.header { text-align: center; margin-bottom: 20px; } |
||||
|
.reporte-table { |
||||
|
width: 100%; |
||||
|
border-collapse: collapse; |
||||
|
margin: 0 auto 20px auto; |
||||
|
} |
||||
|
.reporte-table th, .reporte-table td { |
||||
|
border: 1px solid #333; |
||||
|
padding: 6px 4px; |
||||
|
text-align: center; |
||||
|
} |
||||
|
.reporte-table th { |
||||
|
background: #e3e8f0; |
||||
|
font-weight: bold; |
||||
|
font-size: 11px; |
||||
|
} |
||||
|
.firmas { |
||||
|
margin-top: 40px; |
||||
|
width: 100%; |
||||
|
text-align: center; |
||||
|
} |
||||
|
.firmas td { |
||||
|
padding: 30px 10px 0 10px; |
||||
|
} |
||||
|
</style> |
||||
|
</head> |
||||
|
<body> |
||||
|
<div class="header"> |
||||
|
<h2>REPORTE GENERAL DE PRÉSTAMOS</h2> |
||||
|
<p>Fecha de generación: {{ now()->format('d/m/Y H:i') }}</p> |
||||
|
</div> |
||||
|
<table class="reporte-table"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>#</th> |
||||
|
<th>Solicitante</th> |
||||
|
<th>Vehículo</th> |
||||
|
<th>Destino</th> |
||||
|
<th>Fecha Salida</th> |
||||
|
<th>Fecha Llegada</th> |
||||
|
<th>Motivo</th> |
||||
|
<th>Domicilio</th> |
||||
|
<th>Personas</th> |
||||
|
<th>Chofer</th> |
||||
|
<th>Estado</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
@foreach($prestamos as $i => $prestamo) |
||||
|
<tr> |
||||
|
<td>{{ $i + 1 }}</td> |
||||
|
<td>{{ $prestamo->nombre_solicitante }}</td> |
||||
|
<td>{{ $prestamo->vehiculo->nombre ?? '-' }}</td> |
||||
|
<td>{{ $prestamo->destino }}</td> |
||||
|
<td>{{ \Carbon\Carbon::parse($prestamo->fecha_hora_salida)->format('d/m/Y H:i') }}</td> |
||||
|
<td>{{ \Carbon\Carbon::parse($prestamo->fecha_hora_llegada)->format('d/m/Y H:i') }}</td> |
||||
|
<td>{{ $prestamo->motivo }}</td> |
||||
|
<td>{{ $prestamo->domicilio }}</td> |
||||
|
<td>{{ $prestamo->numero_personas }}</td> |
||||
|
<td>{{ $prestamo->choferAsignado ? $prestamo->choferAsignado->nombre : 'Sin chofer' }}</td> |
||||
|
<td>{{ ucfirst($prestamo->estado) }}</td> |
||||
|
</tr> |
||||
|
@endforeach |
||||
|
</tbody> |
||||
|
</table> |
||||
|
<table class="firmas"> |
||||
|
<tr> |
||||
|
<td>_________________________<br>Elaboró</td> |
||||
|
<td>_________________________<br>Vo. Bo.</td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
</body> |
||||
|
</html> |
@ -0,0 +1,53 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html> |
||||
|
<head> |
||||
|
<title>Reporte de Puestos</title> |
||||
|
<style> |
||||
|
body { |
||||
|
font-family: Arial, sans-serif; |
||||
|
} |
||||
|
table { |
||||
|
width: 100%; |
||||
|
border-collapse: collapse; |
||||
|
margin-top: 20px; |
||||
|
} |
||||
|
th, td { |
||||
|
border: 1px solid #ddd; |
||||
|
padding: 8px; |
||||
|
text-align: left; |
||||
|
} |
||||
|
th { |
||||
|
background-color: #f2f2f2; |
||||
|
} |
||||
|
.header { |
||||
|
text-align: center; |
||||
|
margin-bottom: 30px; |
||||
|
} |
||||
|
</style> |
||||
|
</head> |
||||
|
<body> |
||||
|
<div class="header"> |
||||
|
<h1>Reporte de Puestos</h1> |
||||
|
<p>Fecha de generación: {{ date('d/m/Y H:i:s') }}</p> |
||||
|
</div> |
||||
|
|
||||
|
<table> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>#</th> |
||||
|
<th>Nombre del Puesto</th> |
||||
|
|
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
@foreach($puestos as $index => $puesto) |
||||
|
<tr> |
||||
|
<td>{{ $index + 1 }}</td> |
||||
|
<td>{{ $puesto->nombre }}</td> |
||||
|
|
||||
|
</tr> |
||||
|
@endforeach |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</body> |
||||
|
</html> |
@ -0,0 +1,47 @@ |
|||||
|
@extends('layouts.dashboard') |
||||
|
|
||||
|
@section('content') |
||||
|
<div class="container mx-auto px-4 py-6"> |
||||
|
<div class="bg-white rounded-lg shadow-lg"> |
||||
|
<div class="p-4 border-b border-gray-200 flex justify-between items-center"> |
||||
|
<h2 class="text-2xl font-bold">Préstamos Pendientes</h2> |
||||
|
</div> |
||||
|
<div class="overflow-x-auto"> |
||||
|
<table class="min-w-full divide-y divide-gray-200"> |
||||
|
<thead class="bg-gray-50"> |
||||
|
<tr> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">#</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Solicitante</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Destino</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Fecha Salida</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Fecha Llegada</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Motivo</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Domicilio</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Personas</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Chofer</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody class="bg-white divide-y divide-gray-200"> |
||||
|
@forelse($prestamos as $index => $prestamo) |
||||
|
<tr class="hover:bg-gray-50"> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ $index + 1 }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $prestamo->nombre_solicitante }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $prestamo->destino }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $prestamo->fecha_hora_salida }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $prestamo->fecha_hora_llegada }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $prestamo->motivo }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $prestamo->domicilio }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $prestamo->numero_personas }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{{ $prestamo->chofer ? 'Sí' : 'No' }}</td> |
||||
|
</tr> |
||||
|
@empty |
||||
|
<tr> |
||||
|
<td colspan="9" class="px-6 py-4 text-center text-gray-500">No hay préstamos pendientes.</td> |
||||
|
</tr> |
||||
|
@endforelse |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
@endsection |
@ -0,0 +1,91 @@ |
|||||
|
@extends('layouts.dashboard') |
||||
|
|
||||
|
@section('content') |
||||
|
<div class="container mx-auto px-4 py-6"> |
||||
|
<div class="bg-white rounded-lg shadow-lg"> |
||||
|
<div class="p-4 border-b border-gray-200 flex justify-between items-center"> |
||||
|
<h2 class="text-2xl font-bold">Préstamos Rechazados</h2> |
||||
|
</div> |
||||
|
<!-- Barra de búsqueda --> |
||||
|
<div class="p-4 border-b border-gray-200 bg-gray-50"> |
||||
|
<form action="{{ route('prestamos.rechazados') }}" method="GET" class="flex gap-2"> |
||||
|
<div class="relative w-full sm:w-64"> |
||||
|
<input type="text" |
||||
|
name="busqueda" |
||||
|
placeholder="Buscar préstamo..." |
||||
|
value="{{ request('busqueda') }}" |
||||
|
class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> |
||||
|
<div class="absolute left-3 top-2.5 text-gray-400"> |
||||
|
<i class="fas fa-search"></i> |
||||
|
</div> |
||||
|
</div> |
||||
|
<button type="submit" class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600"> |
||||
|
Buscar |
||||
|
</button> |
||||
|
@if(request('busqueda')) |
||||
|
<a href="{{ route('prestamos.rechazados') }}" class="px-4 py-2 bg-gray-500 text-white rounded-lg hover:bg-gray-600"> |
||||
|
Limpiar |
||||
|
</a> |
||||
|
@endif |
||||
|
</form> |
||||
|
</div> |
||||
|
<div class="overflow-x-auto"> |
||||
|
<table class="min-w-full divide-y divide-gray-200"> |
||||
|
<thead class="bg-gray-50"> |
||||
|
<tr> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Número</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Solicitante</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Destino</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Fecha Salida</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Fecha Llegada</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Motivo</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Domicilio</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Personas</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Chofer</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Estado</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody class="bg-white divide-y divide-gray-200"> |
||||
|
@forelse($prestamos as $prestamo) |
||||
|
<tr class="hover:bg-gray-50"> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ $prestamo->id }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"> |
||||
|
<i class="fas fa-user text-blue-500 mr-2"></i> |
||||
|
{{ $prestamo->nombre_solicitante }} |
||||
|
</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm"> |
||||
|
<i class="fas fa-map-marker-alt text-red-500 mr-2"></i> |
||||
|
{{ $prestamo->destino }} |
||||
|
</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm"> |
||||
|
<i class="fas fa-calendar text-green-500 mr-2"></i> |
||||
|
{{ \Carbon\Carbon::parse($prestamo->fecha_hora_salida)->format('d/m/Y H:i') }} |
||||
|
</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm"> |
||||
|
<i class="fas fa-calendar-check text-yellow-500 mr-2"></i> |
||||
|
{{ \Carbon\Carbon::parse($prestamo->fecha_hora_llegada)->format('d/m/Y H:i') }} |
||||
|
</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm">{{ $prestamo->motivo }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm">{{ $prestamo->domicilio }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-center">{{ $prestamo->numero_personas }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm">{{ $prestamo->chofer ? 'Sí' : 'No' }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm"> |
||||
|
<span class="inline-flex items-center px-3 py-1 rounded-full bg-red-50"> |
||||
|
<span class="flex items-center justify-center w-5 h-5 rounded-full bg-red-700 mr-2"> |
||||
|
<i class="fas fa-times text-white text-xs"></i> |
||||
|
</span> |
||||
|
<span class="text-red-700 font-semibold">Rechazado</span> |
||||
|
</span> |
||||
|
</td> |
||||
|
</tr> |
||||
|
@empty |
||||
|
<tr> |
||||
|
<td colspan="10" class="px-6 py-4 text-center text-gray-500">No hay préstamos rechazados.</td> |
||||
|
</tr> |
||||
|
@endforelse |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
@endsection |
@ -0,0 +1,23 @@ |
|||||
|
@extends('layouts.dashboard') |
||||
|
|
||||
|
@section('content') |
||||
|
<div class="container mx-auto px-4 py-6"> |
||||
|
<div class="max-w-lg mx-auto bg-white rounded-lg shadow-lg p-6"> |
||||
|
<h2 class="text-2xl font-bold mb-4 text-gray-800">Detalle del Préstamo</h2> |
||||
|
<ul class="divide-y divide-gray-200"> |
||||
|
<li class="py-2"><strong>Solicitante:</strong> {{ $prestamo->nombre_solicitante }}</li> |
||||
|
<li class="py-2"><strong>Destino:</strong> {{ $prestamo->destino }}</li> |
||||
|
<li class="py-2"><strong>Fecha y Hora de Salida:</strong> {{ $prestamo->fecha_hora_salida }}</li> |
||||
|
<li class="py-2"><strong>Fecha y Hora de Llegada:</strong> {{ $prestamo->fecha_hora_llegada }}</li> |
||||
|
<li class="py-2"><strong>Motivo:</strong> {{ $prestamo->motivo }}</li> |
||||
|
<li class="py-2"><strong>Domicilio:</strong> {{ $prestamo->domicilio }}</li> |
||||
|
<li class="py-2"><strong>Número de Personas:</strong> {{ $prestamo->numero_personas }}</li> |
||||
|
<li class="py-2"><strong>Chofer:</strong> {{ $prestamo->chofer ? 'Sí' : 'No' }}</li> |
||||
|
<li class="py-2"><strong>Estado:</strong> {{ $prestamo->estado }}</li> |
||||
|
</ul> |
||||
|
<div class="mt-6"> |
||||
|
<a href="{{ route('prestamos.index') }}" class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">Volver</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
@endsection |
@ -0,0 +1,78 @@ |
|||||
|
@extends('layouts.dashboard') |
||||
|
|
||||
|
@section('content') |
||||
|
<div class="container mx-auto px-4 py-6"> |
||||
|
<div class="max-w-2xl mx-auto"> |
||||
|
<div class="bg-white rounded-lg shadow-lg overflow-hidden"> |
||||
|
<div class="p-6"> |
||||
|
<h2 class="text-2xl font-bold text-gray-800 mb-6">Nueva Solicitud de Vehículo</h2> |
||||
|
|
||||
|
@if($errors->any()) |
||||
|
<div class="mb-6 bg-red-50 border-l-4 border-red-500 p-4 rounded-r-lg"> |
||||
|
<div class="flex items-center"> |
||||
|
<div class="text-red-700"> |
||||
|
<ul> |
||||
|
@foreach($errors->all() as $error) |
||||
|
<li>{{ $error }}</li> |
||||
|
@endforeach |
||||
|
</ul> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
@endif |
||||
|
|
||||
|
<form action="{{ route('profesor.solicitudes.store') }}" method="POST"> |
||||
|
@csrf |
||||
|
<div class="space-y-6"> |
||||
|
<div> |
||||
|
<label for="fecha_solicitud" class="block text-sm font-medium text-gray-700 mb-2">Fecha de Solicitud</label> |
||||
|
<input type="date" name="fecha_solicitud" id="fecha_solicitud" |
||||
|
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" |
||||
|
required> |
||||
|
</div> |
||||
|
|
||||
|
<div> |
||||
|
<label for="hora_salida" class="block text-sm font-medium text-gray-700 mb-2">Hora de Salida</label> |
||||
|
<input type="time" name="hora_salida" id="hora_salida" |
||||
|
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" |
||||
|
required> |
||||
|
</div> |
||||
|
|
||||
|
<div> |
||||
|
<label for="hora_regreso" class="block text-sm font-medium text-gray-700 mb-2">Hora de Regreso</label> |
||||
|
<input type="time" name="hora_regreso" id="hora_regreso" |
||||
|
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" |
||||
|
required> |
||||
|
</div> |
||||
|
|
||||
|
<div> |
||||
|
<label for="destino" class="block text-sm font-medium text-gray-700 mb-2">Destino</label> |
||||
|
<input type="text" name="destino" id="destino" |
||||
|
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" |
||||
|
required> |
||||
|
</div> |
||||
|
|
||||
|
<div> |
||||
|
<label for="motivo" class="block text-sm font-medium text-gray-700 mb-2">Motivo</label> |
||||
|
<textarea name="motivo" id="motivo" rows="4" |
||||
|
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500" |
||||
|
required></textarea> |
||||
|
</div> |
||||
|
|
||||
|
<div class="flex justify-end space-x-4"> |
||||
|
<a href="{{ route('profesor.solicitudes.index') }}" |
||||
|
class="px-4 py-2 border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"> |
||||
|
Cancelar |
||||
|
</a> |
||||
|
<button type="submit" |
||||
|
class="px-4 py-2 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"> |
||||
|
Enviar Solicitud |
||||
|
</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</form> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
@endsection |
@ -0,0 +1,51 @@ |
|||||
|
@extends('layouts.dashboard') |
||||
|
|
||||
|
@section('content') |
||||
|
<div class="container mx-auto px-4 py-6"> |
||||
|
<div class="flex justify-between items-center mb-6"> |
||||
|
<h2 class="text-2xl font-bold text-gray-800">Mis Solicitudes de Vehículo</h2> |
||||
|
<a href="{{ route('profesor.solicitudes.create') }}" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"> |
||||
|
Nueva Solicitud |
||||
|
</a> |
||||
|
</div> |
||||
|
|
||||
|
@if(session('success')) |
||||
|
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative mb-4" role="alert"> |
||||
|
<span class="block sm:inline">{{ session('success') }}</span> |
||||
|
</div> |
||||
|
@endif |
||||
|
|
||||
|
<div class="bg-white shadow-md rounded-lg overflow-hidden"> |
||||
|
<table class="min-w-full divide-y divide-gray-200"> |
||||
|
<thead class="bg-gray-50"> |
||||
|
<tr> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Fecha</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Hora Salida</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Hora Regreso</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Destino</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Estado</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody class="bg-white divide-y divide-gray-200"> |
||||
|
@foreach($solicitudes as $solicitud) |
||||
|
<tr> |
||||
|
<td class="px-6 py-4 whitespace-nowrap">{{ $solicitud->fecha_solicitud }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap">{{ $solicitud->hora_salida }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap">{{ $solicitud->hora_regreso }}</td> |
||||
|
<td class="px-6 py-4">{{ $solicitud->destino }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap"> |
||||
|
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full |
||||
|
@if($solicitud->estado === 'aprobada') bg-green-100 text-green-800 |
||||
|
@elseif($solicitud->estado === 'rechazada') bg-red-100 text-red-800 |
||||
|
@else bg-yellow-100 text-yellow-800 |
||||
|
@endif"> |
||||
|
{{ ucfirst($solicitud->estado) }} |
||||
|
</span> |
||||
|
</td> |
||||
|
</tr> |
||||
|
@endforeach |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
</div> |
||||
|
@endsection |
@ -0,0 +1,142 @@ |
|||||
|
@extends('layouts.dashboard') |
||||
|
|
||||
|
@section('content') |
||||
|
<div class="container mx-auto px-4 py-6"> |
||||
|
<!-- Mensajes de éxito y error --> |
||||
|
@if(session('success')) |
||||
|
<div id="success-message" class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative mb-4" role="alert"> |
||||
|
<span class="block sm:inline">{{ session('success') }}</span> |
||||
|
</div> |
||||
|
@endif |
||||
|
|
||||
|
@if(session('error')) |
||||
|
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4" role="alert"> |
||||
|
<span class="block sm:inline">{{ session('error') }}</span> |
||||
|
</div> |
||||
|
@endif |
||||
|
|
||||
|
<div class="bg-white rounded-lg shadow-lg"> |
||||
|
<!-- Encabezado con título y botones de acción --> |
||||
|
<div class="p-4 border-b border-gray-200 flex justify-between items-center"> |
||||
|
<h2 class="text-2xl font-bold">Gestión de Puestos</h2> |
||||
|
<div class="flex items-center space-x-6"> |
||||
|
<!-- Íconos de agregar --> |
||||
|
<div class="flex space-x-4"> |
||||
|
<a href="{{ route('puestos.excel') }}" |
||||
|
class="text-green-600 hover:text-green-700 transition-colors duration-200" |
||||
|
title="Exportar a Excel"> |
||||
|
<i class="fas fa-file-excel text-xl"></i> |
||||
|
</a> |
||||
|
|
||||
|
<a href="{{ route('puestos.pdf') }}" |
||||
|
class="text-red-600 hover:text-red-700 transition-colors duration-200" |
||||
|
title="Exportar a PDF"> |
||||
|
<i class="fas fa-file-pdf text-xl"></i> |
||||
|
</a> |
||||
|
<!-- Agregar nuevo puesto --> |
||||
|
<a href="{{ route('puestos.create') }}" |
||||
|
class="text-blue-500 hover:text-blue-600 transition-colors duration-200" |
||||
|
title="Agregar nuevo puesto"> |
||||
|
<i class="fas fa-plus text-xl"></i> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- Barra de búsqueda --> |
||||
|
<div class="p-4 border-b border-gray-200 bg-gray-50"> |
||||
|
<form action="{{ route('puestos.index') }}" method="GET" class="flex gap-2"> |
||||
|
<div class="relative w-full sm:w-64"> |
||||
|
<input type="text" |
||||
|
name="busqueda" |
||||
|
placeholder="Buscar puesto..." |
||||
|
value="{{ request('busqueda') }}" |
||||
|
class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> |
||||
|
<div class="absolute left-3 top-2.5 text-gray-400"> |
||||
|
<i class="fas fa-search"></i> |
||||
|
</div> |
||||
|
</div> |
||||
|
<button type="submit" class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600"> |
||||
|
Buscar |
||||
|
</button> |
||||
|
@if(request('busqueda')) |
||||
|
<a href="{{ route('puestos.index') }}" class="px-4 py-2 bg-gray-500 text-white rounded-lg hover:bg-gray-600"> |
||||
|
Limpiar |
||||
|
</a> |
||||
|
@endif |
||||
|
</form> |
||||
|
</div> |
||||
|
|
||||
|
<!-- Tabla de puestos --> |
||||
|
<div class="overflow-x-auto"> |
||||
|
<table class="min-w-full divide-y divide-gray-200"> |
||||
|
<thead class="bg-gray-50"> |
||||
|
<tr> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Número</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Puesto</th> |
||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Acciones</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody class="bg-white divide-y divide-gray-200"> |
||||
|
@foreach($puestos as $index => $puesto) |
||||
|
<tr class="hover:bg-gray-50"> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ $index + 1 }}</td> |
||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"> |
||||
|
<i class="fas fa-briefcase text-blue-500 mr-2"></i> |
||||
|
{{ $puesto->nombre }} |
||||
|
</td> |
||||
|
<td class="flex space-x-2 px-6 py-4 whitespace-nowrap text-sm"> |
||||
|
<a href="{{ route('puestos.edit', $puesto->id) }}" |
||||
|
class="text-yellow-600 hover:text-yellow-700 transition-colors duration-200" |
||||
|
title="Editar puesto"> |
||||
|
<i class="fas fa-edit"></i> |
||||
|
</a> |
||||
|
<form action="{{ route('puestos.destroy', $puesto->id) }}" method="POST" class="d-inline"> |
||||
|
@csrf |
||||
|
@method('DELETE') |
||||
|
<a href="#" onclick="event.preventDefault(); confirmarEliminacion(this);" |
||||
|
class="text-red-600 hover:text-red-700 transition-colors duration-200" |
||||
|
title="Eliminar puesto"> |
||||
|
<i class="fas fa-trash"></i> |
||||
|
</a> |
||||
|
</form> |
||||
|
</td> |
||||
|
</tr> |
||||
|
@endforeach |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<script> |
||||
|
// Desaparecer el mensaje después de 3 segundos |
||||
|
setTimeout(function() { |
||||
|
var message = document.getElementById('success-message'); |
||||
|
if (message) { |
||||
|
message.style.transition = 'opacity 0.5s ease'; |
||||
|
message.style.opacity = '0'; |
||||
|
setTimeout(function() { |
||||
|
message.remove(); |
||||
|
}, 500); |
||||
|
} |
||||
|
}, 3000); |
||||
|
|
||||
|
function confirmarEliminacion(button) { |
||||
|
Swal.fire({ |
||||
|
title: '¿Estás seguro?', |
||||
|
text: "Esta acción no se puede deshacer", |
||||
|
icon: 'warning', |
||||
|
showCancelButton: true, |
||||
|
confirmButtonColor: '#3085d6', |
||||
|
cancelButtonColor: '#d33', |
||||
|
confirmButtonText: 'Sí, eliminar', |
||||
|
cancelButtonText: 'Cancelar' |
||||
|
}).then((result) => { |
||||
|
if (result.isConfirmed) { |
||||
|
button.closest('form').submit(); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
</script> |
||||
|
@endsection |
@ -1,152 +0,0 @@ |
|||||
@extends('layouts.dashboard') |
|
||||
|
|
||||
@section('content') |
|
||||
<div class="container mx-auto px-4 py-6"> |
|
||||
<!-- Mensajes de éxito y error --> |
|
||||
@if(session('success')) |
|
||||
<div id="success-message" class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative mb-4" role="alert"> |
|
||||
<span class="block sm:inline">{{ session('success') }}</span> |
|
||||
</div> |
|
||||
@endif |
|
||||
|
|
||||
@if(session('error')) |
|
||||
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4" role="alert"> |
|
||||
<span class="block sm:inline">{{ session('error') }}</span> |
|
||||
</div> |
|
||||
@endif |
|
||||
|
|
||||
<div class="bg-white rounded-lg shadow-lg"> |
|
||||
<!-- Encabezado con título y botones de acción --> |
|
||||
<div class="p-4 border-b border-gray-200 flex justify-between items-center"> |
|
||||
<h2 class="text-2xl font-bold">Gestión de Tipos de Licencias</h2> |
|
||||
<div class="flex items-center space-x-6"> |
|
||||
<!-- Íconos de exportación y agregar --> |
|
||||
<div class="flex space-x-4"> |
|
||||
<!-- Exportar a Excel --> |
|
||||
<a href="{{ route('tiposLicencias.excel') }}" |
|
||||
class="text-green-600 hover:text-green-700 transition-colors duration-200" |
|
||||
title="Exportar a Excel"> |
|
||||
<i class="fas fa-file-excel text-xl"></i> |
|
||||
</a> |
|
||||
|
|
||||
<!-- Exportar a PDF --> |
|
||||
<a href="{{ route('tiposLicencias.pdf') }}" |
|
||||
class="text-red-600 hover:text-red-700 transition-colors duration-200" |
|
||||
title="Exportar a PDF"> |
|
||||
<i class="fas fa-file-pdf text-xl"></i> |
|
||||
</a> |
|
||||
|
|
||||
<!-- Agregar nuevo tipo de licencia --> |
|
||||
<a href="{{ route('tiposLicencias.create') }}" |
|
||||
class="text-blue-500 hover:text-blue-600 transition-colors duration-200" |
|
||||
title="Agregar nuevo tipo de licencia"> |
|
||||
<i class="fas fa-plus text-xl"></i> |
|
||||
</a> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
<!-- Barra de búsqueda --> |
|
||||
<div class="p-4 border-b border-gray-200 bg-gray-50"> |
|
||||
<form action="{{ route('tiposLicencias.index') }}" method="GET" class="flex gap-2"> |
|
||||
<div class="relative w-full sm:w-64"> |
|
||||
<input type="text" |
|
||||
name="busqueda" |
|
||||
placeholder="Buscar tipo de licencia..." |
|
||||
value="{{ request('busqueda') }}" |
|
||||
class="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> |
|
||||
<div class="absolute left-3 top-2.5 text-gray-400"> |
|
||||
<i class="fas fa-search"></i> |
|
||||
</div> |
|
||||
</div> |
|
||||
<button type="submit" class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600"> |
|
||||
Buscar/Actualizar |
|
||||
</button> |
|
||||
@if(request('busqueda')) |
|
||||
<a href="{{ route('tiposLicencias.index') }}" class="px-4 py-2 bg-gray-500 text-white rounded-lg hover:bg-gray-600"> |
|
||||
Limpiar |
|
||||
</a> |
|
||||
@endif |
|
||||
</form> |
|
||||
</div> |
|
||||
|
|
||||
<!-- Tabla de tipos de licencias --> |
|
||||
<div class="overflow-x-auto"> |
|
||||
<table class="min-w-full divide-y divide-gray-200"> |
|
||||
<thead class="bg-gray-50"> |
|
||||
<tr> |
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID</th> |
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tipo de Licencia</th> |
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Estado</th> |
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Acciones</th> |
|
||||
</tr> |
|
||||
</thead> |
|
||||
<tbody class="bg-white divide-y divide-gray-200"> |
|
||||
@foreach($tiposLicencias as $tipoLicencia) |
|
||||
<tr class="hover:bg-gray-50"> |
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{{ $tipoLicencia->id }}</td> |
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900"> |
|
||||
<i class="fas fa-id-card text-blue-500 mr-2"></i> |
|
||||
{{ $tipoLicencia->tipoLicencia }} |
|
||||
</td> |
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm"> |
|
||||
@if($tipoLicencia->eliminado == 1) |
|
||||
<span class="flex items-center"> |
|
||||
<span class="h-2 w-2 bg-green-500 rounded-full mr-2"></span> Activo |
|
||||
</span> |
|
||||
@else |
|
||||
<span class="flex items-center"> |
|
||||
<span class="h-2 w-2 bg-red-500 rounded-full mr-2"></span> Inactivo |
|
||||
</span> |
|
||||
@endif |
|
||||
</td> |
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm"> |
|
||||
<div class="flex gap-2"> |
|
||||
@if($tipoLicencia->eliminado == 0) |
|
||||
<a href="{{ route('tiposLicencias.toggle-status', ['id' => $tipoLicencia->id]) }}" |
|
||||
class="text-green-600 hover:text-green-700 transition-colors duration-200" |
|
||||
title="Recuperar tipo de licencia"> |
|
||||
<i class="fas fa-undo"></i> |
|
||||
</a> |
|
||||
@else |
|
||||
<a href="{{ route('tiposLicencias.edit', $tipoLicencia->id) }}" |
|
||||
class="text-yellow-600 hover:text-yellow-700 transition-colors duration-200" |
|
||||
title="Editar tipo de licencia"> |
|
||||
<i class="fas fa-edit"></i> |
|
||||
</a> |
|
||||
<form action="{{ route('tiposLicencias.destroy', $tipoLicencia->id) }}" |
|
||||
method="POST" |
|
||||
class="inline"> |
|
||||
@csrf |
|
||||
@method('DELETE') |
|
||||
<button type="submit" |
|
||||
class="text-red-600 hover:text-red-700 transition-colors duration-200" |
|
||||
title="Eliminar tipo de licencia"> |
|
||||
<i class="fas fa-trash"></i> |
|
||||
</button> |
|
||||
</form> |
|
||||
@endif |
|
||||
</div> |
|
||||
</td> |
|
||||
</tr> |
|
||||
@endforeach |
|
||||
</tbody> |
|
||||
</table> |
|
||||
</div> |
|
||||
</div> |
|
||||
</div> |
|
||||
|
|
||||
<script> |
|
||||
// Desaparecer el mensaje después de 3 segundos |
|
||||
setTimeout(function() { |
|
||||
var message = document.getElementById('success-message'); |
|
||||
if (message) { |
|
||||
message.style.transition = 'opacity 0.5s ease'; |
|
||||
message.style.opacity = '0'; |
|
||||
setTimeout(function() { |
|
||||
message.remove(); |
|
||||
}, 500); |
|
||||
} |
|
||||
}, 3000); |
|
||||
</script> |
|
||||
@endsection |
|
@ -0,0 +1,402 @@ |
|||||
|
@extends('layouts.app') |
||||
|
|
||||
|
@section('title', 'Reporte de Usuario - PrestamosTecmm') |
||||
|
@push('head') |
||||
|
<link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}"> |
||||
|
@endpush |
||||
|
|
||||
|
@section('content') |
||||
|
<link rel="stylesheet" href="{{ asset('css/user-dashboard.css') }}"> |
||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
||||
|
|
||||
|
<style> |
||||
|
.contenedor-flex { |
||||
|
display: flex; |
||||
|
gap: 32px; |
||||
|
align-items: flex-start; |
||||
|
justify-content: center; |
||||
|
flex-wrap: nowrap; |
||||
|
height: 100%; |
||||
|
} |
||||
|
.tabla-reporte { |
||||
|
font-family: 'Century Gothic', sans-serif; |
||||
|
font-size: 12px; |
||||
|
border-collapse: collapse; |
||||
|
width: 100%; |
||||
|
min-width: 500px; |
||||
|
max-width: 800px; |
||||
|
background: #fff; |
||||
|
box-shadow: 0 2px 8px #0001; |
||||
|
border-radius: 10px; |
||||
|
overflow: hidden; |
||||
|
margin: 0 auto; |
||||
|
} |
||||
|
.tabla-reporte th, .tabla-reporte td { |
||||
|
border: 1px solid #e2e8f0; |
||||
|
padding: 8px; |
||||
|
text-align: center; |
||||
|
vertical-align: middle; |
||||
|
} |
||||
|
.tabla-reporte th { |
||||
|
background: #f7fafc; |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
.miniatura-img { |
||||
|
width: 50px; |
||||
|
height: 50px; |
||||
|
object-fit: cover; |
||||
|
border-radius: 6px; |
||||
|
border: 1px solid #ccc; |
||||
|
} |
||||
|
</style> |
||||
|
|
||||
|
@php |
||||
|
if (!isset($prestamo)) $prestamo = null; |
||||
|
@endphp |
||||
|
|
||||
|
<body class="user-dashboard-bg"> |
||||
|
<!-- Botón de cerrar sesión --> |
||||
|
<div class="user-dashboard-logout"> |
||||
|
<form method="POST" action="{{ route('logout') }}"> |
||||
|
@csrf |
||||
|
<button type="submit" class="user-dashboard-logout-btn"> |
||||
|
<i class="fas fa-sign-out-alt"></i> Cerrar Sesión |
||||
|
</button> |
||||
|
</form> |
||||
|
</div> |
||||
|
<div class="user-dashboard-header">PrestamosTecmm</div> |
||||
|
<div class="contenedor-flex"> |
||||
|
<div class="user-dashboard-card" style="min-width:350px;max-width:400px;flex:1; margin-top:40px;"> |
||||
|
<h1 class="user-dashboard-title">Reporte de Usuario</h1> |
||||
|
@if($prestamo) |
||||
|
<div class="alert alert-primary" style="font-size:1.1rem; font-weight:600; margin-bottom:24px;"> |
||||
|
Seleccionaste el préstamo con destino: <strong>{{ $prestamo->destino }}</strong> |
||||
|
</div> |
||||
|
@endif |
||||
|
<form id="form-reporte" style="font-family: 'Century Gothic', sans-serif; font-size: 12px;"> |
||||
|
<div style="margin-bottom: 18px; text-align:left;"> |
||||
|
<label for="foto_gasolina_inicio" style="font-weight:600; color:#2d3748;">Foto de la gasolina (antes de salir):</label><br><br> |
||||
|
<input type="file" id="foto_gasolina_inicio" name="foto_gasolina_inicio" accept="image/*" style="width:100%;"> |
||||
|
</div> |
||||
|
<div style="margin-bottom: 18px; text-align:left;"> |
||||
|
<label for="foto_vehiculo" style="font-weight:600; color:#2d3748;">Foto del vehículo:</label><br><br> |
||||
|
<input type="file" id="foto_vehiculo" name="foto_vehiculo" accept="image/*" style="width:100%;"> |
||||
|
</div> |
||||
|
<div style="margin-bottom: 18px; text-align:left;"> |
||||
|
<label for="foto_gasolina_fin" style="font-weight:600; color:#2d3748;">Foto de la gasolina (después de regresar):</label><br><br> |
||||
|
<input type="file" id="foto_gasolina_fin" name="foto_gasolina_fin" accept="image/*" style="width:100%;"> |
||||
|
</div> |
||||
|
<div style="margin-bottom: 18px; text-align:left;"> |
||||
|
<label for="fecha_salida" style="font-weight:600; color:#2d3748;">Fecha y hora de salida:</label><br><br> |
||||
|
<input type="datetime-local" id="fecha_salida" name="fecha_salida" style="width:100%; padding:8px; border-radius:6px; border:1px solid #ccc;"> |
||||
|
</div> |
||||
|
<div style="margin-bottom: 18px; text-align:left;"> |
||||
|
<label for="fecha_regreso" style="font-weight:600; color:#2d3748;">Fecha y hora de regreso:</label><br><br> |
||||
|
<input type="datetime-local" id="fecha_regreso" name="fecha_regreso" style="width:100%; padding:8px; border-radius:6px; border:1px solid #ccc;"> |
||||
|
</div> |
||||
|
<div style="margin-bottom: 18px; text-align:left;"> |
||||
|
<label for="motivo" style="font-weight:600; color:#2d3748;">Motivo del préstamo:</label><br><br> |
||||
|
<textarea id="motivo" name="motivo" style="width:100%; padding:8px; border-radius:6px; border:1px solid #ccc; min-height:100px;" placeholder="Especifique el motivo del préstamo del vehículo..."></textarea> |
||||
|
</div> |
||||
|
<button type="submit" class="user-dashboard-btn" style="width:100%; margin-top:10px;">Guardar</button> |
||||
|
</form> |
||||
|
</div> |
||||
|
<div style="flex:1; min-width:350px; max-width:800px;"> |
||||
|
<table class="tabla-reporte" id="tabla-reporte"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Gasolina (salida)</th> |
||||
|
<th>Vehículo</th> |
||||
|
<th>Gasolina (regreso)</th> |
||||
|
<th>Fecha salida</th> |
||||
|
<th>Fecha regreso</th> |
||||
|
<th>Motivo</th> |
||||
|
<th>Acciones</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
<!-- Aquí se agregarán los registros --> |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- jsPDF y autoTable --> |
||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script> |
||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.7.0/jspdf.plugin.autotable.min.js"></script> |
||||
|
<script> |
||||
|
// Iconos SVG para editar, eliminar y PDF |
||||
|
const iconoEditar = `<button type='button' class='btn-accion editar' title='Editar' style='background:none;border:none;cursor:pointer;'><i class="fas fa-edit" style="color:#3182ce;font-size:20px;"></i></button>`; |
||||
|
const iconoEliminar = `<button type='button' class='btn-accion eliminar' title='Eliminar' style='background:none;border:none;cursor:pointer;'><i class="fas fa-trash-alt" style="color:#e53e3e;font-size:20px;"></i></button>`; |
||||
|
const iconoPDF = `<button type='button' class='btn-accion pdf' title='Generar PDF' style='background:none;border:none;cursor:pointer;'><i class="fas fa-file-pdf" style="color:#e53e3e;font-size:20px;"></i></button>`; |
||||
|
|
||||
|
let filaEditando = null; |
||||
|
|
||||
|
// Agregar SweetAlert2 CDN si no está |
||||
|
if (!window.Swal) { |
||||
|
var script = document.createElement('script'); |
||||
|
script.src = 'https://cdn.jsdelivr.net/npm/sweetalert2@11'; |
||||
|
document.head.appendChild(script); |
||||
|
} |
||||
|
|
||||
|
document.getElementById('form-reporte').addEventListener('submit', function(e) { |
||||
|
e.preventDefault(); |
||||
|
// Obtener los archivos y datos |
||||
|
const fotoGasIni = document.getElementById('foto_gasolina_inicio').files[0]; |
||||
|
const fotoVehiculo = document.getElementById('foto_vehiculo').files[0]; |
||||
|
const fotoGasFin = document.getElementById('foto_gasolina_fin').files[0]; |
||||
|
const fechaSalida = document.getElementById('fecha_salida').value; |
||||
|
const fechaRegreso = document.getElementById('fecha_regreso').value; |
||||
|
const motivo = document.getElementById('motivo').value; |
||||
|
|
||||
|
function crearMiniatura(archivo) { |
||||
|
if (!archivo) return ''; |
||||
|
const url = URL.createObjectURL(archivo); |
||||
|
return `<div><img src="${url}" class='miniatura-img img-clickable' data-img-url="${url}" alt="${archivo ? archivo.name : ''}"><br><span>${archivo.name}</span></div>`; |
||||
|
} |
||||
|
|
||||
|
// Si estamos editando una fila, actualizamos esa fila y no agregamos una nueva |
||||
|
if (filaEditando) { |
||||
|
filaEditando.innerHTML = ` |
||||
|
<td>${crearMiniatura(fotoGasIni)}</td> |
||||
|
<td>${crearMiniatura(fotoVehiculo)}</td> |
||||
|
<td>${crearMiniatura(fotoGasFin)}</td> |
||||
|
<td>${fechaSalida ? fechaSalida.replace('T', ' ') : ''}</td> |
||||
|
<td>${fechaRegreso ? fechaRegreso.replace('T', ' ') : ''}</td> |
||||
|
<td>${motivo}</td> |
||||
|
<td>${iconoEditar}${iconoEliminar}${iconoPDF}</td> |
||||
|
`; |
||||
|
filaEditando = null; |
||||
|
document.getElementById('form-reporte').reset(); |
||||
|
asignarEventosMiniaturas(); |
||||
|
asignarEventosAcciones(); |
||||
|
Swal.fire({ |
||||
|
icon: 'success', |
||||
|
title: '¡Editado correctamente!', |
||||
|
showConfirmButton: false, |
||||
|
timer: 1500 |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// Si no estamos editando, agregamos una nueva fila |
||||
|
const tabla = document.getElementById('tabla-reporte').querySelector('tbody'); |
||||
|
const fila = document.createElement('tr'); |
||||
|
fila.innerHTML = ` |
||||
|
<td>${crearMiniatura(fotoGasIni)}</td> |
||||
|
<td>${crearMiniatura(fotoVehiculo)}</td> |
||||
|
<td>${crearMiniatura(fotoGasFin)}</td> |
||||
|
<td>${fechaSalida ? fechaSalida.replace('T', ' ') : ''}</td> |
||||
|
<td>${fechaRegreso ? fechaRegreso.replace('T', ' ') : ''}</td> |
||||
|
<td>${motivo}</td> |
||||
|
<td>${iconoEditar}${iconoEliminar}${iconoPDF}</td> |
||||
|
`; |
||||
|
tabla.appendChild(fila); |
||||
|
document.getElementById('form-reporte').reset(); |
||||
|
asignarEventosMiniaturas(); |
||||
|
asignarEventosAcciones(); |
||||
|
Swal.fire({ |
||||
|
icon: 'success', |
||||
|
title: '¡Guardado correctamente!', |
||||
|
showConfirmButton: false, |
||||
|
timer: 1500 |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
// Modal para mostrar imagen grande |
||||
|
function crearModalImagen() { |
||||
|
if (document.getElementById('modal-img-grande')) return; |
||||
|
const modal = document.createElement('div'); |
||||
|
modal.id = 'modal-img-grande'; |
||||
|
modal.style.position = 'fixed'; |
||||
|
modal.style.top = 0; |
||||
|
modal.style.left = 0; |
||||
|
modal.style.width = '100vw'; |
||||
|
modal.style.height = '100vh'; |
||||
|
modal.style.background = 'rgba(0,0,0,0.7)'; |
||||
|
modal.style.display = 'none'; |
||||
|
modal.style.alignItems = 'center'; |
||||
|
modal.style.justifyContent = 'center'; |
||||
|
modal.style.zIndex = 9999; |
||||
|
modal.style.cursor = 'pointer'; |
||||
|
modal.innerHTML = ` |
||||
|
<div style="position:relative; max-width:90vw; max-height:90vh;"> |
||||
|
<span id="cerrar-modal-img" style="position:absolute;top:-30px;right:0;font-size:2rem;color:white;cursor:pointer;font-weight:bold;">×</span> |
||||
|
<img id="img-modal-grande" src="" alt="Imagen grande" style="max-width:90vw; max-height:80vh; border-radius:10px; box-shadow:0 2px 16px #0008; background:#fff;"> |
||||
|
</div> |
||||
|
`; |
||||
|
document.body.appendChild(modal); |
||||
|
modal.addEventListener('click', function(e) { |
||||
|
if (e.target === modal || e.target.id === 'cerrar-modal-img') { |
||||
|
modal.style.display = 'none'; |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function asignarEventosMiniaturas() { |
||||
|
crearModalImagen(); |
||||
|
document.querySelectorAll('.img-clickable').forEach(img => { |
||||
|
img.onclick = function(e) { |
||||
|
e.stopPropagation(); |
||||
|
const modal = document.getElementById('modal-img-grande'); |
||||
|
const imgModal = document.getElementById('img-modal-grande'); |
||||
|
imgModal.src = img.getAttribute('data-img-url'); |
||||
|
modal.style.display = 'flex'; |
||||
|
}; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// Asignar eventos a los botones de editar, eliminar y PDF |
||||
|
function asignarEventosAcciones() { |
||||
|
document.querySelectorAll('.btn-accion.eliminar').forEach(btn => { |
||||
|
btn.onclick = function() { |
||||
|
Swal.fire({ |
||||
|
title: '¿Estás seguro?', |
||||
|
text: 'Esta acción no se puede deshacer', |
||||
|
icon: 'warning', |
||||
|
showCancelButton: true, |
||||
|
confirmButtonColor: '#3085d6', |
||||
|
cancelButtonColor: '#d33', |
||||
|
confirmButtonText: 'Sí, eliminar', |
||||
|
cancelButtonText: 'Cancelar' |
||||
|
}).then((result) => { |
||||
|
if (result.isConfirmed) { |
||||
|
const fila = btn.closest('tr'); |
||||
|
fila.remove(); |
||||
|
Swal.fire({ |
||||
|
icon: 'success', |
||||
|
title: '¡Eliminado correctamente!', |
||||
|
showConfirmButton: false, |
||||
|
timer: 1500 |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
}; |
||||
|
}); |
||||
|
document.querySelectorAll('.btn-accion.editar').forEach(btn => { |
||||
|
btn.onclick = function() { |
||||
|
const fila = btn.closest('tr'); |
||||
|
const celdas = fila.querySelectorAll('td'); |
||||
|
document.getElementById('foto_gasolina_inicio').value = ''; |
||||
|
document.getElementById('foto_vehiculo').value = ''; |
||||
|
document.getElementById('foto_gasolina_fin').value = ''; |
||||
|
document.getElementById('fecha_salida').value = celdas[3].innerText.replace(' ', 'T'); |
||||
|
document.getElementById('fecha_regreso').value = celdas[4].innerText.replace(' ', 'T'); |
||||
|
document.getElementById('motivo').value = celdas[5].innerText; |
||||
|
filaEditando = fila; |
||||
|
window.scrollTo({top:0, behavior:'smooth'}); |
||||
|
}; |
||||
|
}); |
||||
|
document.querySelectorAll('.btn-accion.pdf').forEach(btn => { |
||||
|
btn.onclick = function() { |
||||
|
const fila = btn.closest('tr'); |
||||
|
const celdas = fila.querySelectorAll('td'); |
||||
|
generarPDFPersonalizado({ |
||||
|
motivo: celdas[5].innerText.trim(), |
||||
|
fechaSalida: celdas[3].innerText.trim(), |
||||
|
fechaRegreso: celdas[4].innerText.trim(), |
||||
|
imagenes: [ |
||||
|
fila.querySelectorAll('img.miniatura-img')[0]?.src, |
||||
|
fila.querySelectorAll('img.miniatura-img')[1]?.src, |
||||
|
fila.querySelectorAll('img.miniatura-img')[2]?.src |
||||
|
].filter(Boolean), |
||||
|
callback: function() { |
||||
|
Swal.fire({ |
||||
|
icon: 'success', |
||||
|
title: '¡PDF generado!', |
||||
|
showConfirmButton: false, |
||||
|
timer: 1500 |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
}; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// Generar PDF con la estructura solicitada, sin recuadros y fechas bien alineadas |
||||
|
function generarPDFPersonalizado(data) { |
||||
|
const { jsPDF } = window.jspdf; |
||||
|
const doc = new jsPDF({ orientation: 'portrait', unit: 'pt', format: 'letter' }); |
||||
|
const pageWidth = doc.internal.pageSize.getWidth(); |
||||
|
const pageHeight = doc.internal.pageSize.getHeight(); |
||||
|
|
||||
|
// Título |
||||
|
doc.setFont('helvetica', 'bold'); |
||||
|
doc.setFontSize(30); |
||||
|
doc.text('PRESTAMOS TECMM', pageWidth / 2, 60, { align: 'center' }); |
||||
|
|
||||
|
// REPORTE |
||||
|
doc.setFontSize(13); |
||||
|
doc.setFont('helvetica', 'bold'); |
||||
|
doc.text('REPORTE', 40, 110); |
||||
|
doc.setFont('helvetica', 'normal'); |
||||
|
doc.setFontSize(12); |
||||
|
doc.text(data.motivo || '', 40, 130, { maxWidth: 250 }); |
||||
|
|
||||
|
// FECHA Y HORA (alineado a la derecha, una debajo de otra) |
||||
|
doc.setFont('helvetica', 'bold'); |
||||
|
doc.setFontSize(13); |
||||
|
doc.text('FECHA Y HORA', 320, 110); |
||||
|
doc.setFont('helvetica', 'normal'); |
||||
|
doc.setFontSize(12); |
||||
|
doc.text(`Salida: ${data.fechaSalida || ''}`, 320, 130); |
||||
|
doc.text(`Regreso: ${data.fechaRegreso || ''}`, 320, 150); |
||||
|
|
||||
|
// LAS 3 IMÁGENES |
||||
|
doc.setFont('helvetica', 'bold'); |
||||
|
doc.setFontSize(13); |
||||
|
doc.text('LAS 3 IMÁGENES', 320, 190); |
||||
|
let yImg = 210; |
||||
|
let xImg = 320; |
||||
|
const imagenes = (data.imagenes || []).filter(Boolean); |
||||
|
let cargadas = 0; |
||||
|
if (imagenes.length > 0) { |
||||
|
imagenes.forEach((src, idx) => { |
||||
|
if (src && src.startsWith('blob:')) { |
||||
|
const img = new window.Image(); |
||||
|
img.crossOrigin = ''; |
||||
|
img.onload = function() { |
||||
|
doc.addImage(img, 'PNG', xImg, yImg, 60, 60); |
||||
|
xImg += 70; |
||||
|
cargadas++; |
||||
|
if (cargadas === imagenes.length) { |
||||
|
// Firma |
||||
|
doc.setFont('helvetica', 'normal'); |
||||
|
doc.setFontSize(15); |
||||
|
doc.line(150, 500, 350, 500); |
||||
|
doc.text('FIRMA', pageWidth / 2, 520, { align: 'center' }); |
||||
|
doc.save('reporte_prestamo.pdf'); |
||||
|
if (typeof data.callback === 'function') data.callback(); |
||||
|
} |
||||
|
}; |
||||
|
img.onerror = function() { |
||||
|
cargadas++; |
||||
|
if (cargadas === imagenes.length) { |
||||
|
doc.setFont('helvetica', 'normal'); |
||||
|
doc.setFontSize(15); |
||||
|
doc.line(150, 500, 350, 500); |
||||
|
doc.text('FIRMA', pageWidth / 2, 520, { align: 'center' }); |
||||
|
doc.save('reporte_prestamo.pdf'); |
||||
|
if (typeof data.callback === 'function') data.callback(); |
||||
|
} |
||||
|
}; |
||||
|
img.src = src; |
||||
|
} |
||||
|
}); |
||||
|
} else { |
||||
|
// Firma |
||||
|
doc.setFont('helvetica', 'normal'); |
||||
|
doc.setFontSize(15); |
||||
|
doc.line(150, 500, 350, 500); |
||||
|
doc.text('FIRMA', pageWidth / 2, 520, { align: 'center' }); |
||||
|
doc.save('reporte_prestamo.pdf'); |
||||
|
if (typeof data.callback === 'function') data.callback(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
window.onload = function() { |
||||
|
asignarEventosMiniaturas(); |
||||
|
asignarEventosAcciones(); |
||||
|
}; |
||||
|
</script> |
||||
|
</body> |
||||
|
@endsection |
@ -0,0 +1,28 @@ |
|||||
|
@extends('layouts.app') |
||||
|
|
||||
|
@section('content') |
||||
|
<div class="container"> |
||||
|
<h2>Detalle del Préstamo</h2> |
||||
|
<div class="card mb-4"> |
||||
|
<div class="card-body"> |
||||
|
<ul class="list-group"> |
||||
|
<li class="list-group-item"><strong>Destino:</strong> {{ $prestamo->destino }}</li> |
||||
|
<li class="list-group-item"><strong>Fecha Salida:</strong> {{ $prestamo->fecha_salida }}</li> |
||||
|
<li class="list-group-item"><strong>Fecha Llegada:</strong> {{ $prestamo->fecha_llegada }}</li> |
||||
|
<li class="list-group-item"><strong>Motivo:</strong> {{ $prestamo->motivo }}</li> |
||||
|
<li class="list-group-item"><strong>Domicilio:</strong> {{ $prestamo->domicilio }}</li> |
||||
|
<li class="list-group-item"><strong>Personas:</strong> {{ $prestamo->personas }}</li> |
||||
|
<li class="list-group-item"><strong>Chofer:</strong> {{ $prestamo->chofer }}</li> |
||||
|
<li class="list-group-item"><strong>Estado:</strong> {{ $prestamo->estado }}</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
</div> |
||||
|
<a href="{{ url('/user-dashboard/cuestionario?prestamo_id=' . $prestamo->id) }}" class="btn btn-success"> |
||||
|
Continuar con el cuestionario |
||||
|
</a> |
||||
|
<a href="{{ route('user.prestamos.aceptados') }}" class="btn btn-secondary">Volver a la lista</a> |
||||
|
<a href="{{ route('user.prestamo.pdf', $prestamo->id) }}" class="btn btn-danger" target="_blank"> |
||||
|
<i class="fas fa-file-pdf"></i> Descargar PDF |
||||
|
</a> |
||||
|
</div> |
||||
|
@endsection |
@ -0,0 +1,34 @@ |
|||||
|
@extends('layouts.app') |
||||
|
|
||||
|
@section('title', 'Dashboard - PrestamosTecmm') |
||||
|
@push('head') |
||||
|
<link rel="icon" type="image/x-icon" href="{{ asset('favicon.ico') }}"> |
||||
|
@endpush |
||||
|
|
||||
|
@section('content') |
||||
|
<!-- Enlazamos el CSS personalizado solo para este dashboard --> |
||||
|
<link rel="stylesheet" href="{{ asset('css/user-dashboard.css') }}"> |
||||
|
<!-- Cargamos Font Awesome para el ícono --> |
||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
||||
|
|
||||
|
<body class="user-dashboard-bg"> |
||||
|
<!-- Botón de cerrar sesión --> |
||||
|
<div class="user-dashboard-logout"> |
||||
|
<form method="POST" action="{{ route('logout') }}"> |
||||
|
@csrf |
||||
|
<button type="submit" class="user-dashboard-logout-btn"> |
||||
|
<i class="fas fa-sign-out-alt"></i> Cerrar Sesión |
||||
|
</button> |
||||
|
</form> |
||||
|
</div> |
||||
|
<div class="user-dashboard-header">PrestamosTecmm</div> |
||||
|
<div class="user-dashboard-card"> |
||||
|
<h1 class="user-dashboard-title">Bienvenido a los Préstamos TecMM</h1> |
||||
|
<p class="user-dashboard-desc">Gestiona tus préstamos de manera fácil y rápida</p> |
||||
|
<div style="display: flex; flex-direction: column; align-items: center; gap: 16px; margin-top: 24px;"> |
||||
|
<!-- <a href="{{ url('/user-dashboard/cuestionario') }}" class="user-dashboard-btn" style="width: 220px;">Ir a la siguiente sección</a> --> |
||||
|
<a href="{{ route('user.prestamos.aceptados') }}" class="user-dashboard-btn" style="width: 220px;">Ver Préstamos Aceptados</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
</body> |
||||
|
@endsection |
@ -0,0 +1,171 @@ |
|||||
|
@extends('layouts.app') |
||||
|
|
||||
|
@section('content') |
||||
|
<link rel="stylesheet" href="{{ asset('css/user-dashboard.css') }}"> |
||||
|
<style> |
||||
|
body.user-dashboard-bg { |
||||
|
background: linear-gradient(120deg, #4158D0 0%, #5068c8 46%, #70e7ff 100%) !important; |
||||
|
min-height: 100vh; |
||||
|
} |
||||
|
.prestamos-card { |
||||
|
border-radius: 24px; |
||||
|
box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.15); |
||||
|
background: #fff; |
||||
|
margin: 40px auto; |
||||
|
max-width: 1100px; |
||||
|
} |
||||
|
.prestamos-header { |
||||
|
border-radius: 24px 24px 0 0; |
||||
|
background: #4158D0; |
||||
|
color: #fff; |
||||
|
padding: 24px 32px; |
||||
|
font-size: 2rem; |
||||
|
font-weight: 800; |
||||
|
letter-spacing: 1px; |
||||
|
text-align: left; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
} |
||||
|
.prestamos-header .logo { |
||||
|
font-size: 2rem; |
||||
|
font-weight: 900; |
||||
|
letter-spacing: 2px; |
||||
|
color: #fff; |
||||
|
} |
||||
|
.prestamos-header .logout-btn { |
||||
|
background: #e53e3e; |
||||
|
color: #fff; |
||||
|
border: none; |
||||
|
border-radius: 8px; |
||||
|
padding: 10px 22px; |
||||
|
font-size: 1rem; |
||||
|
font-weight: 600; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
gap: 8px; |
||||
|
box-shadow: 0 2px 8px rgba(229,62,62,0.15); |
||||
|
transition: background 0.2s; |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
.prestamos-header .logout-btn:hover { |
||||
|
background: #c53030; |
||||
|
color: #fff; |
||||
|
} |
||||
|
.prestamos-table th, .prestamos-table td { |
||||
|
vertical-align: middle; |
||||
|
text-align: center; |
||||
|
} |
||||
|
.prestamos-table th { |
||||
|
background: #f7fafc; |
||||
|
font-weight: bold; |
||||
|
} |
||||
|
.prestamos-table { |
||||
|
border-radius: 16px; |
||||
|
overflow: hidden; |
||||
|
background: #fff; |
||||
|
} |
||||
|
.prestamos-table td, .prestamos-table th { |
||||
|
font-size: 1rem; |
||||
|
} |
||||
|
.prestamos-table .badge { |
||||
|
font-size: 1rem; |
||||
|
padding: 6px 14px; |
||||
|
border-radius: 8px; |
||||
|
} |
||||
|
.prestamos-title { |
||||
|
font-size: 2.2rem; |
||||
|
font-weight: 900; |
||||
|
color: #4158D0; |
||||
|
margin-bottom: 24px; |
||||
|
text-align: center; |
||||
|
letter-spacing: 1px; |
||||
|
} |
||||
|
.btn-action { |
||||
|
border: none; |
||||
|
border-radius: 6px; |
||||
|
padding: 6px 14px; |
||||
|
font-size: 1rem; |
||||
|
font-weight: 600; |
||||
|
margin: 2px; |
||||
|
transition: background 0.2s; |
||||
|
cursor: pointer; |
||||
|
display: inline-flex; |
||||
|
align-items: center; |
||||
|
gap: 6px; |
||||
|
} |
||||
|
.btn-action.details { |
||||
|
background: #3182ce; |
||||
|
color: #fff; |
||||
|
} |
||||
|
.btn-action.details:hover { |
||||
|
background: #225ea8; |
||||
|
} |
||||
|
.btn-action.select { |
||||
|
background: #38a169; |
||||
|
color: #fff; |
||||
|
} |
||||
|
.btn-action.select:hover { |
||||
|
background: #276749; |
||||
|
} |
||||
|
</style> |
||||
|
<body class="user-dashboard-bg"> |
||||
|
<div class="container py-4"> |
||||
|
<div class="prestamos-card"> |
||||
|
<div class="prestamos-header"> |
||||
|
<span class="logo">PréstamosTecmm</span> |
||||
|
<form method="POST" action="{{ route('logout') }}" style="margin:0;"> |
||||
|
@csrf |
||||
|
<button type="submit" class="logout-btn"> |
||||
|
<i class="fas fa-sign-out-alt"></i> Cerrar Sesión |
||||
|
</button> |
||||
|
</form> |
||||
|
</div> |
||||
|
<div class="card-body" style="background: #fff; border-radius: 0 0 24px 24px;"> |
||||
|
<div class="prestamos-title">Préstamos Aceptados</div> |
||||
|
@if($prestamos->isEmpty()) |
||||
|
<div class="alert alert-info text-center mb-0">No tienes préstamos aceptados.</div> |
||||
|
@else |
||||
|
<div class="table-responsive"> |
||||
|
<table class="table table-hover align-middle prestamos-table"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
<th>Destino</th> |
||||
|
<th>Fecha Salida</th> |
||||
|
<th>Fecha Llegada</th> |
||||
|
<th>Motivo</th> |
||||
|
<th>Personas</th> |
||||
|
<th>Chofer</th> |
||||
|
<th>Estado</th> |
||||
|
<th>Acciones</th> |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
@foreach($prestamos as $prestamo) |
||||
|
<tr> |
||||
|
<td>{{ $prestamo->destino }}</td> |
||||
|
<td>{{ $prestamo->fecha_hora_salida }}</td> |
||||
|
<td>{{ $prestamo->fecha_hora_llegada }}</td> |
||||
|
<td>{{ $prestamo->motivo }}</td> |
||||
|
<td>{{ $prestamo->numero_personas }}</td> |
||||
|
<td>{{ $prestamo->choferAsignado ? $prestamo->choferAsignado->nombre : 'Sin chofer' }}</td> |
||||
|
<td> |
||||
|
<span class="badge bg-success">{{ ucfirst($prestamo->estado) }}</span> |
||||
|
</td> |
||||
|
<td> |
||||
|
|
||||
|
<a href="{{ url('/user-dashboard/cuestionario?prestamo_id=' . $prestamo->id) }}" class="btn-action select"> |
||||
|
<i class="fas fa-check"></i> Seleccionar Préstamo |
||||
|
</a> |
||||
|
</td> |
||||
|
</tr> |
||||
|
@endforeach |
||||
|
</tbody> |
||||
|
</table> |
||||
|
</div> |
||||
|
@endif |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</body> |
||||
|
@endsection |
Loading…
Reference in new issue