41 changed files with 1040 additions and 1211 deletions
@ -1,23 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace App\Exports; |
|||
|
|||
use App\Models\Despartamento; // Asegúrate de que el modelo esté correctamente importado |
|||
use Maatwebsite\Excel\Concerns\FromCollection; |
|||
use Maatwebsite\Excel\Concerns\WithHeadings; |
|||
|
|||
class DespartamentosExport implements FromCollection, WithHeadings |
|||
{ |
|||
public function collection() |
|||
{ |
|||
return Despartamento::where('eliminado', 0)->get(); // Obtiene todos los departamentos activos |
|||
} |
|||
|
|||
public function headings(): array |
|||
{ |
|||
return [ |
|||
'ID', |
|||
'Departamento' |
|||
]; |
|||
} |
|||
} |
@ -1,127 +0,0 @@ |
|||
<?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); // Encuentra el departamento por ID |
|||
$despartamento->eliminado = 1; // Cambia el estado a inactivo |
|||
$despartamento->save(); // Guarda los cambios |
|||
|
|||
return redirect()->route('despartamentos.index')->with('success', 'Departamento inactivado correctamente.'); |
|||
} |
|||
|
|||
public function exportExcel() |
|||
{ |
|||
return Excel::download(new DespartamentosExport, 'despartamentos.xlsx'); |
|||
} |
|||
|
|||
public function exportPDF() |
|||
{ |
|||
$departamentos = despartamento::where('eliminado', 0)->get(); |
|||
$pdf = PDF::loadView('exports.departamentos', ['departamentos' => $departamentos]); |
|||
return $pdf->download('departamentos.pdf'); |
|||
} |
|||
} |
@ -0,0 +1,82 @@ |
|||
<?php |
|||
|
|||
namespace App\Http\Controllers; |
|||
|
|||
use App\Models\Maintenance; |
|||
use App\Models\Vehicle; |
|||
use Illuminate\Http\Request; |
|||
use Illuminate\Support\Facades\DB; |
|||
|
|||
class MaintenanceController extends Controller |
|||
{ |
|||
public function index() |
|||
{ |
|||
return view('maintenance.dashboard'); |
|||
} |
|||
|
|||
public function getMaintenanceHistory() |
|||
{ |
|||
$maintenances = Maintenance::with('vehicle') |
|||
->orderBy('date', 'desc') |
|||
->get(); |
|||
|
|||
return response()->json($maintenances); |
|||
} |
|||
|
|||
public function getPendingAlerts() |
|||
{ |
|||
$alerts = Maintenance::with('vehicle') |
|||
->where('status', 'Pendiente') |
|||
->where('next_maintenance_date', '<=', now()->addDays(30)) |
|||
->orderBy('next_maintenance_date', 'asc') |
|||
->get(); |
|||
|
|||
return response()->json($alerts); |
|||
} |
|||
|
|||
public function store(Request $request) |
|||
{ |
|||
$validated = $request->validate([ |
|||
'vehicle_id' => 'required|exists:vehicles,id', |
|||
'maintenance_type' => 'required|string', |
|||
'date' => 'required|date', |
|||
'description' => 'required|string', |
|||
'cost' => 'required|numeric|min:0', |
|||
'status' => 'required|in:Pendiente,En Proceso,Completado', |
|||
'next_maintenance_date' => 'nullable|date' |
|||
]); |
|||
|
|||
$maintenance = Maintenance::create($validated); |
|||
|
|||
return response()->json([ |
|||
'message' => 'Mantenimiento registrado exitosamente', |
|||
'maintenance' => $maintenance |
|||
], 201); |
|||
} |
|||
|
|||
public function update(Request $request, Maintenance $maintenance) |
|||
{ |
|||
$validated = $request->validate([ |
|||
'vehicle_id' => 'required|exists:vehicles,id', |
|||
'maintenance_type' => 'required|string', |
|||
'date' => 'required|date', |
|||
'description' => 'required|string', |
|||
'cost' => 'required|numeric|min:0', |
|||
'status' => 'required|in:Pendiente,En Proceso,Completado', |
|||
'next_maintenance_date' => 'nullable|date' |
|||
]); |
|||
|
|||
$maintenance->update($validated); |
|||
|
|||
return response()->json([ |
|||
'message' => 'Mantenimiento actualizado exitosamente', |
|||
'maintenance' => $maintenance |
|||
]); |
|||
} |
|||
|
|||
public function getVehicles() |
|||
{ |
|||
$vehicles = Vehicle::where('status', 'Activo')->get(); |
|||
return response()->json($vehicles); |
|||
} |
|||
} |
@ -0,0 +1,32 @@ |
|||
<?php |
|||
|
|||
namespace App\Models; |
|||
|
|||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
|||
use Illuminate\Database\Eloquent\Model; |
|||
|
|||
class Maintenance extends Model |
|||
{ |
|||
use HasFactory; |
|||
|
|||
protected $fillable = [ |
|||
'vehicle_id', |
|||
'maintenance_type', |
|||
'date', |
|||
'description', |
|||
'cost', |
|||
'status', |
|||
'next_maintenance_date' |
|||
]; |
|||
|
|||
protected $casts = [ |
|||
'date' => 'date', |
|||
'next_maintenance_date' => 'date', |
|||
'cost' => 'decimal:2' |
|||
]; |
|||
|
|||
public function vehicle() |
|||
{ |
|||
return $this->belongsTo(TiposVeiculo::class, 'vehicle_id'); |
|||
} |
|||
} |
@ -1,13 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace App\Models; |
|||
|
|||
use Illuminate\Database\Eloquent\Factories\HasFactory; |
|||
use Illuminate\Database\Eloquent\Model; |
|||
|
|||
class despartamento extends Model |
|||
{ |
|||
use HasFactory; |
|||
protected $table = 'despartamentos'; |
|||
protected $fillable = ['departamento']; |
|||
} |
@ -1,23 +0,0 @@ |
|||
<?php |
|||
|
|||
namespace Database\Factories; |
|||
|
|||
use Illuminate\Database\Eloquent\Factories\Factory; |
|||
|
|||
/** |
|||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\despartamento> |
|||
*/ |
|||
class DespartamentoFactory extends Factory |
|||
{ |
|||
/** |
|||
* Define the model's default state. |
|||
* |
|||
* @return array<string, mixed> |
|||
*/ |
|||
public function definition(): array |
|||
{ |
|||
return [ |
|||
// |
|||
]; |
|||
} |
|||
} |
@ -1,32 +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::create('despartamentos', function (Blueprint $table) { |
|||
$table->id(); |
|||
$table->string('departamento'); |
|||
$table->timestamps(); |
|||
}); |
|||
DB::table('despartamentos')->insert(['departamento'=> 'fw3f']); |
|||
DB::table('despartamentos')->insert(['departamento'=> 'wfaf']); |
|||
DB::table('despartamentos')->insert(['departamento'=> 'asef']); |
|||
DB::table('despartamentos')->insert(['departamento'=> 'FE fe']); |
|||
} |
|||
|
|||
/** |
|||
* Reverse the migrations. |
|||
*/ |
|||
public function down(): void |
|||
{ |
|||
Schema::dropIfExists('despartamentos'); |
|||
} |
|||
}; |
@ -0,0 +1,27 @@ |
|||
<?php |
|||
|
|||
use Illuminate\Database\Migrations\Migration; |
|||
use Illuminate\Database\Schema\Blueprint; |
|||
use Illuminate\Support\Facades\Schema; |
|||
|
|||
return new class extends Migration |
|||
{ |
|||
public function up() |
|||
{ |
|||
Schema::table('tipos_veiculos', function (Blueprint $table) { |
|||
if (!Schema::hasColumn('tipos_veiculos', 'plate')) { |
|||
$table->string('plate')->after('nombre')->nullable(); |
|||
} |
|||
if (!Schema::hasColumn('tipos_veiculos', 'model')) { |
|||
$table->string('model')->after('plate')->nullable(); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public function down() |
|||
{ |
|||
Schema::table('tipos_veiculos', function (Blueprint $table) { |
|||
$table->dropColumn(['plate', 'model']); |
|||
}); |
|||
} |
|||
}; |
@ -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() |
|||
{ |
|||
Schema::create('maintenances', function (Blueprint $table) { |
|||
$table->id(); |
|||
$table->foreignId('vehicle_id')->constrained('tipos_veiculos')->onDelete('cascade'); |
|||
$table->string('maintenance_type'); |
|||
$table->date('date'); |
|||
$table->text('description'); |
|||
$table->decimal('cost', 10, 2); |
|||
$table->enum('status', ['Pendiente', 'En Proceso', 'Completado'])->default('Pendiente'); |
|||
$table->date('next_maintenance_date')->nullable(); |
|||
$table->timestamps(); |
|||
}); |
|||
} |
|||
|
|||
public function down() |
|||
{ |
|||
Schema::dropIfExists('maintenances'); |
|||
} |
|||
}; |
@ -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('despartamentos', function (Blueprint $table) { |
|||
$table->boolean('eliminado')->default(false); |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Reverse the migrations. |
|||
*/ |
|||
public function down(): void |
|||
{ |
|||
Schema::table('despartamentos', function (Blueprint $table) { |
|||
$table->dropColumn('eliminado'); |
|||
}); |
|||
} |
|||
}; |
@ -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->enum('estado', ['pendiente', 'aceptado', 'rechazado'])->default('pendiente')->after('chofer'); |
|||
}); |
|||
} |
|||
|
|||
/** |
|||
* Reverse the migrations. |
|||
*/ |
|||
public function down(): void |
|||
{ |
|||
Schema::table('prestamos', function (Blueprint $table) { |
|||
$table->dropColumn('estado'); |
|||
}); |
|||
} |
|||
}; |
@ -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) { |
|||
// |
|||
}); |
|||
} |
|||
}; |
@ -0,0 +1,22 @@ |
|||
<?php |
|||
|
|||
use Illuminate\Database\Migrations\Migration; |
|||
use Illuminate\Database\Schema\Blueprint; |
|||
use Illuminate\Support\Facades\Schema; |
|||
|
|||
return new class extends Migration |
|||
{ |
|||
public function up() |
|||
{ |
|||
Schema::table('users', function (Blueprint $table) { |
|||
$table->string('rol')->default('usuario')->after('email'); |
|||
}); |
|||
} |
|||
|
|||
public function down() |
|||
{ |
|||
Schema::table('users', function (Blueprint $table) { |
|||
$table->dropColumn('rol'); |
|||
}); |
|||
} |
|||
}; |
@ -1,20 +0,0 @@ |
|||
use Illuminate\Database\Migrations\Migration; |
|||
use Illuminate\Database\Schema\Blueprint; |
|||
use Illuminate\Support\Facades\Schema; |
|||
|
|||
class AddFechaAceptacionToPrestamosTable extends Migration |
|||
{ |
|||
public function up() |
|||
{ |
|||
Schema::table('prestamos', function (Blueprint $table) { |
|||
$table->timestamp('fecha_aceptacion')->nullable()->after('estado'); |
|||
}); |
|||
} |
|||
|
|||
public function down() |
|||
{ |
|||
Schema::table('prestamos', function (Blueprint $table) { |
|||
$table->dropColumn('fecha_aceptacion'); |
|||
}); |
|||
} |
|||
} |
@ -0,0 +1,143 @@ |
|||
import React, { useState, useEffect } from 'react'; |
|||
import { Card, Row, Col, Button, Table, Alert } from 'react-bootstrap'; |
|||
import NewMaintenanceForm from './NewMaintenanceForm'; |
|||
import axios from 'axios'; |
|||
|
|||
const JorgeDashboard = () => { |
|||
const [maintenanceHistory, setMaintenanceHistory] = useState([]); |
|||
const [pendingAlerts, setPendingAlerts] = useState([]); |
|||
const [showNewMaintenanceForm, setShowNewMaintenanceForm] = useState(false); |
|||
const [vehicles, setVehicles] = useState([]); |
|||
const [loading, setLoading] = useState(true); |
|||
const [error, setError] = useState(null); |
|||
|
|||
useEffect(() => { |
|||
fetchData(); |
|||
}, []); |
|||
|
|||
const fetchData = async () => { |
|||
try { |
|||
setLoading(true); |
|||
const [historyRes, alertsRes, vehiclesRes] = await Promise.all([ |
|||
axios.get('/api/maintenance/history'), |
|||
axios.get('/api/maintenance/alerts'), |
|||
axios.get('/api/maintenance/vehicles') |
|||
]); |
|||
|
|||
setMaintenanceHistory(historyRes.data); |
|||
setPendingAlerts(alertsRes.data); |
|||
setVehicles(vehiclesRes.data); |
|||
setError(null); |
|||
} catch (err) { |
|||
setError('Error al cargar los datos. Por favor, intente nuevamente.'); |
|||
console.error('Error fetching data:', err); |
|||
} finally { |
|||
setLoading(false); |
|||
} |
|||
}; |
|||
|
|||
const handleNewMaintenance = async (formData) => { |
|||
try { |
|||
const response = await axios.post('/api/maintenance', formData); |
|||
setMaintenanceHistory(prev => [response.data.maintenance, ...prev]); |
|||
setShowNewMaintenanceForm(false); |
|||
} catch (err) { |
|||
setError('Error al guardar el mantenimiento. Por favor, intente nuevamente.'); |
|||
console.error('Error saving maintenance:', err); |
|||
} |
|||
}; |
|||
|
|||
if (loading) { |
|||
return <div className="text-center p-5">Cargando...</div>; |
|||
} |
|||
|
|||
if (error) { |
|||
return <Alert variant="danger">{error}</Alert>; |
|||
} |
|||
|
|||
return ( |
|||
<div className="container-fluid"> |
|||
<h2 className="mb-4">Panel de Control - Mantenimiento de Vehículos</h2> |
|||
|
|||
{/* Alertas Pendientes */} |
|||
<Row className="mb-4"> |
|||
<Col> |
|||
<Card> |
|||
<Card.Header> |
|||
<h4>Alertas de Mantenimiento Pendiente</h4> |
|||
</Card.Header> |
|||
<Card.Body> |
|||
{pendingAlerts.length === 0 ? ( |
|||
<Alert variant="success">No hay alertas pendientes</Alert> |
|||
) : ( |
|||
pendingAlerts.map(alert => ( |
|||
<Alert key={alert.id} variant="warning"> |
|||
<strong>{alert.vehicle.plate}</strong> - {alert.maintenance_type} pendiente para: {new Date(alert.next_maintenance_date).toLocaleDateString()} |
|||
</Alert> |
|||
)) |
|||
)} |
|||
</Card.Body> |
|||
</Card> |
|||
</Col> |
|||
</Row> |
|||
|
|||
{/* Historial de Mantenimientos */} |
|||
<Row> |
|||
<Col> |
|||
<Card> |
|||
<Card.Header className="d-flex justify-content-between align-items-center"> |
|||
<h4>Historial de Mantenimientos</h4> |
|||
<Button |
|||
variant="primary" |
|||
onClick={() => setShowNewMaintenanceForm(true)} |
|||
> |
|||
Nuevo Mantenimiento |
|||
</Button> |
|||
</Card.Header> |
|||
<Card.Body> |
|||
<Table striped bordered hover> |
|||
<thead> |
|||
<tr> |
|||
<th>Vehículo</th> |
|||
<th>Fecha</th> |
|||
<th>Tipo</th> |
|||
<th>Estado</th> |
|||
<th>Acciones</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
{maintenanceHistory.map(record => ( |
|||
<tr key={record.id}> |
|||
<td>{record.vehicle.plate}</td> |
|||
<td>{new Date(record.date).toLocaleDateString()}</td> |
|||
<td>{record.maintenance_type}</td> |
|||
<td>{record.status}</td> |
|||
<td> |
|||
<Button variant="info" size="sm" className="me-2"> |
|||
Ver Detalles |
|||
</Button> |
|||
<Button variant="secondary" size="sm"> |
|||
Editar |
|||
</Button> |
|||
</td> |
|||
</tr> |
|||
))} |
|||
</tbody> |
|||
</Table> |
|||
</Card.Body> |
|||
</Card> |
|||
</Col> |
|||
</Row> |
|||
|
|||
{/* Modal de Nuevo Mantenimiento */} |
|||
<NewMaintenanceForm |
|||
show={showNewMaintenanceForm} |
|||
handleClose={() => setShowNewMaintenanceForm(false)} |
|||
onSubmit={handleNewMaintenance} |
|||
vehicles={vehicles} |
|||
/> |
|||
</div> |
|||
); |
|||
}; |
|||
|
|||
export default JorgeDashboard; |
@ -0,0 +1,151 @@ |
|||
import React, { useState } from 'react'; |
|||
import { Modal, Form, Button } from 'react-bootstrap'; |
|||
|
|||
const NewMaintenanceForm = ({ show, handleClose, onSubmit, vehicles }) => { |
|||
const [formData, setFormData] = useState({ |
|||
vehicle_id: '', |
|||
maintenance_type: '', |
|||
date: '', |
|||
description: '', |
|||
cost: '', |
|||
status: 'Pendiente', |
|||
next_maintenance_date: '' |
|||
}); |
|||
|
|||
const handleChange = (e) => { |
|||
const { name, value } = e.target; |
|||
setFormData(prev => ({ |
|||
...prev, |
|||
[name]: value |
|||
})); |
|||
}; |
|||
|
|||
const handleSubmit = (e) => { |
|||
e.preventDefault(); |
|||
onSubmit(formData); |
|||
// Resetear el formulario |
|||
setFormData({ |
|||
vehicle_id: '', |
|||
maintenance_type: '', |
|||
date: '', |
|||
description: '', |
|||
cost: '', |
|||
status: 'Pendiente', |
|||
next_maintenance_date: '' |
|||
}); |
|||
}; |
|||
|
|||
return ( |
|||
<Modal show={show} onHide={handleClose}> |
|||
<Modal.Header closeButton> |
|||
<Modal.Title>Nuevo Registro de Mantenimiento</Modal.Title> |
|||
</Modal.Header> |
|||
<Modal.Body> |
|||
<Form onSubmit={handleSubmit}> |
|||
<Form.Group className="mb-3"> |
|||
<Form.Label>Vehículo</Form.Label> |
|||
<Form.Select |
|||
name="vehicle_id" |
|||
value={formData.vehicle_id} |
|||
onChange={handleChange} |
|||
required |
|||
> |
|||
<option value="">Seleccione un vehículo</option> |
|||
{vehicles.map(vehicle => ( |
|||
<option key={vehicle.id} value={vehicle.id}> |
|||
{vehicle.plate} - {vehicle.model} |
|||
</option> |
|||
))} |
|||
</Form.Select> |
|||
</Form.Group> |
|||
|
|||
<Form.Group className="mb-3"> |
|||
<Form.Label>Tipo de Mantenimiento</Form.Label> |
|||
<Form.Select |
|||
name="maintenance_type" |
|||
value={formData.maintenance_type} |
|||
onChange={handleChange} |
|||
required |
|||
> |
|||
<option value="">Seleccione un tipo</option> |
|||
<option value="Preventivo">Preventivo</option> |
|||
<option value="Correctivo">Correctivo</option> |
|||
<option value="Cambio de Aceite">Cambio de Aceite</option> |
|||
<option value="Revisión General">Revisión General</option> |
|||
</Form.Select> |
|||
</Form.Group> |
|||
|
|||
<Form.Group className="mb-3"> |
|||
<Form.Label>Fecha</Form.Label> |
|||
<Form.Control |
|||
type="date" |
|||
name="date" |
|||
value={formData.date} |
|||
onChange={handleChange} |
|||
required |
|||
/> |
|||
</Form.Group> |
|||
|
|||
<Form.Group className="mb-3"> |
|||
<Form.Label>Descripción</Form.Label> |
|||
<Form.Control |
|||
as="textarea" |
|||
rows={3} |
|||
name="description" |
|||
value={formData.description} |
|||
onChange={handleChange} |
|||
required |
|||
/> |
|||
</Form.Group> |
|||
|
|||
<Form.Group className="mb-3"> |
|||
<Form.Label>Costo</Form.Label> |
|||
<Form.Control |
|||
type="number" |
|||
step="0.01" |
|||
name="cost" |
|||
value={formData.cost} |
|||
onChange={handleChange} |
|||
required |
|||
/> |
|||
</Form.Group> |
|||
|
|||
<Form.Group className="mb-3"> |
|||
<Form.Label>Estado</Form.Label> |
|||
<Form.Select |
|||
name="status" |
|||
value={formData.status} |
|||
onChange={handleChange} |
|||
required |
|||
> |
|||
<option value="Pendiente">Pendiente</option> |
|||
<option value="En Proceso">En Proceso</option> |
|||
<option value="Completado">Completado</option> |
|||
</Form.Select> |
|||
</Form.Group> |
|||
|
|||
<Form.Group className="mb-3"> |
|||
<Form.Label>Próxima Fecha de Mantenimiento</Form.Label> |
|||
<Form.Control |
|||
type="date" |
|||
name="next_maintenance_date" |
|||
value={formData.next_maintenance_date} |
|||
onChange={handleChange} |
|||
/> |
|||
</Form.Group> |
|||
|
|||
<div className="d-flex justify-content-end gap-2"> |
|||
<Button variant="secondary" onClick={handleClose}> |
|||
Cancelar |
|||
</Button> |
|||
<Button variant="primary" type="submit"> |
|||
Guardar |
|||
</Button> |
|||
</div> |
|||
</Form> |
|||
</Modal.Body> |
|||
</Modal> |
|||
); |
|||
}; |
|||
|
|||
export default NewMaintenanceForm; |
@ -0,0 +1,10 @@ |
|||
import 'bootstrap/dist/css/bootstrap.min.css'; |
|||
import React from 'react'; |
|||
import { createRoot } from 'react-dom/client'; |
|||
import JorgeDashboard from './components/dashboard/JorgeDashboard'; |
|||
|
|||
const container = document.getElementById('maintenance-dashboard'); |
|||
if (container) { |
|||
const root = createRoot(container); |
|||
root.render(<JorgeDashboard />); |
|||
} |
@ -1,142 +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 Departamentos</h2> |
|||
<div class="flex items-center space-x-6"> |
|||
<!-- Íconos de agregar --> |
|||
<div class="flex space-x-4"> |
|||
<a href="{{ route('despartamentos.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('despartamentos.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 departamento --> |
|||
<a href="{{ route('despartamentos.create') }}" |
|||
class="text-blue-500 hover:text-blue-600 transition-colors duration-200" |
|||
title="Agregar nuevo departamento"> |
|||
<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('despartamentos.index') }}" method="GET" class="flex gap-2"> |
|||
<div class="relative w-full sm:w-64"> |
|||
<input type="text" |
|||
name="busqueda" |
|||
placeholder="Buscar departamento..." |
|||
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('despartamentos.index') }}" class="px-4 py-2 bg-gray-500 text-white rounded-lg hover:bg-gray-600"> |
|||
Limpiar |
|||
</a> |
|||
@endif |
|||
</form> |
|||
</div> |
|||
|
|||
<!-- Tabla de departamentos --> |
|||
<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">Departamento</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($despartamentos as $index => $despartamento) |
|||
<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-building text-blue-500 mr-2"></i> |
|||
{{ $despartamento->departamento }} |
|||
</td> |
|||
<td class="flex space-x-2 px-6 py-4 whitespace-nowrap text-sm"> |
|||
<a href="{{ route('despartamentos.edit', $despartamento->id) }}" |
|||
class="text-yellow-600 hover:text-yellow-700 transition-colors duration-200" |
|||
title="Editar departamento"> |
|||
<i class="fas fa-edit"></i> |
|||
</a> |
|||
<form action="{{ route('despartamentos.destroy', $despartamento->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 departamento"> |
|||
<i class="fas fa-trash"></i> |
|||
</a> |
|||
</form> |
|||
</td> |
|||
</tr> |
|||
@endforeach |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script> |
|||
// Desaparecer el mensaje después de 3 segundos |
|||
setTimeout(function() { |
|||
var message = document.getElementById('success-message'); |
|||
if (message) { |
|||
message.style.transition = 'opacity 0.5s ease'; |
|||
message.style.opacity = '0'; |
|||
setTimeout(function() { |
|||
message.remove(); |
|||
}, 500); |
|||
} |
|||
}, 3000); |
|||
|
|||
function confirmarEliminacion(button) { |
|||
Swal.fire({ |
|||
title: '¿Estás seguro?', |
|||
text: "Esta acción no se puede deshacer", |
|||
icon: 'warning', |
|||
showCancelButton: true, |
|||
confirmButtonColor: '#3085d6', |
|||
cancelButtonColor: '#d33', |
|||
confirmButtonText: 'Sí, eliminar', |
|||
cancelButtonText: 'Cancelar' |
|||
}).then((result) => { |
|||
if (result.isConfirmed) { |
|||
button.closest('form').submit(); |
|||
} |
|||
}); |
|||
} |
|||
</script> |
|||
@endsection |
@ -1,82 +0,0 @@ |
|||
@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($despartamento) ? 'Editar Departamento' : 'Nuevo Departamento' }} |
|||
</h2> |
|||
<div class="h-10 w-10 bg-blue-100 rounded-full flex items-center justify-center"> |
|||
<i class="fas fa-building text-blue-600"></i> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Mensajes de error --> |
|||
@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 |
|||
<!-- Formulario --> |
|||
<form id="despartamentoForm" |
|||
action="{{ isset($despartamento) ? route('despartamentos.update', $despartamento->id) : route('despartamentos.store') }}" |
|||
method="POST"> |
|||
@csrf |
|||
@if(isset($despartamento)) |
|||
@method('PUT') |
|||
@endif |
|||
|
|||
<div class="space-y-6"> |
|||
<!-- Campo Nombre --> |
|||
<div> |
|||
<label for="departamento" class="block text-sm font-medium text-gray-700 mb-2"> |
|||
Nombre del Departamento |
|||
</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="departamento" |
|||
id="departamento" |
|||
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 departamento" |
|||
value="{{ isset($despartamento) ? $despartamento->departamento : old('departamento') }}"> |
|||
</div> |
|||
@error('departamento') |
|||
<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('despartamentos.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($despartamento) ? 'Actualizar' : 'Guardar' }} |
|||
</button> |
|||
</div> |
|||
</div> |
|||
</form> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
@endsection |
@ -1,36 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<title>Departamentos</title> |
|||
<style> |
|||
table { |
|||
width: 100%; |
|||
border-collapse: collapse; |
|||
} |
|||
th, td { |
|||
border: 1px solid black; |
|||
padding: 8px; |
|||
text-align: left; |
|||
} |
|||
</style> |
|||
</head> |
|||
<body> |
|||
<h1>Lista de Departamentos</h1> |
|||
<table> |
|||
<thead> |
|||
<tr> |
|||
<th>ID</th> |
|||
<th>Departamento</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
@foreach($departamentos as $departamento) |
|||
<tr> |
|||
<td>{{ $departamento->id }}</td> |
|||
<td>{{ $departamento->departamento }}</td> |
|||
</tr> |
|||
@endforeach |
|||
</tbody> |
|||
</table> |
|||
</body> |
|||
</html> |
@ -0,0 +1,9 @@ |
|||
@extends('layouts.dashboard') |
|||
|
|||
@section('content') |
|||
<div id="maintenance-dashboard"></div> |
|||
@endsection |
|||
|
|||
@push('scripts') |
|||
@vite('resources/js/maintenance-dashboard.js') |
|||
@endpush |
@ -1,141 +0,0 @@ |
|||
@extends('layouts.dashboard') |
|||
|
|||
@section('content') |
|||
<div class="container mx-auto px-4 py-6"> |
|||
<!-- Mensajes de éxito/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"> |
|||
{{ session('success') }} |
|||
</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">Aceptar Prestamos</h2> |
|||
</div> |
|||
|
|||
<!-- Barra de búsqueda --> |
|||
<div class="p-4 border-b border-gray-200 bg-gray-50"> |
|||
<form action="{{ route('prestamos.aceptados') }}" 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.aceptados') }}" 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> |
|||
<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($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 }}</td> |
|||
<td class="px-6 py-4 whitespace-nowrap text-sm"> |
|||
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full |
|||
{{ $prestamo->estado === 'pendiente' ? 'bg-yellow-100 text-yellow-800' : |
|||
($prestamo->estado === 'aceptado' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800') }}"> |
|||
{{ ucfirst($prestamo->estado) }} |
|||
</span> |
|||
</td> |
|||
<td class="px-6 py-4 whitespace-nowrap text-sm"> |
|||
<div class="flex gap-2"> |
|||
@if($prestamo->estado === 'pendiente') |
|||
<form action="{{ route('prestamos.aceptar', $prestamo->id) }}" method="POST" class="inline"> |
|||
@csrf |
|||
<button type="submit" class="text-green-600 hover:text-green-900" title="Aceptar"> |
|||
<i class="fas fa-check"></i> |
|||
</button> |
|||
</form> |
|||
<form action="{{ route('prestamos.rechazar', $prestamo->id) }}" method="POST" class="inline"> |
|||
@csrf |
|||
<button type="submit" class="text-red-600 hover:text-red-900" title="Rechazar"> |
|||
<i class="fas fa-times"></i> |
|||
</button> |
|||
</form> |
|||
@else |
|||
<span class="text-gray-400"> |
|||
<i class="fas fa-check-circle"></i> |
|||
Procesado |
|||
</span> |
|||
@endif |
|||
</div> |
|||
</td> |
|||
</tr> |
|||
@endforeach |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script> |
|||
document.addEventListener('DOMContentLoaded', function() { |
|||
// Desaparecer mensaje de éxito |
|||
var message = document.getElementById('success-message'); |
|||
if (message) { |
|||
setTimeout(function() { |
|||
message.style.transition = 'opacity 0.5s ease'; |
|||
message.style.opacity = '0'; |
|||
setTimeout(function() { |
|||
message.remove(); |
|||
}, 500); |
|||
}, 3000); |
|||
} |
|||
}); |
|||
</script> |
|||
@endsection |
@ -1,160 +0,0 @@ |
|||
@extends('layouts.dashboard') |
|||
|
|||
@section('content') |
|||
<div class="container mx-auto px-4 py-6"> |
|||
<!-- Mensajes de éxito/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"> |
|||
{{ session('success') }} |
|||
</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">Historial de Préstamos</h2> |
|||
|
|||
<!-- Botones de exportación --> |
|||
<div class="flex gap-2"> |
|||
<a href="{{ route('prestamos.export', ['format' => 'excel']) }}" class="text-gray-600 hover:text-green-700 p-2" title="Exportar a Excel"> |
|||
<i class="fas fa-file-excel"></i> |
|||
</a> |
|||
<a href="{{ route('prestamos.export', ['format' => 'pdf']) }}" class="text-gray-600 hover:text-red-600 p-2" title="Exportar a PDF"> |
|||
<i class="fas fa-file-pdf"></i> |
|||
</a> |
|||
<button onclick="window.print()" class="text-gray-600 hover:text-gray-800 p-2" title="Imprimir"> |
|||
<i class="fas fa-print"></i> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Barra de búsqueda y filtros --> |
|||
<div class="p-4 border-b border-gray-200 bg-gray-50"> |
|||
<form action="{{ route('prestamos.historial') }}" method="GET" class="flex flex-wrap gap-4"> |
|||
<div class="relative flex-1 min-w-[200px]"> |
|||
<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> |
|||
|
|||
<!-- Filtro de estado --> |
|||
<select name="estado" class="border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> |
|||
<option value="">Todos los estados</option> |
|||
<option value="aceptado" {{ request('estado') === 'aceptado' ? 'selected' : '' }}>Aceptados</option> |
|||
<option value="rechazado" {{ request('estado') === 'rechazado' ? 'selected' : '' }}>Rechazados</option> |
|||
</select> |
|||
|
|||
<!-- Filtro de fechas --> |
|||
<input type="date" |
|||
name="fecha_desde" |
|||
value="{{ request('fecha_desde') }}" |
|||
class="border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500" |
|||
placeholder="Fecha desde"> |
|||
|
|||
<input type="date" |
|||
name="fecha_hasta" |
|||
value="{{ request('fecha_hasta') }}" |
|||
class="border border-gray-300 rounded-lg px-4 py-2 focus:ring-2 focus:ring-blue-500 focus:border-blue-500" |
|||
placeholder="Fecha hasta"> |
|||
|
|||
<button type="submit" class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600"> |
|||
Filtrar |
|||
</button> |
|||
|
|||
@if(request('busqueda') || request('estado') || request('fecha_desde') || request('fecha_hasta')) |
|||
<a href="{{ route('prestamos.historial') }}" 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> |
|||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Fecha Actualización</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody class="bg-white divide-y divide-gray-200"> |
|||
@foreach($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 }}</td> |
|||
<td class="px-6 py-4 whitespace-nowrap text-sm"> |
|||
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full |
|||
{{ $prestamo->estado === 'aceptado' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800' }}"> |
|||
{{ ucfirst($prestamo->estado) }} |
|||
</span> |
|||
</td> |
|||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500"> |
|||
{{ \Carbon\Carbon::parse($prestamo->updated_at)->format('d/m/Y H:i') }} |
|||
</td> |
|||
</tr> |
|||
@endforeach |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
|
|||
<!-- Paginación --> |
|||
<div class="px-6 py-4 border-t border-gray-200"> |
|||
{{ $prestamos->links() }} |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script> |
|||
document.addEventListener('DOMContentLoaded', function() { |
|||
// Desaparecer mensaje de éxito |
|||
var message = document.getElementById('success-message'); |
|||
if (message) { |
|||
setTimeout(function() { |
|||
message.style.transition = 'opacity 0.5s ease'; |
|||
message.style.opacity = '0'; |
|||
setTimeout(function() { |
|||
message.remove(); |
|||
}, 500); |
|||
}, 3000); |
|||
} |
|||
}); |
|||
</script> |
|||
@endsection |
Loading…
Reference in new issue