Damian 2 months ago
parent
commit
2205dfe871
  1. 24
      app/Exports/ChoferesExport.php
  2. 38
      app/Exports/UsuariosExport.php
  3. 44
      app/Exports/puestosExport.php
  4. 13
      app/Http/Controllers/AdminController.php
  5. 11
      app/Http/Controllers/Auth/LoginController.php
  6. 97
      app/Http/Controllers/ChoferController.php
  7. 129
      app/Http/Controllers/DespartamentoController.php
  8. 30
      app/Http/Controllers/HomeController.php
  9. 77
      app/Http/Controllers/PrestamoController.php
  10. 128
      app/Http/Controllers/PuestoController.php
  11. 49
      app/Http/Controllers/SolicitudVehiculoController.php
  12. 65
      app/Http/Controllers/TipoController.php
  13. 23
      app/Http/Controllers/TiposLicenciasController.php
  14. 54
      app/Http/Controllers/UserDashboardController.php
  15. 116
      app/Http/Controllers/usuariosController.php
  16. 9
      app/Http/Kernel.php
  17. 15
      app/Http/Middleware/AdminMiddleware.php
  18. 23
      app/Http/Middleware/AdminOrServiciosRole.php
  19. 20
      app/Http/Middleware/CheckAdminRole.php
  20. 19
      app/Http/Middleware/CheckProfesorRole.php
  21. 19
      app/Http/Middleware/CheckServiciosRole.php
  22. 18
      app/Models/Chofer.php
  23. 26
      app/Models/SolicitudVehiculo.php
  24. 7
      app/Models/User.php
  25. 14
      app/Models/prestamo.php
  26. 1
      app/Models/puesto.php
  27. 13
      app/Models/tipo.php
  28. 10
      app/Providers/AuthServiceProvider.php
  29. 23
      database/factories/TipoFactory.php
  30. 34
      database/migrations/2013_02_20_022824_create_tipos_table.php
  31. 66
      database/migrations/2014_10_12_000000_create_users_table.php
  32. 31
      database/migrations/2024_03_19_create_user_dashboard_user.php
  33. 28
      database/migrations/2024_03_27_000000_create_solicitud_vehiculos_table.php
  34. 1
      database/migrations/2025_03_27_174121_create_prestamos_table.php
  35. 12
      database/migrations/2025_04_01_191325_add_estado_to_prestamos_table.php
  36. 4
      database/migrations/2025_04_01_192918_add_fecha_aceptacion_to_prestamos_table.php
  37. 29
      database/migrations/2025_05_22_205902_create_chofers_table.php
  38. 25
      database/migrations/2025_05_22_212123_add_chofer_id_to_prestamos_table.php
  39. 5
      database/seeders/DatabaseSeeder.php
  40. 22
      database/seeders/ProfesorSeeder.php
  41. 26
      database/seeders/ServiciosSeeder.php
  42. 0
      hollla.txt
  43. 85
      public/css/user-dashboard.css
  44. 20
      resources/views/auth/login.blade.php
  45. 95
      resources/views/choferes.blade.php
  46. 62
      resources/views/choferesCrearEditar.blade.php
  47. 86
      resources/views/dashboard.blade.php
  48. 55
      resources/views/exports/choferes-pdf.blade.php
  49. 66
      resources/views/exports/prestamo-individual-pdf.blade.php
  50. 79
      resources/views/exports/prestamos-reporte-pdf.blade.php
  51. 53
      resources/views/exports/puestos.blade.php
  52. 31
      resources/views/exports/usuarios-pdf.blade.php
  53. 5
      resources/views/layouts/app.blade.php
  54. 64
      resources/views/layouts/dashboard.blade.php
  55. 7
      resources/views/prestamos.blade.php
  56. 47
      resources/views/prestamos/pendientes.blade.php
  57. 91
      resources/views/prestamos/rechazados.blade.php
  58. 23
      resources/views/prestamos/show.blade.php
  59. 50
      resources/views/prestamosCrearEditar.blade.php
  60. 78
      resources/views/profesor/solicitudes/create.blade.php
  61. 51
      resources/views/profesor/solicitudes/index.blade.php
  62. 142
      resources/views/puestos.blade.php
  63. 51
      resources/views/puestosCrearEditar.blade.php
  64. 152
      resources/views/tiposLicencia.blade.php
  65. 402
      resources/views/user-dashboard/cuestionario.blade.php
  66. 28
      resources/views/user-dashboard/detalle-prestamo.blade.php
  67. 34
      resources/views/user-dashboard/index.blade.php
  68. 171
      resources/views/user-dashboard/prestamos-aceptados.blade.php
  69. 22
      resources/views/usuarios.blade.php
  70. 29
      resources/views/usuariosCrearEditar.blade.php
  71. 57
      routes/web.php

24
app/Exports/ChoferesExport.php

@ -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',
];
}
}

38
app/Exports/UsuariosExport.php

@ -10,23 +10,37 @@ class UsuariosExport implements FromCollection, WithHeadings
{
public function collection()
{
return User::select( 'name', 'email','apellido',
'puesto',
'carrera',
'telefono',)->get();
$usuarios = User::with(['puesto', 'tipo', 'departamento'])->get();
$data = [];
$contador = 1;
foreach ($usuarios as $usuario) {
$data[] = [
'No.' => $contador++,
'Nombre' => $usuario->name,
'Correo' => $usuario->email,
'Apellido' => $usuario->apellido,
'Puesto' => $usuario->puesto->nombre ?? '',
'Tipo' => $usuario->tipo->nombre ?? '',
'Departamento' => $usuario->departamento->departamento ?? '',
'Teléfono' => $usuario->telefono,
];
}
return collect($data);
}
public function headings(): array
{
return [
'nombre',
'correo',
'apellido',
'puesto',
'carrera',
'telefono',
'Fecha de Creación',
'Última Actualización'
'No.',
'Nombre',
'Correo',
'Apellido',
'Puesto',
'Tipo',
'Departamento',
'Teléfono',
];
}
}

44
app/Exports/puestosExport.php

@ -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',
];
}
}

13
app/Http/Controllers/AdminController.php

@ -0,0 +1,13 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class AdminController extends Controller
{
public function dashboard()
{
return view('admin.dashboard');
}
}

11
app/Http/Controllers/Auth/LoginController.php

@ -39,11 +39,14 @@ class LoginController extends Controller
$this->middleware('auth')->only('logout');
}
protected function authenticated(Request $request, $user)
protected function authenticated($request, $user)
{
if ($user->rol === 'mantenimiento') {
return redirect('/maintenance');
}
if ($user->tipos_id == 1) {
return redirect('/dashboard');
} elseif ($user->tipos_id == 2) {
return redirect('/user-dashboard');
} else {
return redirect('/home');
}
}
}

97
app/Http/Controllers/ChoferController.php

@ -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');
}
}

129
app/Http/Controllers/DespartamentoController.php

@ -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');
}
}

30
app/Http/Controllers/HomeController.php

@ -23,8 +23,36 @@ class HomeController extends Controller
*/
public function index()
{
$user = auth()->user();
return view('dashboard');
// Validar que el usuario tenga tipo asignado y que sea Administrador o Servicios Generales
if (!$user->tipo || !in_array($user->tipos_id, [1, 4])) {
// Cerrar la sesión del usuario
auth()->logout();
// Redirigir con mensaje de error
return redirect()->route('login')->with('error', 'No tienes permisos para acceder al sistema. Solo los administradores o servicios pueden acceder en este momento.');
}
// Notificaciones si el usuario no tiene puesto o departamento asignado
$notificaciones = [];
if (is_null($user->puesto_id)) {
$notificaciones[] = 'No tienes un puesto asignado. Contacta al administrador para que te asigne uno.';
}
if (is_null($user->departamento_id)) {
$notificaciones[] = 'No tienes un departamento asignado. Contacta al administrador para que te asigne uno.';
}
// Si es administrador, mostrar el dashboard con datos reales
$adminData = [
'totalUsers' => \App\Models\User::where('eliminado', 0)->count(),
'totalPrestamos' => \App\Models\Prestamo::count(),
'prestamosPendientes' => \App\Models\Prestamo::where('estado', 'pendiente')->count(),
'prestamosAceptados' => \App\Models\Prestamo::where('estado', 'aceptado')->count(),
];
return view('dashboard', [
'adminData' => $adminData,
'notificaciones' => $notificaciones
]);
}
}

