sergiomarquez778 1 month ago
parent
commit
ee78d69b3f
  1. 24
      app/Exports/ChoferesExport.php
  2. 7
      app/Http/Controllers/Auth/LoginController.php
  3. 97
      app/Http/Controllers/ChoferController.php
  4. 35
      app/Http/Controllers/PrestamoController.php
  5. 49
      app/Http/Controllers/SolicitudVehiculoController.php
  6. 23
      app/Http/Controllers/TiposLicenciasController.php
  7. 23
      app/Http/Controllers/UserDashboardController.php
  8. 6
      app/Http/Controllers/usuariosController.php
  9. 5
      app/Http/Kernel.php
  10. 23
      app/Http/Middleware/AdminOrServiciosRole.php
  11. 20
      app/Http/Middleware/CheckAdminRole.php
  12. 19
      app/Http/Middleware/CheckProfesorRole.php
  13. 19
      app/Http/Middleware/CheckServiciosRole.php
  14. 18
      app/Models/Chofer.php
  15. 26
      app/Models/SolicitudVehiculo.php
  16. 1
      app/Models/User.php
  17. 8
      app/Models/prestamo.php
  18. 9
      app/Providers/AuthServiceProvider.php
  19. 62
      database/migrations/2014_10_12_000000_create_users_table.php
  20. 31
      database/migrations/2024_03_19_create_user_dashboard_user.php
  21. 28
      database/migrations/2024_03_27_000000_create_solicitud_vehiculos_table.php
  22. 1
      database/migrations/2025_03_27_174121_create_prestamos_table.php
  23. 28
      database/migrations/2025_03_28_182126_add_estado_to_prestamos_table.php
  24. 28
      database/migrations/2025_03_28_183038_add_estado_to_prestamos_table.php
  25. 11
      database/migrations/2025_04_01_191325_add_estado_to_prestamos_table.php
  26. 28
      database/migrations/2025_05_20_032155_add_columneliminado_topuestos.php
  27. 17
      database/migrations/2025_05_22_205902_create_chofers_table.php
  28. 25
      database/migrations/2025_05_22_212123_add_chofer_id_to_prestamos_table.php
  29. 5
      database/seeders/DatabaseSeeder.php
  30. 22
      database/seeders/ProfesorSeeder.php
  31. 24
      database/seeders/ServiciosSeeder.php
  32. 85
      public/css/user-dashboard.css
  33. 95
      resources/views/choferes.blade.php
  34. 62
      resources/views/choferesCrearEditar.blade.php
  35. 55
      resources/views/exports/choferes-pdf.blade.php
  36. 5
      resources/views/layouts/app.blade.php
  37. 6
      resources/views/layouts/dashboard.blade.php
  38. 7
      resources/views/prestamos.blade.php
  39. 50
      resources/views/prestamosCrearEditar.blade.php
  40. 78
      resources/views/profesor/solicitudes/create.blade.php
  41. 51
      resources/views/profesor/solicitudes/index.blade.php
  42. 152
      resources/views/tiposLicencia.blade.php
  43. 81
      resources/views/tiposLicenciaCrearEditar.blade.php
  44. 393
      resources/views/user-dashboard/cuestionario.blade.php
  45. 31
      resources/views/user-dashboard/index.blade.php
  46. 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',
];
}
}

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

@ -37,4 +37,11 @@ class LoginController extends Controller
$this->middleware('guest')->except('logout');
$this->middleware('auth')->only('logout');
}
protected function authenticated($request, $user)
{
if ($user->email === 'usuarios@usuariosgmail.com') {
return redirect('/user-dashboard');
}
}
}

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

35
app/Http/Controllers/PrestamoController.php

