259 lines
11 KiB
PHP
259 lines
11 KiB
PHP
<?php
|
|
$page_title = 'Panel de Control';
|
|
require_once __DIR__ . '/includes/header.php';
|
|
require_once __DIR__ . '/db/config.php';
|
|
|
|
// Proteger la página: si el usuario no ha iniciado sesión, redirigir a login
|
|
if (!is_logged_in()) {
|
|
header('Location: /auth/login.php');
|
|
exit();
|
|
}
|
|
|
|
// Obtener el número total de productos
|
|
$pdo = db();
|
|
$stmt = $pdo->query("SELECT COUNT(*) FROM productos");
|
|
$total_products = $stmt->fetchColumn();
|
|
|
|
// Obtener stock por ciudad y producto, ordenando las ciudades por stock total
|
|
$stock_stmt = $pdo->query("
|
|
SELECT
|
|
c.nombre AS ciudad,
|
|
p.nombre AS producto,
|
|
s.stock_actual
|
|
FROM
|
|
stock_por_ciudad s
|
|
JOIN
|
|
ciudades c ON s.ciudad_id = c.id
|
|
JOIN
|
|
productos p ON s.producto_id = p.id
|
|
JOIN
|
|
(SELECT ciudad_id, SUM(stock_actual) as total_stock FROM stock_por_ciudad GROUP BY ciudad_id) as stock_totales
|
|
ON c.id = stock_totales.ciudad_id
|
|
WHERE
|
|
s.stock_actual > 0
|
|
ORDER BY
|
|
stock_totales.total_stock DESC, p.nombre;
|
|
");
|
|
$stock_data = $stock_stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// Agrupar por ciudad
|
|
$stock_por_ciudad = [];
|
|
foreach ($stock_data as $row) {
|
|
$stock_por_ciudad[$row['ciudad']][] = [
|
|
'producto' => $row['producto'],
|
|
'stock' => $row['stock_actual']
|
|
];
|
|
}
|
|
|
|
?>
|
|
|
|
<div class="container-fluid">
|
|
<!-- Mensaje de Bienvenida -->
|
|
<div class="row mb-4">
|
|
<div class="col-12 text-center">
|
|
<h1 class="welcome-title">Bienvenido a tu Panel de Control</h1>
|
|
<p class="welcome-subtitle">Aquí tienes un resumen de tu aplicación.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row justify-content-center">
|
|
<!-- Tarjeta de Total de Productos -->
|
|
<div class="col-md-6 col-lg-4 mb-4">
|
|
<div class="card info-card h-100">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center">
|
|
<div class="icon-circle">
|
|
<!-- Icono de Caja (Productos) -->
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-box"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path><polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline><line x1="12" y1="22.08" x2="12" y2="12"></line></svg>
|
|
</div>
|
|
<div class="ms-3">
|
|
<h5 class="card-title">Total de Productos</h5>
|
|
<p class="card-text"><?php echo $total_products; ?></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tarjeta de Acceso a Productos -->
|
|
<div class="col-md-6 col-lg-4 mb-4">
|
|
<a href="productos.php" class="card-link">
|
|
<div class="card info-card h-100">
|
|
<div class="card-body">
|
|
<div class="d-flex align-items-center">
|
|
<div class="icon-circle">
|
|
<!-- Icono de Tareas (Administrar) -->
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-settings"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
|
|
</div>
|
|
<div class="ms-3">
|
|
<h5 class="card-title">Administrar Productos</h5>
|
|
<p class="card-text">Ir a la lista de productos</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Tarjeta de Gráfico de Stock -->
|
|
<div class="col-md-12 col-lg-4 mb-4">
|
|
<div class="card info-card h-100">
|
|
<div class="card-body">
|
|
<h5 class="card-title text-center">Distribución de Stock</h5>
|
|
<div style="height: 300px;">
|
|
<canvas id="stockChart"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row justify-content-center">
|
|
<!-- Tarjeta de Stock por Ciudad y Producto -->
|
|
<div class="col-md-12 col-lg-8 mb-4">
|
|
<div class="card info-card h-100">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Stock por Ciudad y Producto</h5>
|
|
<div class="accordion" id="stockAccordion">
|
|
<?php if (empty($stock_por_ciudad)): ?>
|
|
<p class="text-center mt-3">No hay datos de stock disponibles.</p>
|
|
<?php else: ?>
|
|
<?php
|
|
$i = 0;
|
|
foreach ($stock_por_ciudad as $ciudad => $productos):
|
|
$ciudad_id = 'ciudad_' . $i++;
|
|
?>
|
|
<div class="accordion-item">
|
|
<h2 class="accordion-header" id="heading-<?php echo $ciudad_id; ?>">
|
|
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-<?php echo $ciudad_id; ?>" aria-expanded="false" aria-controls="collapse-<?php echo $ciudad_id; ?>">
|
|
<?php echo htmlspecialchars($ciudad); ?>
|
|
</button>
|
|
</h2>
|
|
<div id="collapse-<?php echo $ciudad_id; ?>" class="accordion-collapse collapse" aria-labelledby="heading-<?php echo $ciudad_id; ?>" data-bs-parent="#stockAccordion">
|
|
<div class="accordion-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-sm table-hover">
|
|
<thead>
|
|
<tr>
|
|
<th>Producto</th>
|
|
<th>Stock</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($productos as $producto): ?>
|
|
<tr>
|
|
<td><?php echo htmlspecialchars($producto['producto']); ?></td>
|
|
<td><?php echo htmlspecialchars($producto['stock']); ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php
|
|
// Preparar datos para el gráfico
|
|
$chart_labels = [];
|
|
$chart_data = [];
|
|
$chart_bg_colors = []; // Array para los colores de fondo
|
|
$chart_border_colors = []; // Array para los colores de borde
|
|
|
|
// Paleta de colores (puedes añadir más si tienes muchas ciudades)
|
|
$color_palette_bg = [
|
|
'rgba(54, 162, 235, 0.8)', // Azul
|
|
'rgba(255, 206, 86, 0.8)', // Amarillo
|
|
'rgba(75, 192, 192, 0.8)', // Turquesa
|
|
'rgba(153, 102, 255, 0.8)',// Morado
|
|
'rgba(255, 99, 132, 0.8)', // Rojo
|
|
'rgba(255, 159, 64, 0.8)' // Naranja
|
|
];
|
|
$color_palette_border = [
|
|
'rgba(54, 162, 235, 1)',
|
|
'rgba(255, 206, 86, 1)',
|
|
'rgba(75, 192, 192, 1)',
|
|
'rgba(153, 102, 255, 1)',
|
|
'rgba(255, 99, 132, 1)',
|
|
'rgba(255, 159, 64, 1)'
|
|
];
|
|
|
|
// Asignar verde a Lima
|
|
$city_color_map = [
|
|
'Lima' => [
|
|
'bg' => 'rgba(40, 167, 69, 0.8)', // Verde fondo
|
|
'border' => 'rgba(40, 167, 69, 1)' // Verde borde
|
|
]
|
|
];
|
|
|
|
if (!empty($stock_por_ciudad)) {
|
|
$color_index = 0;
|
|
foreach ($stock_por_ciudad as $ciudad => $productos) {
|
|
$chart_labels[] = $ciudad;
|
|
|
|
// Asignar color
|
|
if (isset($city_color_map[$ciudad])) {
|
|
$chart_bg_colors[] = $city_color_map[$ciudad]['bg'];
|
|
$chart_border_colors[] = $city_color_map[$ciudad]['border'];
|
|
} else {
|
|
// Asignar un color de la paleta
|
|
$chart_bg_colors[] = $color_palette_bg[$color_index % count($color_palette_bg)];
|
|
$chart_border_colors[] = $color_palette_border[$color_index % count($color_palette_border)];
|
|
$color_index++;
|
|
}
|
|
|
|
$total_stock = 0;
|
|
foreach ($productos as $producto) {
|
|
$total_stock += $producto['stock'];
|
|
}
|
|
$chart_data[] = $total_stock;
|
|
}
|
|
}
|
|
?>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
const ctx = document.getElementById('stockChart');
|
|
if (ctx && <?php echo json_encode(!empty($chart_data)); ?>) {
|
|
new Chart(ctx, {
|
|
type: 'pie',
|
|
data: {
|
|
labels: <?php echo json_encode($chart_labels); ?>,
|
|
datasets: [{
|
|
label: 'Stock Total',
|
|
data: <?php echo json_encode($chart_data); ?>,
|
|
backgroundColor: <?php echo json_encode($chart_bg_colors); ?>,
|
|
borderColor: <?php echo json_encode($chart_border_colors); ?>,
|
|
borderWidth: 1
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
plugins: {
|
|
legend: {
|
|
position: 'bottom',
|
|
},
|
|
title: {
|
|
display: false,
|
|
}
|
|
}
|
|
}
|
|
});
|
|
} else if (ctx) {
|
|
ctx.getContext('2d').fillText("No hay datos de stock para mostrar.", ctx.width / 2 - 50, ctx.height / 2);
|
|
}
|
|
});
|
|
</script>
|
|
|
|
<?php
|
|
require_once __DIR__ . '/includes/footer.php';
|
|
?>
|