77
app/Http/Controllers/PrestamoController.php

@ -43,7 +43,13 @@ class PrestamoController extends Controller
*/
public function create()
{
return view('prestamosCrearEditar', ['prestamo' => null]); // No se necesita pasar préstamos
$vehiculos = \App\Models\tiposVeiculos::where('status', true)->get();
$choferes = \App\Models\Chofer::all();
return view('prestamosCrearEditar', [
'prestamo' => null,
'vehiculos' => $vehiculos,
'choferes' => $choferes
]);
}
/**
@ -54,28 +60,28 @@ class PrestamoController extends Controller
// Validación de datos
$request->validate([
'nombre_solicitante' => 'required|string|max:255',
'chofer_id' => 'required|exists:choferes,id',
'destino' => 'required|string|max:255',
'fecha_hora_salida' => 'required|date',
'fecha_hora_llegada' => 'required|date',
'motivo' => 'required|string|max:255',
'domicilio' => 'required|string|max:255',
'numero_personas' => 'required|integer',
'vehiculo_id' => 'required|exists:tipos_veiculos,id'
]);
// Crea un nuevo préstamo
$prestamo = new Prestamo();
$prestamo->nombre_solicitante = $request->nombre_solicitante;
$prestamo->destino = $request->destino;
$prestamo->fecha_hora_salida = $request->fecha_hora_salida;
$prestamo->fecha_hora_llegada = $request->fecha_hora_llegada;
$prestamo->motivo = $request->motivo;
$prestamo->domicilio = $request->domicilio;
$prestamo->numero_personas = $request->numero_personas;
$prestamo->chofer = $request->has('chofer') ? 1 : 0; // Manejo del checkbox
$prestamo->eliminado = 0; // Marca como activo por defecto
// Preparar los datos
$datos = $request->all();
$datos['chofer'] = $request->has('chofer') ? 1 : 0;
// Sobrescribir el nombre del solicitante con el nombre del usuario autenticado
$datos['nombre_solicitante'] = auth()->user()->name;
$prestamo = new Prestamo($datos);
$prestamo->estado = 'pendiente';
$prestamo->save();
return redirect()->route('prestamos.index')->with('success', 'Préstamo creado exitosamente.');
return redirect()->route('prestamos.index')
->with('success', 'Préstamo solicitado correctamente. Esperando aprobación.');
}
/**
@ -84,7 +90,13 @@ class PrestamoController extends Controller
public function edit($id)
{
$prestamo = Prestamo::findOrFail($id); // Busca el préstamo por ID
return view('prestamosCrearEditar', ['prestamo' => $prestamo]); // Pasa el préstamo a la vista
$vehiculos = \App\Models\tiposVeiculos::where('status', true)->get();
$choferes = \App\Models\Chofer::all();
return view('prestamosCrearEditar', [
'prestamo' => $prestamo,
'vehiculos' => $vehiculos,
'choferes' => $choferes
]); // Pasa el préstamo a la vista
}
/**
@ -143,9 +155,9 @@ class PrestamoController extends Controller
*/
public function exportPDF()
{
$prestamos = Prestamo::where('eliminado', 0)->get();
$pdf = PDF::loadView('exports.prestamos-pdf', ['prestamos' => $prestamos]);
return $pdf->download('prestamos.pdf');
$prestamos = \App\Models\Prestamo::with(['vehiculo', 'choferAsignado'])->get();
$pdf = \PDF::loadView('exports.prestamos-reporte-pdf', ['prestamos' => $prestamos]);
return $pdf->download('reporte_general_prestamos.pdf');
}
public function aceptados(Request $request)
@ -190,4 +202,35 @@ class PrestamoController extends Controller
return redirect()->route('prestamos.index')
->with('success', 'Préstamo rechazado exitosamente.');
}
public function show($id)
{
$prestamo = \App\Models\Prestamo::findOrFail($id);
return view('prestamos.show', compact('prestamo'));
}
public function pendientes()
{
$prestamos = \App\Models\Prestamo::where('estado', 'pendiente')->where('eliminado', 0)->get();
return view('prestamos.pendientes', compact('prestamos'));
}
public function rechazados(Request $request)
{
$busqueda = $request->busqueda;
$prestamos = \App\Models\Prestamo::where('estado', 'rechazado')
->where('eliminado', 0)
->when($busqueda, function($query) use ($busqueda) {
$query->where(function($q) use ($busqueda) {
$q->where('nombre_solicitante', 'LIKE', "%{$busqueda}%")
->orWhere('destino', 'LIKE', "%{$busqueda}%")
->orWhere('motivo', 'LIKE', "%{$busqueda}%");
});
})
->orderBy('created_at', 'desc')
->get();
return view('prestamos.rechazados', compact('prestamos'));
}
}

128
app/Http/Controllers/PuestoController.php

@ -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');
}
}

49
app/Http/Controllers/SolicitudVehiculoController.php

@ -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');
}
}

65
app/Http/Controllers/TipoController.php

@ -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)
{
//
}
}

23
app/Http/Controllers/TiposLicenciasController.php