@ -40,7 +40,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
]);
}
/**
@ -48,16 +54,27 @@ class PrestamoController extends Controller
*/
public function store(Request $request)
{
// 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'
]);
// Preparar los datos
$datos = $request->all();
$datos['chofer'] = $request->has('chofer') ? 1 : 0; // Convertir 'on' a 1, o ausencia a 0
$datos['chofer'] = $request->has('chofer') ? 1 : 0;
$prestamo = new Prestamo($datos);
$prestamo->estado = 'pendiente'; // Estado inicial
$prestamo->estado = 'pendiente';
$prestamo->save();
// Aquí puedes agregar notificaciones para los administradores
return redirect()->route('prestamos.index')
->with('success', 'Préstamo solicitado correctamente. Esperando aprobación.');
}
@ -68,7 +85,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
}
/**

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

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')) {

23
app/Http/Controllers/UserDashboardController.php

@ -0,0 +1,23 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class UserDashboardController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
// Verificar si el usuario tiene el correo específico
if (auth()->user()->email !== 'usuarios@usuariosgmail.com') {
return redirect('/')->with('error', 'No tienes permiso para acceder a esta sección');
}
return view('user-dashboard.index');
}
}

6
app/Http/Controllers/usuariosController.php

@ -106,6 +106,12 @@ class usuariosController extends Controller
$usuario->departamento_id = $request->departamento_id;
$usuario->telefono = $request->telefono;
$usuario->password = bcrypt($request->password);
// Asignar rol si viene en la petición y el usuario autenticado es admin o servicios
if (auth()->user()->rol === 'admin' && $request->has('rol')) {
$usuario->rol = $request->rol;
} elseif (auth()->user()->rol === 'servicios') {
$usuario->rol = 'usuario'; // Solo puede crear usuarios normales
}
$usuario->save();
return redirect()->route('usuarios')->with('success', 'Usuario creado exitosamente.');

5
app/Http/Kernel.php

@ -60,9 +60,14 @@ 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 = [

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()->rol !== 'admin') {
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()->rol !== 'servicios') {
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);
}
}

1
app/Models/User.php

@ -28,6 +28,7 @@ class User extends Authenticatable
'departamento_id',
'telefono',
'password',
'rol',
];

8
app/Models/prestamo.php

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

9
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,11 @@ class AuthServiceProvider extends ServiceProvider
* Register any authentication / authorization services.
*/
public function boot(): void
{
{
$this->registerPolicies();
//
}
Gate::define('gestionar-prestamos', function ($user) {
return in_array($user->rol, ['admin', 'servicios']);
});
}
}

62
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,72 +19,25 @@ return new class extends Migration
$table->timestamp('email_verified_at')->nullable();
$table->string('apellido')->nullable();
$table->unsignedBigInteger('puesto_id')->nullable();
$table->unsignedBigInteger('tipos_id')->nullable();
$table->unsignedBigInteger('departamento_id')->nullable();
$table->string('telefono')->nullable();
$table->string('password');
$table->string('rol')->default('profesor');
$table->rememberToken();
$table->timestamps();
$table->foreign('puesto_id')->references('id')->on('puestos');
$table->foreign('tipos_id')->references('id')->on('tipos');
$table->foreign('departamento_id')->references('id')->on('despartamentos');
});
DB::table('users')->insert([
'name' => 'silva',
'email' => 'silva@silva.com',
'apellido' => 'anael',
'tipos_id' => 2, // Asegúrate que este ID corresponde a "Usuario" en la tabla tipos
'puesto_id' => 2, // Asegúrate que este ID corresponde a "docente" en la tabla puestos
'departamento_id' => 2, // Asegúrate que este ID corresponde a "wfaf" en la tabla despartamentos
'telefono' => '33652147821',
'password' => bcrypt('12345678'),
'email_verified_at' => now(),
'created_at' => now(),
'updated_at' => now(),
]);
DB::table('users')->insert([
'name' => 'monse',
'email' => 'monse@monse.com',
'apellido' => 'martinez',
'tipos_id' => 1,
'puesto_id' => 1,
'departamento_id' => 3,
'telefono' => null,
'password' => bcrypt('12345678'),
'email_verified_at' => now(),
'created_at' => now(),
'updated_at' => now(),
'name'=> 'Administrador',
'email'=> 'admin@admin.com',
'password'=> bcrypt('12345678'),
'rol' => 'admin'
]);
DB::table('users')->insert([
'name' => 'usuario_tipo3',
'email' => 'tipo3@ejemplo.com',
'apellido' => 'apellido3',
'tipos_id' => 3, // Tercer tipo restante
'puesto_id' => 1, // Puedes ajustar el puesto según corresponda
'departamento_id' => 1, // Puedes ajustar el departamento según corresponda
'telefono' => '3333333333',
'password' => bcrypt('12345678'),
'email_verified_at' => now(),
'created_at' => now(),
'updated_at' => now(),
]);
DB::table('users')->insert([
'name' => 'usuario_tipo4',
'email' => 'tipo4@ejemplo.com',
'apellido' => 'apellido4',
'tipos_id' => 4, // Cuarto tipo restante
'puesto_id' => 1, // Puedes ajustar el puesto según corresponda
'departamento_id' => 1, // Puedes ajustar el departamento según corresponda
'telefono' => '4444444444',
'password' => bcrypt('12345678'),
'email_verified_at' => now(),
'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();
});
}

28
database/migrations/2025_03_28_182126_add_estado_to_prestamos_table.php

@ -1,28 +0,0 @@
<?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::table('prestamos', function (Blueprint $table) {
//
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('prestamos', function (Blueprint $table) {
//
});
}
};

28
database/migrations/2025_03_28_183038_add_estado_to_prestamos_table.php

@ -1,28 +0,0 @@
<?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::table('prestamos', function (Blueprint $table) {
$table->string('estado')->default('pendiente'); // pendiente, aceptado, rechazado
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('prestamos', function (Blueprint $table) {
$table->dropColumn('estado');
});
}
};

11
database/migrations/2025_04_01_191325_add_estado_to_prestamos_table.php

