cambios imagenes en el catalogo, permisos al empleado para que pued agregar clientes y arreglos en la vista del report
This commit is contained in:
@@ -38,7 +38,7 @@ class ClientController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function create()
|
public function create()
|
||||||
{
|
{
|
||||||
$this->checkAdmin();
|
//$this->checkAdmin();
|
||||||
return view('clients.create');
|
return view('clients.create');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ class ClientController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
$this->checkAdmin();
|
//$this->checkAdmin();
|
||||||
$validated = $request->validate([
|
$validated = $request->validate([
|
||||||
'name' => ['required', 'string', 'max:255', 'not_regex:/[0-9]/'],
|
'name' => ['required', 'string', 'max:255', 'not_regex:/[0-9]/'],
|
||||||
'phone' => 'nullable|string|max:50',
|
'phone' => 'nullable|string|max:50',
|
||||||
|
|||||||
@@ -120,7 +120,7 @@
|
|||||||
{{-- Imagen si existe --}}
|
{{-- Imagen si existe --}}
|
||||||
@if (!empty($product->image_path))
|
@if (!empty($product->image_path))
|
||||||
<img src="{{ asset('storage/' . $product->image_path) }}" alt="{{ $product->name }}"
|
<img src="{{ asset('storage/' . $product->image_path) }}" alt="{{ $product->name }}"
|
||||||
class="w-full h-40 object-cover rounded mb-4">
|
class="w-full h-40 object-contain bg-white p-2 rounded mb-4">
|
||||||
@else
|
@else
|
||||||
<div class="w-full border border-neutral-200 dark:border-neutral-800 h-40 bg-stone-200 dark:bg-stone-900 flex items-center justify-center rounded mb-4">
|
<div class="w-full border border-neutral-200 dark:border-neutral-800 h-40 bg-stone-200 dark:bg-stone-900 flex items-center justify-center rounded mb-4">
|
||||||
<span class="text-lime-800 dark:text-neon-lime text-md uppercase font-bold">Sin imagen</span>
|
<span class="text-lime-800 dark:text-neon-lime text-md uppercase font-bold">Sin imagen</span>
|
||||||
|
|||||||
@@ -21,15 +21,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
@if(auth()->user()->role === 'admin')
|
<form action="{{ route('clients.index') }}" method="GET" class="w-full md:w-1/2">
|
||||||
<a href="{{ route('clients.create') }}" class="w-full md:w-auto text-center px-5 py-3 text-sm font-bold text-neon-lime dark:text-neutral-900 bg-neutral-950 dark:bg-neon-lime rounded-lg hover:bg-neutral-900/80 hover:dark:bg-[#b3e600] transition-colors uppercase tracking-wide">
|
</form>
|
||||||
+ Nuevo Cliente
|
|
||||||
</a>
|
<a href="{{ route('clients.create') }}" class="w-full md:w-auto text-center px-5 py-3 text-sm font-bold text-neon-lime dark:text-neutral-900 bg-neutral-950 dark:bg-neon-lime rounded-lg hover:bg-neutral-900/80 hover:dark:bg-[#b3e600] transition-colors uppercase tracking-wide">
|
||||||
@else
|
+ Nuevo Cliente
|
||||||
<span title="Acceso denegado" class="w-full md:w-auto text-center px-5 py-3 text-sm font-bold text-gray-500 dark:text-neutral-500 bg-gray-300 dark:bg-neutral-800 border border-gray-400 dark:border-neutral-700 rounded-lg cursor-not-allowed pointer-events-none select-none uppercase tracking-wide">
|
</a>
|
||||||
+ Nuevo Cliente
|
</div>
|
||||||
</span>
|
|
||||||
@endif
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="relative overflow-x-auto shadow-md sm:rounded-lg border border-gray-400 dark:border-neutral-800 w-full">
|
<div class="relative overflow-x-auto shadow-md sm:rounded-lg border border-gray-400 dark:border-neutral-800 w-full">
|
||||||
|
|||||||
@@ -169,7 +169,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
|
<details class="group bg-white dark:bg-neutral-900 border border-gray-200 dark:border-neutral-800 rounded-lg shadow-sm [&_summary::-webkit-details-marker]:hidden">
|
||||||
|
<summary class="flex items-center justify-between p-5 cursor-pointer font-semibold text-gray-900 dark:text-white transition-colors hover:bg-gray-50 dark:hover:bg-neutral-800/50 rounded-lg">
|
||||||
|
<span>¿Qué diferencias de permisos hay entre Administrador y Empleado?</span>
|
||||||
|
<span class="transition-transform duration-300 group-open:-rotate-180 text-gray-500">
|
||||||
|
<svg fill="none" height="24" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" viewBox="0 0 24 24" width="24"><path d="M6 9l6 6 6-6"></path></svg>
|
||||||
|
</span>
|
||||||
|
</summary>
|
||||||
|
<div class="px-5 pb-5 pt-2 text-gray-600 dark:text-gray-400 border-t border-gray-100 dark:border-neutral-800/50 space-y-3">
|
||||||
|
<p>El sistema cuenta con dos niveles de acceso para garantizar la seguridad de la información:</p>
|
||||||
|
<ul class="list-disc pl-5 space-y-1">
|
||||||
|
<li><strong>Administrador (Dueño):</strong> Tiene control total del sistema. Posee acceso exclusivo al módulo de personal (para dar de alta, baja o modificar empleados). Además, es el <strong>único</strong> autorizado para modificar o eliminar registros en el sistema (productos, clientes, proveedores, etc.).</li>
|
||||||
|
<li><strong>Empleado:</strong> Tiene un acceso diseñado específicamente para la operatoria diaria del local. Puede agregar nuevos registros (crear ventas, cargar clientes nuevos, agendar turnos en el taller), pero <strong>no puede modificar ni eliminar</strong> información ya guardada.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
<div id="contact" class="mt-8 p-6 bg-lime-50 dark:bg-lime-900/10 border border-lime-200 dark:border-lime-900/30 rounded-xl text-center shadow-sm">
|
<div id="contact" class="mt-8 p-6 bg-lime-50 dark:bg-lime-900/10 border border-lime-200 dark:border-lime-900/30 rounded-xl text-center shadow-sm">
|
||||||
<h3 class="text-lg font-bold text-lime-800 dark:text-neon-lime mb-2">¿Necesitas más ayuda?</h3>
|
<h3 class="text-lg font-bold text-lime-800 dark:text-neon-lime mb-2">¿Necesitas más ayuda?</h3>
|
||||||
<p class="text-sm text-lime-700 dark:text-gray-400 mb-5">Si tienes alguna otra duda o experimentas problemas técnicos, nuestro equipo de soporte está disponible para ayudarte.</p>
|
<p class="text-sm text-lime-700 dark:text-gray-400 mb-5">Si tienes alguna otra duda o experimentas problemas técnicos, nuestro equipo de soporte está disponible para ayudarte.</p>
|
||||||
|
|||||||
@@ -3,9 +3,7 @@
|
|||||||
|
|
||||||
<div class="w-full mx-auto pb-10">
|
<div class="w-full mx-auto pb-10">
|
||||||
|
|
||||||
<!-- Tarjetas de Resumen -->
|
|
||||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
||||||
<!-- Ingresos -->
|
|
||||||
<div class="bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-6 shadow-lg">
|
<div class="bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-6 shadow-lg">
|
||||||
<div class="flex justify-between items-start">
|
<div class="flex justify-between items-start">
|
||||||
<div>
|
<div>
|
||||||
@@ -19,7 +17,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Egresos -->
|
|
||||||
<div class="bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-6 shadow-lg">
|
<div class="bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-6 shadow-lg">
|
||||||
<div class="flex justify-between items-start">
|
<div class="flex justify-between items-start">
|
||||||
<div>
|
<div>
|
||||||
@@ -33,7 +30,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Balance -->
|
|
||||||
<div class="bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-6 shadow-lg">
|
<div class="bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-6 shadow-lg">
|
||||||
<div class="flex justify-between items-start">
|
<div class="flex justify-between items-start">
|
||||||
<div>
|
<div>
|
||||||
@@ -50,7 +46,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Gráfico de Evolución -->
|
|
||||||
<div class="mb-6 bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-6 shadow-lg">
|
<div class="mb-6 bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-6 shadow-lg">
|
||||||
<h3 class="text-lg font-bold text-neutral-900 dark:text-white mb-4">Evolución de Ingresos y Egresos (Últimos 6 meses)</h3>
|
<h3 class="text-lg font-bold text-neutral-900 dark:text-white mb-4">Evolución de Ingresos y Egresos (Últimos 6 meses)</h3>
|
||||||
<div class="relative h-72 w-full">
|
<div class="relative h-72 w-full">
|
||||||
@@ -58,9 +53,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Gráficos de Torta (Distribución) -->
|
|
||||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||||
<!-- Gráfico de Torta Ingresos -->
|
|
||||||
<div class="bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-6 shadow-lg">
|
<div class="bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-6 shadow-lg">
|
||||||
<h3 class="text-lg font-bold text-neutral-900 dark:text-white mb-4">Ingresos por Categoría</h3>
|
<h3 class="text-lg font-bold text-neutral-900 dark:text-white mb-4">Ingresos por Categoría</h3>
|
||||||
<div class="relative h-72 w-full flex justify-center">
|
<div class="relative h-72 w-full flex justify-center">
|
||||||
@@ -68,7 +61,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Gráfico de Torta Gastos -->
|
|
||||||
<div class="bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-6 shadow-lg">
|
<div class="bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-6 shadow-lg">
|
||||||
<h3 class="text-lg font-bold text-neutral-900 dark:text-white mb-4">Gastos por Categoría</h3>
|
<h3 class="text-lg font-bold text-neutral-900 dark:text-white mb-4">Gastos por Categoría</h3>
|
||||||
<div class="relative h-72 w-full flex justify-center">
|
<div class="relative h-72 w-full flex justify-center">
|
||||||
@@ -77,26 +69,21 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Nuevas Métricas -->
|
|
||||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mt-6">
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mt-6">
|
||||||
|
|
||||||
<!-- Top 5 Productos -->
|
|
||||||
<div class="bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-6 shadow-lg">
|
<div class="bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-6 shadow-lg">
|
||||||
<h3 class="text-lg font-bold text-neutral-900 dark:text-white mb-4">Top 5 Productos Vendidos</h3>
|
<h3 class="text-lg font-bold text-neutral-900 dark:text-white mb-4">Top 5 Productos Vendidos</h3>
|
||||||
<div class="relative h-64 w-full">
|
<div class="relative h-96 w-full">
|
||||||
<canvas id="topProductsChart"></canvas>
|
<canvas id="topProductsChart"></canvas>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Top 5 Repuestos -->
|
|
||||||
<div class="bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-6 shadow-lg">
|
<div class="bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-6 shadow-lg">
|
||||||
<h3 class="text-lg font-bold text-neutral-900 dark:text-white mb-4">Top 5 Repuestos Usados</h3>
|
<h3 class="text-lg font-bold text-neutral-900 dark:text-white mb-4">Top 5 Repuestos Usados</h3>
|
||||||
<div class="relative h-64 w-full">
|
<div class="relative h-96 w-full">
|
||||||
<canvas id="topSparesChart"></canvas>
|
<canvas id="topSparesChart"></canvas> </div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Top Clientes -->
|
|
||||||
<div class="bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-6 shadow-lg">
|
<div class="bg-gray-200 dark:bg-panel-bg border border-neutral-400 dark:border-neutral-800 rounded-xl p-6 shadow-lg">
|
||||||
<h3 class="text-lg font-bold text-neutral-900 dark:text-white mb-4">Mejores Clientes</h3>
|
<h3 class="text-lg font-bold text-neutral-900 dark:text-white mb-4">Mejores Clientes</h3>
|
||||||
<ul class="space-y-4">
|
<ul class="space-y-4">
|
||||||
@@ -121,7 +108,6 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Cargar Chart.js desde CDN -->
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -131,6 +117,27 @@
|
|||||||
const textColor = isDark ? '#e5e7eb' : '#111827';
|
const textColor = isDark ? '#e5e7eb' : '#111827';
|
||||||
const gridColor = isDark ? '#374151' : '#d1d5db';
|
const gridColor = isDark ? '#374151' : '#d1d5db';
|
||||||
|
|
||||||
|
// NUEVA FUNCIÓN: Agrupa textos largos en múltiples líneas
|
||||||
|
const agruparTexto = (texto, maxCaracteres = 22) => {
|
||||||
|
if (!texto) return 'Eliminado';
|
||||||
|
if (texto.length <= maxCaracteres) return texto;
|
||||||
|
|
||||||
|
let palabras = texto.split(' ');
|
||||||
|
let lineas = [];
|
||||||
|
let lineaActual = '';
|
||||||
|
|
||||||
|
palabras.forEach(palabra => {
|
||||||
|
if ((lineaActual + palabra).length > maxCaracteres) {
|
||||||
|
lineas.push(lineaActual.trim());
|
||||||
|
lineaActual = palabra + ' ';
|
||||||
|
} else {
|
||||||
|
lineaActual += palabra + ' ';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (lineaActual) lineas.push(lineaActual.trim());
|
||||||
|
return lineas;
|
||||||
|
};
|
||||||
|
|
||||||
// --- GRÁFICO DE BALANCE (Barras) ---
|
// --- GRÁFICO DE BALANCE (Barras) ---
|
||||||
const ctxBalance = document.getElementById('balanceChart').getContext('2d');
|
const ctxBalance = document.getElementById('balanceChart').getContext('2d');
|
||||||
const months = @json($months);
|
const months = @json($months);
|
||||||
@@ -269,7 +276,7 @@
|
|||||||
new Chart(ctxTopProducts, {
|
new Chart(ctxTopProducts, {
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
data: {
|
data: {
|
||||||
labels: rawTopProducts.map(i => i.product ? i.product.name : 'Eliminado'),
|
labels: rawTopProducts.map(i => agruparTexto(i.product ? i.product.name : 'Eliminado')),
|
||||||
datasets: [{
|
datasets: [{
|
||||||
label: 'Cantidad Vendida',
|
label: 'Cantidad Vendida',
|
||||||
data: rawTopProducts.map(i => i.total_qty),
|
data: rawTopProducts.map(i => i.total_qty),
|
||||||
@@ -286,7 +293,7 @@
|
|||||||
plugins: { legend: { display: false } },
|
plugins: { legend: { display: false } },
|
||||||
scales: {
|
scales: {
|
||||||
x: { ticks: { color: textColor }, grid: { color: gridColor, drawBorder: false } },
|
x: { ticks: { color: textColor }, grid: { color: gridColor, drawBorder: false } },
|
||||||
y: { ticks: { color: textColor }, grid: { display: false } }
|
y: { ticks: { color: textColor, autoSkip: false }, grid: { display: false } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -298,7 +305,7 @@
|
|||||||
new Chart(ctxTopSpares, {
|
new Chart(ctxTopSpares, {
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
data: {
|
data: {
|
||||||
labels: rawTopSpares.map(i => i.product ? i.product.name : 'Eliminado'),
|
labels: rawTopSpares.map(i => agruparTexto(i.product ? i.product.name : 'Eliminado')),
|
||||||
datasets: [{
|
datasets: [{
|
||||||
label: 'Cantidad Usada/Vendida',
|
label: 'Cantidad Usada/Vendida',
|
||||||
data: rawTopSpares.map(i => i.total_qty),
|
data: rawTopSpares.map(i => i.total_qty),
|
||||||
@@ -315,11 +322,11 @@
|
|||||||
plugins: { legend: { display: false } },
|
plugins: { legend: { display: false } },
|
||||||
scales: {
|
scales: {
|
||||||
x: { ticks: { color: textColor }, grid: { color: gridColor, drawBorder: false } },
|
x: { ticks: { color: textColor }, grid: { color: gridColor, drawBorder: false } },
|
||||||
y: { ticks: { color: textColor }, grid: { display: false } }
|
y: { ticks: { color: textColor, autoSkip: false }, grid: { display: false } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</x-layout>
|
</x-layout>
|
||||||
Reference in New Issue
Block a user