@ -59,17 +59,6 @@ class TiposLicenciasController extends Controller
*/
public function store(Request $request)
{
// Verificar si ya existe un tipo de licencia con el mismo nombre
$existe = tiposLicencias::where('tipoLicencia', $request->tipoLicencia)
->where('eliminado', 1)
->exists();
if ($existe) {
return redirect()->route('tiposLicencias.create')
->with('error', 'Ya existe un tipo de licencia con el nombre "' . $request->tipoLicencia . '". Por favor, ingrese un nombre diferente.')
->withInput();
}
$tipoLicencia = new TiposLicencias();
$tipoLicencia->tipoLicencia = $request->tipoLicencia;
$tipoLicencia->eliminado = 1;
@ -92,18 +81,6 @@ class TiposLicenciasController extends Controller
*/
public function update(Request $request, $id)
{
// Verificar si ya existe otro tipo de licencia con el mismo nombre
$existe = tiposLicencias::where('tipoLicencia', $request->tipoLicencia)
->where('id', '!=', $id)
->where('eliminado', 1)
->exists();
if ($existe) {
return redirect()->route('tiposLicencias.edit', $id)
->with('error', 'Ya existe un tipo de licencia con el nombre "' . $request->tipoLicencia . '". Por favor, ingrese un nombre diferente.')
->withInput();
}
$tipoLicencia = TiposLicencias::findOrFail($id);
$tipoLicencia->tipoLicencia = $request->tipoLicencia;
if ($request->has('eliminado')) {

54
app/Http/Controllers/UserDashboardController.php

@ -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');
}
}

116
app/Http/Controllers/usuariosController.php

@ -8,6 +8,8 @@ use App\Exports\UsuariosExport;
use Maatwebsite\Excel\Facades\Excel;
use PDF; // Asegúrate de incluir la clase PDF
use App\Models\Puesto;
use App\Models\Despartamento;
use App\Models\Tipo;
class usuariosController extends Controller
{
@ -39,8 +41,10 @@ class usuariosController extends Controller
*/
public function create()
{
$tipos = Tipo::all();
$despartamentos = Despartamento::all();
$puestos = Puesto::all();
return view('usuariosCrearEditar', ['usuario' => null, 'puestos' => $puestos]);
return view('usuariosCrearEditar', ['usuario' => null, 'puestos' => $puestos, 'despartamentos'=> $despartamentos, 'tipos' => $tipos]);
}
@ -49,26 +53,66 @@ class usuariosController extends Controller
*/
public function store(Request $request)
{
// Validación de datos
// Validación de datos en español
$request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'apellido' => 'required|string|max:255',
'puesto_id' => 'required|exists:puestos,id',
'carrera' => 'required|string|max:255',
'telefono' => 'required|string|max:255',
'password' => 'required|string|min:8|confirmed',
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
'apellido' => ['required', 'string', 'max:255'],
'tipos_id' => ['required', 'exists:tipos,id'],
'puesto_id' => ['required', 'exists:puestos,id'],
'departamento_id' => ['required', 'exists:despartamentos,id'],
'telefono' => ['required', 'string', 'max:255'],
'password' => ['required', 'string', 'min:8', 'confirmed'],
], [
'name.required' => 'El campo nombre es obligatorio.',
'name.string' => 'El campo nombre debe ser una cadena de texto.',
'name.max' => 'El campo nombre no debe exceder 255 caracteres.',
'email.required' => 'El campo correo electrónico es obligatorio.',
'email.string' => 'El campo correo electrónico debe ser una cadena de texto.',
'email.email' => 'El campo correo electrónico debe ser una dirección de correo válida.',
'email.max' => 'El campo correo electrónico no debe exceder 255 caracteres.',
'email.unique' => 'El correo electrónico ya está registrado.',
'apellido.required' => 'El campo apellido es obligatorio.',
'apellido.string' => 'El campo apellido debe ser una cadena de texto.',
'apellido.max' => 'El campo apellido no debe exceder 255 caracteres.',
'tipos_id.required' => 'El campo tipo es obligatorio.',
'tipos_id.exists' => 'El tipo seleccionado no es válido.',
'puesto_id.required' => 'El campo puesto es obligatorio.',
'puesto_id.exists' => 'El puesto seleccionado no es válido.',
'departamento_id.required' => 'El campo departamento es obligatorio.',
'departamento_id.exists' => 'El departamento seleccionado no es válido.',
'telefono.required' => 'El campo teléfono es obligatorio.',
'telefono.string' => 'El campo teléfono debe ser una cadena de texto.',
'telefono.max' => 'El campo teléfono no debe exceder 255 caracteres.',
'password.required' => 'El campo contraseña es obligatorio.',
'password.string' => 'El campo contraseña debe ser una cadena de texto.',
'password.min' => 'La contraseña debe tener al menos 8 caracteres.',
'password.confirmed' => 'Las contraseñas no coinciden.',
]);
// Validación extra: si el usuario autenticado es de servicios generales, solo puede crear usuarios de tipo Usuario
if (auth()->user()->tipos_id == 4 && $request->tipos_id != 2) {
return redirect()->back()->withInput()->withErrors(['tipos_id' => 'Solo puedes crear usuarios de tipo Usuario.']);
}
// Si la validación pasa, crea el usuario
$usuario = new User();
$usuario->name = $request->name;
$usuario->email = $request->email;
$usuario->apellido = $request->apellido;
$usuario->tipos_id = $request->tipos_id;
$usuario->puesto_id = $request->puesto_id;
$usuario->carrera = $request->carrera;
$usuario->telefono = $request->telefono;
$usuario->password = bcrypt($request->password);
// Ya no asignamos rol, solo usamos tipos_id
$usuario->save();
return redirect()->route('usuarios')->with('success', 'Usuario creado exitosamente.');
@ -90,7 +134,9 @@ class usuariosController extends Controller
{
$user = User::findOrFail($id);
$puestos = Puesto::all();
return view('usuariosCrearEditar',['usuario' => $user, 'puestos' => $puestos]); // Asegúrate de que la clave sea 'usuario'
$despartamentos = Despartamento::all();
$tipos = Tipo::all();
return view('usuariosCrearEditar',['usuario' => $user, 'puestos' => $puestos,'despartamentos'=> $despartamentos, 'tipos' => $tipos]); // Asegúrate de que la clave sea 'usuario'
}
// ... existing code ...
@ -100,15 +146,48 @@ class usuariosController extends Controller
*/
public function update(Request $request, $id)
{
// Validación de datos
// Validación de datos (reglas y mensajes personalizados en español)
$request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255',
'apellido' => 'required|string|max:255',
//'puesto_id' => 'required|exists:puesto_id',
'carrera' => 'required|string|max:255',
'telefono' => 'required|string|max:255',
'password' => 'nullable|string|min:8|confirmed',
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'string', 'email', 'max:255', 'unique:users,email,'.$id],
'apellido' => ['required', 'string', 'max:255'],
'tipos_id' => ['required', 'exists:tipos,id'],
'puesto_id' => ['required', 'exists:puestos,id'],
'departamento_id' => ['required', 'exists:despartamentos,id'],
'telefono' => ['required', 'string', 'max:255'],
'password' => ['nullable', 'string', 'min:8', 'confirmed'],
], [
'name.required' => 'El campo nombre es obligatorio.',
'name.string' => 'El campo nombre debe ser una cadena de texto.',
'name.max' => 'El campo nombre no debe exceder 255 caracteres.',
'email.required' => 'El campo correo electrónico es obligatorio.',
'email.string' => 'El campo correo electrónico debe ser una cadena de texto.',
'email.email' => 'El campo correo electrónico debe ser una dirección válida.',
'email.max' => 'El campo correo electrónico no debe exceder 255 caracteres.',
'email.unique' => 'El correo electrónico ya está registrado.',
'apellido.required' => 'El campo apellido es obligatorio.',
'apellido.string' => 'El campo apellido debe ser una cadena de texto.',
'apellido.max' => 'El campo apellido no debe exceder 255 caracteres.',
'tipos_id.required' => 'El campo tipo es obligatorio.',
'tipos_id.exists' => 'El tipo seleccionado no es válido.',
'puesto_id.required' => 'El campo puesto es obligatorio.',
'puesto_id.exists' => 'El puesto seleccionado no es válido.',
'departamento_id.required' => 'El campo departamento es obligatorio.',
'departamento_id.exists' => 'El departamento seleccionado no es válido.',
'telefono.required' => 'El campo teléfono es obligatorio.',
'telefono.string' => 'El campo teléfono debe ser una cadena de texto.',
'telefono.max' => 'El campo teléfono no debe exceder 255 caracteres.',
'password.required' => 'El campo contraseña es obligatorio.',
'password.string' => 'El campo contraseña debe ser una cadena de texto.',
'password.min' => 'La contraseña debe tener al menos 8 caracteres.',
'password.confirmed' => 'Las contraseñas no coinciden.',
]);
// Actualizar usuario
@ -116,6 +195,7 @@ class usuariosController extends Controller
$usuario->name = $request->name;
$usuario->email = $request->email;
$usuario->apellido = $request->apellido;
$usuario->tipos_id = $request->tipos_id;
$usuario->puesto_id = $request->puesto_id;
$usuario->carrera = $request->carrera;
$usuario->telefono = $request->telefono;

9
app/Http/Kernel.php

@ -60,9 +60,18 @@ class Kernel extends HttpKernel
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'precognitive' => \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
'signed' => \App\Http\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'profesor' => \App\Http\Middleware\CheckProfesorRole::class,
'admin' => \App\Http\Middleware\CheckAdminRole::class,
'servicios' => \App\Http\Middleware\CheckServiciosRole::class,
'adminOrServicios' => \App\Http\Middleware\AdminOrServiciosRole::class,
];
protected $routeMiddleware = [
// ... otros middlewares
'admin' => \App\Http\Middleware\AdminMiddleware::class,
];
}

15
app/Http/Middleware/AdminMiddleware.php