@ -9,21 +9,22 @@ return new class extends Migration
/**
* Run the migrations.
*/
public function up(): void
public function up()
{
Schema::table('prestamos', function (Blueprint $table) {
// $table->enum('estado', ['pendiente', 'aceptado', 'rechazado'])->default('pendiente')->after('chofer');
// Línea comentada porque la columna ya existe
$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');
}
});
}
};

28
database/migrations/2025_05_20_032155_add_columneliminado_topuestos.php

@ -1,28 +0,0 @@
<?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::table('puestos', function (Blueprint $table) {
$table->boolean('eliminado')->default(false);
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('puestos', function (Blueprint $table) {
$table->dropColumn('eliminado');
});
}
};

17
database/migrations/2025_03_28_175646_add_estado_to_prestamos_table.php → database/migrations/2025_05_22_205902_create_chofers_table.php

@ -9,20 +9,21 @@ return new class extends Migration
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('prestamos', function (Blueprint $table) {
//
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::table('prestamos', function (Blueprint $table) {
//
});
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',
]);
}
}

24
database/seeders/ServiciosSeeder.php

@ -0,0 +1,24 @@
<?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'),
'rol' => 'servicios',
]
);
}
}

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

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

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>

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'))
<nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="{{ url('/') }}">
@ -73,7 +74,7 @@
</div>
</div>
</nav>
@endif
<main class="py-4">
@yield('content')
</main>

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

@ -73,7 +73,7 @@
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>
@ -171,9 +171,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>

7
resources/views/prestamos.blade.php

@ -86,6 +86,7 @@
<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">Vehiculo</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">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>
@ -110,6 +111,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>

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

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

81
resources/views/tiposLicenciaCrearEditar.blade.php

@ -1,81 +0,0 @@
{{-- 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">
<!-- 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' }}
</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>
</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">
<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') }}
</div>
</div>
</div>
@endif
<!-- Formulario -->
<form id="tipoLicenciaForm"
action="{{ isset($tipoLicencia) ? route('tiposLicencias.update', $tipoLicencia->id) : route('tiposLicencias.store') }}"
method="POST">
@csrf
@if(isset($tipoLicencia))
@method('PUT')
@endif
<div class="space-y-6">
<!-- Campo Tipo de Licencia -->
<div>
<label for="tipoLicencia" class="block text-sm font-medium text-gray-700 mb-2">
Tipo de Licencia
</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"
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>
</div>
@error('tipoLicencia')
<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') }}"
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' }}
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
@endsection
{{-- End of Selection --}}

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

@ -0,0 +1,393 @@
@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>
<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>
<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

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

@ -0,0 +1,31 @@
@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>
<a href="{{ url('/user-dashboard/cuestionario') }}" class="user-dashboard-btn">Ir a la siguiente sección</a>
</div>
</body>
@endsection

57
routes/web.php

@ -10,7 +10,8 @@ use App\Http\Controllers\TiposLicenciasController;
use App\Http\Controllers\CapacidadController;
use App\Http\Controllers\PrestamoController;
use App\Http\Controllers\DespartamentoController;
use App\Http\Controllers\PuestoController;
use App\Http\Controllers\SolicitudVehiculoController;
use App\Http\Controllers\ChoferController;
/*
@ -32,7 +33,6 @@ use App\Http\Controllers\PuestoController;
Route::resource('marca', MarcaController::class);
Route::resource('docentes', DocentesController::class);
Route::resource('puestos', PuestoController::class);
Route::resource('despartamentos', DespartamentoController::class);
@ -57,46 +57,61 @@ use App\Http\Controllers\PuestoController;
Route::get('/despartamento/export/excel', [DespartamentoController::class, 'exportExcel'])->name('despartamentos.excel');
Route::get('/despartamento/export/pdf', [DespartamentoController::class, 'exportPDF'])->name('despartamentos.pdf');
Route::get('/puestos/export/excel', [PuestoController::class, 'exportExcel'])->name('puestos.excel');
Route::get('/puestos/export/pdf', [PuestoController::class, 'exportPDF'])->name('puestos.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('/prestamos/export/{format}', [PrestamoController::class, 'export'])->name('prestamos.export');
// 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');
});
// Rutas de gestión de préstamos (crear, editar, eliminar) para admin y servicios
Route::middleware(['auth', 'can:gestionar-prestamos'])->resource('prestamos', PrestamoController::class);
// Después la ruta de recurso (más general)
Route::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('/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
});
// Rutas para profesores
Route::middleware(['auth', 'profesor'])->prefix('profesor')->name('profesor.')->group(function () {
Route::get('/solicitudes', [SolicitudVehiculoController::class, 'index'])->name('solicitudes.index');
Route::get('/solicitudes/create', [SolicitudVehiculoController::class, 'create'])->name('solicitudes.create');
Route::post('/solicitudes', [SolicitudVehiculoController::class, 'store'])->name('solicitudes.store');
});
// 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');

Loading…
Cancel
Save