@ -4,16 +4,21 @@ namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;
class AdminMiddleware
{
public function handle(Request $request, Closure $next)
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if (Auth::check() && Auth::user()->email === 'monse@admin.com') {
return $next($request);
if (!auth()->check() || auth()->user()->tipos_id != 1) {
return redirect('/')->with('error', 'No tienes permisos para acceder a esta página.');
}
return redirect('/')->with('error', 'Acceso denegado. Solo los administradores pueden acceder a esta página.');
return $next($request);
}
}

23
app/Http/Middleware/AdminOrServiciosRole.php

@ -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);
}
}

20
app/Http/Middleware/CheckAdminRole.php

@ -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);
}
}

19
app/Http/Middleware/CheckProfesorRole.php

@ -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);
}
}

19
app/Http/Middleware/CheckServiciosRole.php

@ -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);
}
}

18
app/Models/Chofer.php

@ -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',
];
}

26
app/Models/SolicitudVehiculo.php

@ -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);
}
}

7
app/Models/User.php

@ -22,6 +22,7 @@ class User extends Authenticatable
'name',
'email',
'apellido',
'tipos_id',
'puesto_id',
'carrera',
'telefono',
@ -48,7 +49,7 @@ class User extends Authenticatable
'email_verified_at' => 'datetime',
];
public function puesto():HasOne{
return $this->hasOne(Puesto::class, 'id','puesto_id');
}
public function puesto() { return $this->belongsTo(\App\Models\Puesto::class, 'puesto_id'); }
public function tipo() { return $this->belongsTo(\App\Models\Tipo::class, 'tipos_id'); }
public function departamento() { return $this->belongsTo(\App\Models\Despartamento::class, 'departamento_id'); }
}

14
app/Models/prestamo.php

@ -19,6 +19,18 @@ protected $fillable = [
'domicilio',
'numero_personas',
'chofer',
'estado',
'eliminado',
'vehiculo_id'
];
public function vehiculo()
{
return $this->belongsTo(\App\Models\tiposVeiculos::class, 'vehiculo_id');
}
public function choferAsignado()
{
return $this->belongsTo(\App\Models\Chofer::class, 'chofer');
}
}

1
app/Models/puesto.php

@ -8,4 +8,5 @@ use Illuminate\Database\Eloquent\Model;
class puesto extends Model
{
use HasFactory;
protected $fillable = ['nombre', 'eliminado'];
}

13
app/Models/tipo.php

@ -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'];
}

10
app/Providers/AuthServiceProvider.php

@ -4,6 +4,7 @@ namespace App\Providers;
// use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
class AuthServiceProvider extends ServiceProvider
{
@ -20,9 +21,12 @@ class AuthServiceProvider extends ServiceProvider
* Register any authentication / authorization services.
*/
public function boot(): void
{
{
$this->registerPolicies();
//
}
Gate::define('gestionar-prestamos', function ($user) {
// Permitir solo a tipos_id 1 (Administrador) y 4 (Servicios Generales), agrega más si lo deseas
return in_array($user->tipos_id, [1, 4]);
});
}
}

23
database/factories/TipoFactory.php

@ -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 [
//
];
}
}

34
database/migrations/2013_02_20_022824_create_tipos_table.php

@ -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');
}
};

66
database/migrations/2014_10_12_000000_create_users_table.php

@ -3,6 +3,7 @@
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
@ -18,18 +19,73 @@ return new class extends Migration
$table->timestamp('email_verified_at')->nullable();
$table->string('apellido')->nullable();
$table->unsignedBigInteger('puesto_id')->nullable();
$table->string('carrera')->nullable();
$table->unsignedBigInteger('departamento_id')->nullable();
$table->unsignedBigInteger('tipos_id')->nullable();
$table->string('telefono')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
$table->foreign('puesto_id')->references('id')->on('puestos');
$table->foreign('departamento_id')->references('id')->on('despartamentos');
$table->foreign('tipos_id')->references('id')->on('tipos');
});
DB::table('users')->insert([
'name'=> 'monse',
'email'=> 'monse@admin.com',
'password'=> bcrypt('tecmm2025')
[
'name' => 'usuario',
'email' => 'usuario@usuario.com',
'apellido' => 'usuario',
'puesto_id' => 2,
'departamento_id' => 2,
'tipos_id' => 2,
'telefono' => '33652147821',
'password' => bcrypt('12345678'),
'email_verified_at' => '2025-05-23 18:33:05',
'remember_token' => null,
'created_at' => now(),
'updated_at' => now(),
],
[
'name' => 'monse',
'email' => 'monse@monse.com',
'apellido' => 'martinez',
'puesto_id' => 1,
'departamento_id' => 3,
'tipos_id' => 1,
'telefono' => null,
'password' => bcrypt('12345678'),
'email_verified_at' => '2025-05-23 18:33:05',
'remember_token' => null,
'created_at' => now(),
'updated_at' => now(),
],
[
'name' => 'usuario_tipo3',
'email' => 'tipo3@ejemplo.com',
'apellido' => 'apellido3',
'puesto_id' => 1,
'departamento_id' => 1,
'tipos_id' => 3,
'telefono' => '3333333333',
'password' => bcrypt('12345678'),
'email_verified_at' => '2025-05-23 18:33:05',
'remember_token' => null,
'created_at' => now(),
'updated_at' => now(),
],
[
'name' => 'jorge',
'email' => 'jorge@jorge.com',
'apellido' => 'jorge',
'puesto_id' => 1,
'departamento_id' => 1,
'tipos_id' => 4,
'telefono' => '4444444444',
'password' => bcrypt('servicios123'),
'email_verified_at' => '2025-05-23 18:33:05',
'remember_token' => null,
'created_at' => now(),
'updated_at' => now(),
],
]);
}

31
database/migrations/2024_03_19_create_user_dashboard_user.php

@ -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();
}
};

28
database/migrations/2024_03_27_000000_create_solicitud_vehiculos_table.php

@ -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');
}
};

1
database/migrations/2025_03_27_174121_create_prestamos_table.php

@ -21,6 +21,7 @@ return new class extends Migration
$table->string('domicilio');
$table->integer('numero_personas');
$table->boolean('chofer')->default(false); // Opción de sí (true) o no (false)
$table->foreignId('vehiculo_id')->constrained('tipos_veiculos')->onDelete('cascade');
$table->timestamps();
});
}

12
database/migrations/2025_03_28_182126_add_estado_to_prestamos_table.php → database/migrations/2025_04_01_191325_add_estado_to_prestamos_table.php

@ -9,20 +9,22 @@ return new class extends Migration
/**
* Run the migrations.
*/
public function up(): void
public function up()
{
Schema::table('prestamos', function (Blueprint $table) {
//
$table->string('estado')->default('pendiente');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
public function down()
{
Schema::table('prestamos', function (Blueprint $table) {
//
if (Schema::hasColumn('prestamos', 'estado')) {
$table->dropColumn('estado');
}
});
}
};

4
database/migrations/2025_03_28_175646_add_estado_to_prestamos_table.php → database/migrations/2025_04_01_192918_add_fecha_aceptacion_to_prestamos_table.php

@ -12,7 +12,7 @@ return new class extends Migration
public function up(): void
{
Schema::table('prestamos', function (Blueprint $table) {
//
$table->timestamp('fecha_aceptacion')->nullable();
});
}
@ -22,7 +22,7 @@ return new class extends Migration
public function down(): void
{
Schema::table('prestamos', function (Blueprint $table) {
//
$table->dropColumn('fecha_aceptacion');
});
}
};

29
database/migrations/2025_05_22_205902_create_chofers_table.php

@ -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');
}
};

25
database/migrations/2025_05_22_212123_add_chofer_id_to_prestamos_table.php

@ -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');
});
}
};

5
database/seeders/DatabaseSeeder.php

@ -18,5 +18,10 @@ class DatabaseSeeder extends Seeder
// 'name' => 'Test User',
// 'email' => 'test@example.com',
// ]);
$this->call([
ProfesorSeeder::class,
ServiciosSeeder::class,
]);
}
}

22
database/seeders/ProfesorSeeder.php

@ -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',
]);
}
}

26
database/seeders/ServiciosSeeder.php

@ -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
-i → hollla.txt

85
public/css/user-dashboard.css

@ -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;
}

20
resources/views/auth/login.blade.php

@ -29,6 +29,14 @@
</div>
@endif
@if(session('error'))
<div class="mb-4 bg-red-50 border-l-4 border-red-500 p-4">
<div class="text-red-700">
{{ session('error') }}
</div>
</div>
@endif
<form method="POST" action="{{ route('login') }}" class="space-y-6">
@csrf
@ -44,6 +52,12 @@
class="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500"
value="{{ old('email') }}"
placeholder="tu@email.com">
@error('email')
<span class="text-red-500 text-sm">
{{ $message }}
</span>
@enderror
</div>
</div>
@ -58,6 +72,12 @@
<input id="password" name="password" type="password" required
class="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500"
placeholder="••••••••">
@error('password')
<span class="text-red-500 text-sm">
{{ $message }}
</span>
@enderror
</div>
</div>

95
resources/views/choferes.blade.php

@ -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

62
resources/views/choferesCrearEditar.blade.php

@ -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 --}}

86
resources/views/dashboard.blade.php

@ -1,6 +1,15 @@
@extends('layouts.dashboard')
@section('content')
@if(!empty($notificaciones))
<div class="bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700 p-4 mb-4">
<ul class="list-disc pl-5">
@foreach($notificaciones as $nota)
<li>{{ $nota }}</li>
@endforeach
</ul>
</div>
@endif
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<!-- Tarjeta de Préstamos Activos -->
<div class="bg-white rounded-lg shadow p-6">
@ -10,8 +19,8 @@
<i class="fas fa-book-reader"></i>
</span>
</div>
<p class="text-3xl font-bold text-gray-900">25</p>
<p class="text-sm text-gray-500 mt-2">↑ 12% desde el mes pasado</p>
<p class="text-3xl font-bold text-gray-900">{{ $adminData['prestamosAceptados'] }}</p>
<p class="text-sm text-gray-500 mt-2">Préstamos actualmente activos</p>
</div>
<!-- Tarjeta de Usuarios Registrados -->
@ -22,32 +31,32 @@
<i class="fas fa-users"></i>
</span>
</div>
<p class="text-3xl font-bold text-gray-900">150</p>
<p class="text-sm text-gray-500 mt-2">↑ 5% desde el mes pasado</p>
<p class="text-3xl font-bold text-gray-900">{{ $adminData['totalUsers'] }}</p>
<p class="text-sm text-gray-500 mt-2">Total de usuarios en el sistema</p>
</div>
<!-- Tarjeta de Préstamos Vencidos -->
<!-- Tarjeta de Préstamos Pendientes -->
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center justify-between mb-4">
<h3 class="text-lg font-semibold text-gray-700">Préstamos Vencidos</h3>
<h3 class="text-lg font-semibold text-gray-700">Préstamos Pendientes</h3>
<span class="text-red-600 bg-red-100 rounded-full p-2">
<i class="fas fa-exclamation-circle"></i>
</span>
</div>
<p class="text-3xl font-bold text-gray-900">3</p>
<p class="text-sm text-gray-500 mt-2">↓ 2% desde el mes pasado</p>
<p class="text-3xl font-bold text-gray-900">{{ $adminData['prestamosPendientes'] }}</p>
<p class="text-sm text-gray-500 mt-2">Préstamos por revisar</p>
</div>
<!-- Tarjeta de Préstamos del Mes -->
<!-- Tarjeta de Total Préstamos -->
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center justify-between mb-4">
<h3 class="text-lg font-semibold text-gray-700">Préstamos del Mes</h3>
<h3 class="text-lg font-semibold text-gray-700">Total Préstamos</h3>
<span class="text-purple-600 bg-purple-100 rounded-full p-2">
<i class="fas fa-chart-line"></i>
</span>
</div>
<p class="text-3xl font-bold text-gray-900">42</p>
<p class="text-sm text-gray-500 mt-2">↑ 8% desde el mes pasado</p>
<p class="text-3xl font-bold text-gray-900">{{ $adminData['totalPrestamos'] }}</p>
<p class="text-sm text-gray-500 mt-2">Total de préstamos registrados</p>
</div>
</div>
@ -66,34 +75,37 @@
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<tr>
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<div class="flex-shrink-0 h-10 w-10">
<img class="h-10 w-10 rounded-full" src="https://ui-avatars.com/api/?name=Juan+Pérez" alt="">
</div>
<div class="ml-4">
<div class="text-sm font-medium text-gray-900">Juan Pérez</div>
<div class="text-sm text-gray-500">juan@example.com</div>
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm text-gray-900">Solicitó préstamo</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm text-gray-900">Hace 2 horas</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">
Aprobado
</span>
</td>
</tr>
<!-- Más filas de actividad aquí -->
<!-- Aquí irían los registros de actividad -->
</tbody>
</table>
</div>
</div>
</div>
<!-- Sección de Administración -->
<div class="mt-8 bg-white rounded-lg shadow">
<div class="p-6">
<h2 class="text-xl font-semibold text-gray-800 mb-4">Acciones de Administración</h2>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<a href="{{ route('usuarios') }}" class="p-4 bg-blue-50 rounded-lg hover:bg-blue-100 transition-colors">
<div class="flex items-center space-x-3">
<i class="fas fa-users text-blue-600 text-xl"></i>
<span class="text-blue-800 font-medium">Gestión de Usuarios</span>
</div>
</a>
<a href="{{ route('marca.index') }}" class="p-4 bg-green-50 rounded-lg hover:bg-green-100 transition-colors">
<div class="flex items-center space-x-3">
<i class="fas fa-trademark text-green-600 text-xl"></i>
<span class="text-green-800 font-medium">Gestión de Marcas</span>
</div>
</a>
<a href="{{ route('puestos.index') }}" class="p-4 bg-purple-50 rounded-lg hover:bg-purple-100 transition-colors">
<div class="flex items-center space-x-3">
<i class="fas fa-briefcase text-purple-600 text-xl"></i>
<span class="text-purple-800 font-medium">Gestión de Puestos</span>
</div>
</a>
</div>
</div>
</div>
@endsection

55
resources/views/exports/choferes-pdf.blade.php

@ -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>

66
resources/views/exports/prestamo-individual-pdf.blade.php

@ -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>

79
resources/views/exports/prestamos-reporte-pdf.blade.php

@ -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>

53
resources/views/exports/puestos.blade.php

@ -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>

31
resources/views/exports/usuarios-pdf.blade.php

@ -4,41 +4,56 @@
<head>
<title>Lista de Usuarios</title>
<style>
/* Estilos opcionales para el PDF */
body {
font-family: Arial, sans-serif;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
th, td {
border: 1px solid black;
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>Lista de Usuarios</h1>
<p>Fecha de generación: {{ date('d/m/Y H:i:s') }}</p>
</div>
<table>
<thead>
<tr>
<th>ID</th>
<th>No.</th>
<th>Nombre</th>
<th>Email</th>
<th>Apellido</th>
<th>Puesto</th>
<th>Carrera</th>
<th>Tipo</th>
<th>Departamento</th>
<th>Teléfono</th>
</tr>
</thead>
<tbody>
@foreach($usuarios as $usuario)
@foreach($usuarios as $index => $usuario)
<tr>
<td>{{ $usuario->id }}</td>
<td>{{ $index + 1 }}</td>
<td>{{ $usuario->name }}</td>
<td>{{ $usuario->email }}</td>
<td>{{ $usuario->apellido }}</td>
<td>{{ $usuario->puesto }}</td>
<td>{{ $usuario->carrera }}</td>
<td>{{ $usuario->puesto->nombre ?? '' }}</td>
<td>{{ $usuario->tipo->nombre ?? '' }}</td>
<td>{{ $usuario->departamento->departamento ?? '' }}</td>
<td>{{ $usuario->telefono }}</td>
</tr>
@endforeach

5
resources/views/layouts/app.blade.php

@ -15,11 +15,12 @@
<!-- Scripts -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
<script src="{{ asset('js/app.js') }}" defer></script>
</head>
<body>
<div id="app">
@if (!request()->is('user-dashboard') && !request()->is('user-dashboard/cuestionario') && !request()->is('user-dashboard/prestamos-aceptados'))
<nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="{{ url('/') }}">
@ -65,7 +66,7 @@
</div>
</div>
</nav>
@endif
<main class="py-4">
@yield('content')
</main>

64
resources/views/layouts/dashboard.blade.php

@ -73,29 +73,31 @@
class="pl-4 mt-2 space-y-1 text-sm">
<li>
<a href="{{ route('prestamos.index') }}" class="nav-item-hover flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-white/10 backdrop-blur-sm {{ request()->is('tiposLicencias*') ? 'bg-white/20' : '' }}">
<a href="{{ route('prestamos.index') }}" class="nav-item-hover flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-white/10 backdrop-blur-sm">
<i class="fas fa-plus text-white/80"></i>
<span class="font-light">Nuevo Préstamo</span>
</a>
</li>
<li>
<!-- <li>
<a href="/prestamos/pendientes" class="nav-item-hover flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-white/10 backdrop-blur-sm {{ request()->is('prestamos/pendientes') ? 'bg-white/20' : '' }}">
<i class="fas fa-clock text-white/80"></i>
<span class="font-light">Préstamos Pendientes</span>
</a>
</li>
-->
<li>
<a href="/prestamos/rechazados" class="nav-item-hover flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-white/10 backdrop-blur-sm {{ request()->is('prestamos/rechazados') ? 'bg-white/20' : '' }}">
<i class="fas fa-times text-white/80"></i>
<span class="font-light">Préstamos Rechazados</span>
<a href="/prestamos/aceptados" class="nav-item-hover flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-white/10 backdrop-blur-sm {{ request()->is('prestamos/aceptados') ? 'bg-white/20' : '' }}">
<i class="fas fa-clock text-white/80"></i>
<span class="font-light">Préstamos pendientes/aceptados</span>
</a>
</li>
<li>
<a href="/prestamos/aceptados" class="nav-item-hover flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-white/10 backdrop-blur-sm {{ request()->is('prestamos/aceptados') ? 'bg-white/20' : '' }}">
<i class="fas fa-check text-white/80"></i>
<span class="font-light">Préstamos Aceptados</span>
<a href="/prestamos/rechazados" class="nav-item-hover flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-white/10 backdrop-blur-sm {{ request()->is('prestamos/rechazados') ? 'bg-white/20' : '' }}">
<i class="fas fa-times text-white/80"></i>
<span class="font-light">Préstamos Rechazados</span>
</a>
</li>
<li>
<a href="/prestamos/historial" class="nav-item-hover flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-white/10 backdrop-blur-sm {{ request()->is('prestamos/historial') ? 'bg-white/20' : '' }}">
<i class="fas fa-history text-white/80"></i>
@ -150,6 +152,22 @@
<span class="font-light">Marca</span>
</a>
</li>
<!-- puesto -->
<li>
<a href="{{ route('puestos.index') }}" class="nav-item-hover flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-white/10 backdrop-blur-sm {{ request()->is('puestos*') ? 'bg-white/20' : '' }}">
<i class="fas fa-briefcase text-white/80"></i>
<span class="font-light">Puestos</span>
</a>
</li>
<!-- departamento -->
<li>
<a href="{{ route('despartamentos.index') }}" class="nav-item-hover flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-white/10 backdrop-blur-sm {{ request()->is('departamentos*') ? 'bg-white/20' : '' }}">
<i class="fas fa-building text-white/80"></i>
<span class="font-light">Departamentos</span>
</a>
</li>
<!-- Tipos -->
<li>
@ -161,9 +179,9 @@
<!-- Tipos de Licencia -->
<li>
<a href="{{ route('tiposLicencias.index') }}" class="nav-item-hover flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-white/10 backdrop-blur-sm {{ request()->is('tiposLicencias*') ? 'bg-white/20' : '' }}">
<a href="{{ route('choferes.index') }}" class="nav-item-hover flex items-center space-x-3 px-4 py-3 rounded-lg hover:bg-white/10 backdrop-blur-sm {{ request()->is('choferes*') ? 'bg-white/20' : '' }}">
<i class="fas fa-id-card text-white/80"></i>
<span class="font-light">Tipos de Licencia</span>
<span class="font-light">Choferes</span>
</a>
</li>
@ -181,17 +199,7 @@
<span class="font-light">Tipo de Gasolina</span>
</a>
</li>
<!-- Puestos -->
<li x-data="{ openPuestos: false }" class="relative">
<button @click="openPuestos = !openPuestos"
class="nav-item-hover flex items-center justify-between w-full px-4 py-3 rounded-lg hover:bg-white/10 backdrop-blur-sm">
<div class="flex items-center space-x-2">
<i class="fas fa-user-tie text-white/80"></i>
<span class="font-light">Puestos</span>
</div>
<i class="fas fa-chevron-right text-xs"
:class="{ 'transform rotate-90': openPuestos }"></i>
</button>
<!-- Submenú de Puestos -->
<ul x-show="openPuestos"
@ -234,14 +242,16 @@
<!-- Navbar modernizado -->
<header class="bg-white/80 backdrop-blur-md shadow-sm">
<div class="flex items-center justify-between px-8 py-4">
<div class="flex items-center bg-gray-100 rounded-full px-3 py-1 shadow-sm">
<img src="https://ui-avatars.com/api/?name={{ Auth::user()->name }}&background=E5E7EB&color=374151&rounded=true&size=32" alt="Avatar" class="w-8 h-8 rounded-full mr-2">
<span class="font-semibold text-gray-800">{{ Auth::user()->name }}</span>
<div class="flex items-center gap-2 bg-gray-100 rounded-full px-2 py-1">
<div class="w-10 h-10 flex items-center justify-center rounded-full bg-gray-200 text-gray-700 font-semibold text-lg">
{{ strtoupper(substr(Auth::user()->name ?? 'U', 0, 1)) }}{{ strtoupper(substr(Auth::user()->name ?? 'U', 1, 1)) }}
</div>
<span class="font-medium text-gray-800">{{ Auth::user()->name ?? 'Usuario' }}</span>
</div>
<form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: inline; margin: 0;">
<form method="POST" action="{{ route('logout') }}">
@csrf
<button type="submit" class="flex items-center text-red-600 hover:text-red-800 font-semibold px-3 py-1 rounded transition-colors duration-150" title="Cerrar Sesión">
<i class="fas fa-sign-out-alt mr-2"></i> Cerrar Sesión
<button type="submit" class="flex items-center gap-1 text-red-600 hover:text-red-800 font-semibold transition-colors">
<i class="fas fa-sign-out-alt"></i> Cerrar Sesión
</button>
</form>
</div>

7
resources/views/prestamos.blade.php

@ -77,6 +77,7 @@
<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">Nombre Solicitante</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Vehiculo</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 y Hora Salida</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Fecha y Hora Llegada</th>
@ -100,6 +101,12 @@
{{ $prestamo->nombre_solicitante }}
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
<div class="flex items-center">
<i class="fas fa-truck text-green-500 mr-2"></i>
{{ $prestamo->vehiculo->nombre }}
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
<div class="flex items-center">
<i class="fas fa-map-marker-alt text-red-500 mr-2"></i>

47
resources/views/prestamos/pendientes.blade.php

@ -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

91
resources/views/prestamos/rechazados.blade.php

@ -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

23
resources/views/prestamos/show.blade.php

@ -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

50
resources/views/prestamosCrearEditar.blade.php

@ -61,6 +61,30 @@
@enderror
</div>
<!-- Campo Vehículo -->
<div>
<label for="vehiculo_id" class="block text-sm font-medium text-gray-700 mb-2">
Vehículo
</label>
<div class="relative">
<i class="fas fa-car absolute left-3 top-2.5 text-gray-400"></i>
<select name="vehiculo_id"
id="vehiculo_id"
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>
<option value="">Seleccione un vehículo</option>
@foreach($vehiculos as $vehiculo)
<option value="{{ $vehiculo->id }}" {{ old('vehiculo_id') == $vehiculo->id ? 'selected' : '' }}>
{{ $vehiculo->nombre }} - {{ ucfirst(str_replace('_', ' ', $vehiculo->tipo_combustible)) }}
</option>
@endforeach
</select>
</div>
@error('vehiculo_id')
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
@enderror
</div>
<!-- Campo Destino -->
<div>
<label for="destino" class="block text-sm font-medium text-gray-700 mb-2">
@ -179,14 +203,20 @@
<!-- Campo Chofer -->
<div class="flex items-center">
<input type="checkbox"
name="chofer"
id="chofer"
class="rounded border-gray-300 text-blue-600 shadow-sm focus:ring-blue-500"
{{ isset($prestamo) && $prestamo->chofer ? 'checked' : '' }}>
<input type="checkbox" name="chofer" id="chofer" {{ old('chofer') ? 'checked' : '' }} onchange="toggleChoferCatalogo()">
<label for="chofer" class="ml-2 text-sm text-gray-700">¿Requiere chofer?</label>
</div>
<div id="catalogo-choferes" style="display:none; margin-top: 1em;">
<label for="chofer_id" class="block text-sm font-medium text-gray-700 mb-2">Chofer</label>
<select name="chofer_id" id="chofer_id" class="block w-full border border-gray-300 rounded-md">
<option value="">Seleccione un chofer</option>
@foreach($choferes as $chofer)
<option value="{{ $chofer->id }}">{{ $chofer->nombre }} - {{ $chofer->tipo_licencia }}</option>
@endforeach
</select>
</div>
<!-- Botones de acción -->
<div class="flex justify-end space-x-2 pt-4 border-t border-gray-200">
<a href="{{ route('prestamos.index') }}"
@ -204,4 +234,14 @@
</div>
</div>
</div>
<script>
function toggleChoferCatalogo() {
var check = document.getElementById('chofer').checked;
document.getElementById('catalogo-choferes').style.display = check ? 'block' : 'none';
}
document.addEventListener('DOMContentLoaded', function() {
toggleChoferCatalogo();
});
</script>
@endsection

78
resources/views/profesor/solicitudes/create.blade.php

@ -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

51
resources/views/profesor/solicitudes/index.blade.php

@ -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

142
resources/views/puestos.blade.php

@ -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

51
resources/views/tiposLicenciaCrearEditar.blade.php → resources/views/puestosCrearEditar.blade.php

@ -1,4 +1,3 @@
{{-- Start of Selection --}}
@extends('layouts.dashboard')
@section('content')
@ -9,66 +8,71 @@
<!-- Encabezado del formulario -->
<div class="flex items-center justify-between mb-6">
<h2 class="text-2xl font-bold text-gray-800">
{{ isset($tipoLicencia) ? 'Editar Tipo de Licencia' : 'Nuevo Tipo de Licencia' }}
{{ isset($puesto) ? 'Editar Puesto' : 'Nuevo Puesto' }}
</h2>
<div class="h-10 w-10 bg-blue-100 rounded-full flex items-center justify-center">
<i class="fas fa-car text-blue-600"></i>
<i class="fas fa-briefcase text-blue-600"></i>
</div>
</div>
<!-- Mensajes de error -->
@if(session('error'))
<div class="mb-6 bg-red-100 border-l-4 border-red-500 p-4 rounded-r-lg">
@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 text-xl"></i>
<div class="text-red-700 font-semibold">
{{ session('error') }}
<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
<!-- Formulario -->
<form id="tipoLicenciaForm"
action="{{ isset($tipoLicencia) ? route('tiposLicencias.update', $tipoLicencia->id) : route('tiposLicencias.store') }}"
<form id="puestoForm"
action="{{ isset($puesto) ? route('puestos.update', $puesto->id) : route('puestos.store') }}"
method="POST">
@csrf
@if(isset($tipoLicencia))
@if(isset($puesto))
@method('PUT')
@endif
<div class="space-y-6">
<!-- Campo Tipo de Licencia -->
<!-- Campo Nombre -->
<div>
<label for="tipoLicencia" class="block text-sm font-medium text-gray-700 mb-2">
Tipo de Licencia
<label for="nombre" class="block text-sm font-medium text-gray-700 mb-2">
Nombre del Puesto
</label>
<div class="relative rounded-md shadow-sm">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<i class="fas fa-tag text-gray-400"></i>
</div>
<input type="text"
name="tipoLicencia"
id="tipoLicencia"
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"
value="{{ isset($tipoLicencia) ? $tipoLicencia->tipoLicencia : old('tipoLicencia') }}"
placeholder="Ingrese el tipo de licencia"
required>
required
placeholder="Ingresa el nombre del puesto"
value="{{ isset($puesto) ? $puesto->nombre : old('nombre') }}">
</div>
@error('tipoLicencia')
@error('nombre')
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
@enderror
</div>
<!-- Botones de acción -->
<div class="flex justify-end space-x-2 pt-4 border-t border-gray-200">
<a href="{{ route('tiposLicencias.index') }}"
<a href="{{ route('puestos.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($tipoLicencia) ? 'Actualizar' : 'Guardar' }}
{{ isset($puesto) ? 'Actualizar' : 'Guardar' }}
</button>
</div>
</div>
@ -78,4 +82,3 @@
</div>
</div>
@endsection
{{-- End of Selection --}}

152
resources/views/tiposLicencia.blade.php

@ -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

402
resources/views/user-dashboard/cuestionario.blade.php

@ -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;">&times;</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

28
resources/views/user-dashboard/detalle-prestamo.blade.php

@ -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

34
resources/views/user-dashboard/index.blade.php

@ -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

171
resources/views/user-dashboard/prestamos-aceptados.blade.php

@ -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

22
resources/views/usuarios.blade.php

@ -83,6 +83,7 @@
<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">Email </th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Apellido </th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tipo </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">Carrera </th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Teléfono </th>
@ -97,7 +98,7 @@
</tr>
@else
@foreach($usuarios as $index => $usuario)
<tr class="hover:bg-gray-50">
<tr class="hover:bg-gray-50 @if(is_null($usuario->puesto_id) || is_null($usuario->departamento_id)) bg-red-100 @endif">
<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-user text-blue-500 mr-2"></i>
@ -109,14 +110,31 @@
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
<i class="fas fa-user-tag text-green-500"></i> {{ $usuario->apellido }}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
<div class="flex items-center">
<i class="fas fa-briefcase text-gray-400 mr-2"></i>
{{ $usuario->tipo->nombre ?? 'Sin tipo asignado' }}
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
@if(is_null($usuario->puesto_id) || is_null($usuario->departamento_id))
<i class="fas fa-exclamation-triangle text-red-500 mr-2" title="Usuario sin puesto o departamento asignado"></i>
@endif
<div class="flex items-center">
<i class="fas fa-briefcase text-gray-400 mr-2"></i>
{{ $usuario->puesto->nombre ?? 'Sin puesto asignado' }}
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
<i class="fas fa-graduation-cap text-purple-500"></i> {{ $usuario->carrera }}
@if(is_null($usuario->puesto_id) || is_null($usuario->departamento_id))
<i class="fas fa-exclamation-triangle text-red-500 mr-2" title="Usuario sin puesto o departamento asignado"></i>
@endif
<div class="flex items-center">
<i class="fas fa-building text-gray-400 mr-2"></i>
{{ $usuario->departamento->departamento ?? 'Sin departamento asignado' }}
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-900">
<i class="fas fa-phone text-red-500"></i> {{ $usuario->telefono }}

29
resources/views/usuariosCrearEditar.blade.php

@ -70,7 +70,34 @@
required value="{{ isset($usuario) ? $usuario->apellido : old('apellido') }}">
</div>
</div>
<div>
<label for="tipos_id" class="block text-sm font-medium text-gray-700 mb-2">Tipo</label>
<div class="relative">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<i class="fas fa-id-badge text-gray-400"></i>
</div>
<select name="tipos_id" id="tipos_id" class="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md" required>
<option value="">Selecciona un tipo</option>
@if(auth()->user()->tipos_id == 4)
@foreach($tipos as $tipo)
@if($tipo->id == 2)
<option value="{{ $tipo->id }}"
{{ (isset($usuario) && $usuario->tipos_id == $tipo->id) ? 'selected' : '' }}>
{{ $tipo->nombre }}
</option>
@endif
@endforeach
@else
@foreach($tipos as $tipo)
<option value="{{ $tipo->id }}"
{{ (isset($usuario) && $usuario->tipos_id == $tipo->id) ? 'selected' : '' }}>
{{ $tipo->nombre }}
</option>
@endforeach
@endif
</select>
</div>
</div>
<div>
<label for="puestos_id" class="block text-sm font-medium text-gray-700 mb-2">Puesto</label>
<div class="relative">

57
routes/web.php

@ -9,6 +9,10 @@ use App\Http\Controllers\TiposVeiculosController;
use App\Http\Controllers\TiposLicenciasController;
use App\Http\Controllers\CapacidadController;
use App\Http\Controllers\PrestamoController;
use App\Http\Controllers\DespartamentoController;
use App\Http\Controllers\SolicitudVehiculoController;
use App\Http\Controllers\ChoferController;
use App\Http\Controllers\PuestoController;
/*
@ -49,38 +53,63 @@ use App\Http\Controllers\PrestamoController;
Route::get('/marcas/excel', [MarcaController::class, 'exportExcel'])->name('marcas.excel');
Route::get('/marcas/pdf', [MarcaController::class, 'exportPDF'])->name('marcas.pdf');
// Primero las rutas de exportación (más específicas)
Route::get('/prestamos/excel', [PrestamoController::class, 'exportExcel'])->name('prestamos.excel');
Route::get('/prestamos/pdf', [PrestamoController::class, 'exportPDF'])->name('prestamos.pdf');
Route::get('/despartamento/export/excel', [DespartamentoController::class, 'exportExcel'])->name('despartamentos.excel');
Route::get('/despartamento/export/pdf', [DespartamentoController::class, 'exportPDF'])->name('despartamentos.pdf');
// Rutas de préstamos protegidas solo para administradores (historial, aceptar, rechazar, etc.)
Route::middleware(['auth', 'admin'])->group(function () {
Route::get('/prestamos/aceptados', [PrestamoController::class, 'aceptados'])->name('prestamos.aceptados');
Route::post('/prestamos/{id}/aceptar', [PrestamoController::class, 'aceptar'])->name('prestamos.aceptar');
Route::post('/prestamos/{id}/rechazar', [PrestamoController::class, 'rechazar'])->name('prestamos.rechazar');
Route::get('/prestamos/historial', [PrestamoController::class, 'historial'])->name('prestamos.historial');
Route::get('/prestamos/pendientes', [PrestamoController::class, 'pendientes'])->name('prestamos.pendientes');
Route::get('/prestamos/rechazados', [PrestamoController::class, 'rechazados'])->name('prestamos.rechazados');
Route::get('/prestamos/excel', [PrestamoController::class, 'exportExcel'])->name('prestamos.excel');
Route::get('/prestamos/pdf', [PrestamoController::class, 'exportPDF'])->name('prestamos.pdf');
Route::get('/prestamos/export/{format}', [PrestamoController::class, 'export'])->name('prestamos.export');
});
// Después la ruta de recurso (más general)
Route::resource('prestamos', PrestamoController::class);
// Rutas de gestión de préstamos (crear, editar, eliminar) para admin y servicios
Route::middleware(['auth', 'can:gestionar-prestamos'])->resource('prestamos', PrestamoController::class);
// Ruta general de préstamos (solo para ver)
Route::middleware(['auth'])->group(function () {
Route::get('/prestamos', [PrestamoController::class, 'index'])->name('prestamos.index');
Route::get('/prestamos/{id}', [PrestamoController::class, 'show'])->name('prestamos.show');
});
Route::get('/docentes/export/{format}', [DocentesController::class, 'export'])->name('docentes.export');
Route::get('/docentes/{id}/toggle-status', [DocentesController::class, 'toggleStatus'])->name('docentes.toggle-status');
// Rutas protegidas que requieren autenticación
// Rutas protegidas que requieren autenticación
Route::middleware(['auth'])->group(function () {
Route::get('/dashboard', [HomeController::class, 'index'])->name('dashboard');
Route::get('/maintenance', [MaintenanceController::class, 'index'])->name('maintenance.dashboard');
Route::get('/usuarios', [usuariosController::class,'index'])->name('usuarios');
Route::get('/usuarios/nuevo', [usuariosController::class, 'create'])->name('usuarios.create');
Route::post('/usuarios/store', [usuariosController::class,'store'])->name('usuarios.store');
Route::get('/usuarios/edit/{id}', [usuariosController::class, 'edit'])->name('usuarios.edit');
Route::put('/usuarios/{id}', [usuariosController::class, 'update'])->name('usuarios.update');
Route::delete('/usuarios/destroy/{id}', [usuariosController::class, 'destroy'])->name('usuarios.destroy');
Route::get('usuarios/excel', [usuariosController::class, 'exportExcel'])->name('usuarios.excel');
Route::get('usuarios/pdf', [usuariosController::class, 'exportPDF'])->name('usuarios.pdf');
Route::get('/home', [HomeController::class, 'index'])->name('home');
////corerecion rubi
Route::get('/user-dashboard/prestamos-aceptados', [App\Http\Controllers\UserDashboardController::class, 'prestamosAceptados'])->name('user.prestamos.aceptados');
Route::get('/user-dashboard/prestamos-aceptados/{id}', [App\Http\Controllers\UserDashboardController::class, 'detallePrestamo'])->name('user.prestamos.detalle');
Route::get('/user-dashboard/cuestionario', [App\Http\Controllers\UserDashboardController::class, 'cuestionario'])->name('user.cuestionario');
Route::get('/user-dashboard/prestamo/{id}/pdf', [App\Http\Controllers\UserDashboardController::class, 'pdfPrestamo'])->name('user.prestamo.pdf');
});
// Ruta para el dashboard de usuarios
Route::get('/user-dashboard', [App\Http\Controllers\UserDashboardController::class, 'index'])->name('user.dashboard');
// Ruta para el cuestionario del dashboard de usuario
Route::get('/user-dashboard/cuestionario', function () {
return view('user-dashboard.cuestionario');
})->middleware('auth');
Route::resource('choferes', ChoferController::class);
Route::get('choferes/excel', [App\Http\Controllers\ChoferController::class, 'exportExcel'])->name('choferes.excel');
Route::get('choferes/pdf', [App\Http\Controllers\ChoferController::class, 'exportPDF'])->name('choferes.pdf');
});
Route::resource('puestos', PuestoController::class);

Loading…
Cancel
Save