Autosave: 20260518-171536
This commit is contained in:
parent
4048403247
commit
515395635b
BIN
assets/uploads/marketing_images/6a0b459229e98.png
Normal file
BIN
assets/uploads/marketing_images/6a0b459229e98.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
BIN
assets/uploads/marketing_images/6a0b4592b821f.png
Normal file
BIN
assets/uploads/marketing_images/6a0b4592b821f.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
BIN
assets/uploads/vouchers/6a0b420ae0091-2438.png
Normal file
BIN
assets/uploads/vouchers/6a0b420ae0091-2438.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 315 KiB |
BIN
assets/uploads/vouchers/6a0b448cdb0b7-4848.png
Normal file
BIN
assets/uploads/vouchers/6a0b448cdb0b7-4848.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 349 KiB |
BIN
assets/uploads/vouchers/6a0b4509e9eba-9494.png
Normal file
BIN
assets/uploads/vouchers/6a0b4509e9eba-9494.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 619 KiB |
BIN
assets/uploads/vouchers/6a0b4591572e5-468.png
Normal file
BIN
assets/uploads/vouchers/6a0b4591572e5-468.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 374 KiB |
@ -195,6 +195,40 @@ $stmtTopDetalleCE = $db->query("
|
|||||||
");
|
");
|
||||||
$topProductosDetalleCE = $stmtTopDetalleCE->fetchAll(PDO::FETCH_ASSOC);
|
$topProductosDetalleCE = $stmtTopDetalleCE->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// 14. Rendimiento de Productos en Contraentrega (Para Gráfica de Barras Apiladas)
|
||||||
|
$stmtProdRendimientoCE = $db->query("
|
||||||
|
SELECT
|
||||||
|
producto,
|
||||||
|
COUNT(CASE WHEN estado = 'ENTREGA EXITOSA' THEN 1 END) as exitosas,
|
||||||
|
COUNT(CASE WHEN estado = 'RETORNADO' THEN 1 END) as retornados,
|
||||||
|
COUNT(CASE WHEN estado = 'RUTA_CONTRAENTREGA' THEN 1 END) as en_ruta,
|
||||||
|
COUNT(*) as total
|
||||||
|
FROM pedidos p
|
||||||
|
WHERE $date_condition
|
||||||
|
AND (estado IN ('RUTA_CONTRAENTREGA', 'ENTREGA EXITOSA') OR (estado = 'RETORNADO' AND agencia = 'CONTRAENTREGA'))
|
||||||
|
GROUP BY producto
|
||||||
|
ORDER BY total DESC
|
||||||
|
LIMIT 10
|
||||||
|
");
|
||||||
|
$prodRendimientoCE = $stmtProdRendimientoCE->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// 15. Rendimiento de Productos en Provincia
|
||||||
|
$stmtProdRendimientoProv = $db->query("
|
||||||
|
SELECT
|
||||||
|
producto,
|
||||||
|
COUNT(CASE WHEN estado = 'COMPLETADO ✅' THEN 1 END) as completados,
|
||||||
|
COUNT(CASE WHEN estado = 'GESTIONES' THEN 1 END) as gestiones,
|
||||||
|
COUNT(CASE WHEN estado IN ('ROTULADO 📦', 'EN TRANSITO 🚛', 'EN DESTINO 🏬') THEN 1 END) as en_proceso,
|
||||||
|
COUNT(*) as total
|
||||||
|
FROM pedidos p
|
||||||
|
WHERE $date_condition
|
||||||
|
AND NOT (estado IN ('RUTA_CONTRAENTREGA', 'ENTREGA EXITOSA') OR (estado = 'RETORNADO' AND agencia = 'CONTRAENTREGA'))
|
||||||
|
GROUP BY producto
|
||||||
|
ORDER BY total DESC
|
||||||
|
LIMIT 10
|
||||||
|
");
|
||||||
|
$prodRendimientoProv = $stmtProdRendimientoProv->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
$canalesResumen = [
|
$canalesResumen = [
|
||||||
'Provincia' => ['pedidos' => 0, 'monto' => 0, 'estados' => []],
|
'Provincia' => ['pedidos' => 0, 'monto' => 0, 'estados' => []],
|
||||||
'Contraentrega' => ['pedidos' => 0, 'monto' => 0, 'estados' => []]
|
'Contraentrega' => ['pedidos' => 0, 'monto' => 0, 'estados' => []]
|
||||||
@ -384,7 +418,7 @@ include 'layout_header.php';
|
|||||||
<span class="badge bg-primary text-white">Distribución Interna</span>
|
<span class="badge bg-primary text-white">Distribución Interna</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body d-flex flex-column align-items-center justify-content-center" style="min-height: 300px;">
|
<div class="card-body d-flex flex-column align-items-center justify-content-center" style="min-height: 300px;">
|
||||||
<div style="width: 100%; max-width: 280px;">
|
<div style="width: 100%; max-width: 450px;">
|
||||||
<canvas id="provinciaPieChart"></canvas>
|
<canvas id="provinciaPieChart"></canvas>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-3 text-center">
|
<div class="mt-3 text-center">
|
||||||
@ -403,7 +437,7 @@ include 'layout_header.php';
|
|||||||
<span class="badge bg-warning text-dark">Distribución Interna</span>
|
<span class="badge bg-warning text-dark">Distribución Interna</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body d-flex flex-column align-items-center justify-content-center" style="min-height: 300px;">
|
<div class="card-body d-flex flex-column align-items-center justify-content-center" style="min-height: 300px;">
|
||||||
<div style="width: 100%; max-width: 280px;">
|
<div style="width: 100%; max-width: 450px;">
|
||||||
<canvas id="contraentregaPieChart"></canvas>
|
<canvas id="contraentregaPieChart"></canvas>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-3 text-center">
|
<div class="mt-3 text-center">
|
||||||
@ -438,7 +472,7 @@ include 'layout_header.php';
|
|||||||
<h6 class="border-bottom pb-2 mb-3">Distribución de Estados</h6>
|
<h6 class="border-bottom pb-2 mb-3">Distribución de Estados</h6>
|
||||||
<div class="list-group list-group-flush">
|
<div class="list-group list-group-flush">
|
||||||
<?php
|
<?php
|
||||||
$estadosProv = ['ROTULADO 📦', 'EN TRANSITO 🚛', 'EN DESTINO 🏬', 'COMPLETADO ✅', 'RETORNADO'];
|
$estadosProv = ['ROTULADO 📦', 'EN TRANSITO 🚛', 'EN DESTINO 🏬', 'COMPLETADO ✅', 'GESTIONES'];
|
||||||
foreach ($estadosProv as $est):
|
foreach ($estadosProv as $est):
|
||||||
$count = $canalesResumen['Provincia']['estados'][$est] ?? 0;
|
$count = $canalesResumen['Provincia']['estados'][$est] ?? 0;
|
||||||
$pct = $canalesResumen['Provincia']['pedidos'] > 0 ? ($count / array_sum($canalesResumen['Provincia']['estados'])) * 100 : 0;
|
$pct = $canalesResumen['Provincia']['pedidos'] > 0 ? ($count / array_sum($canalesResumen['Provincia']['estados'])) * 100 : 0;
|
||||||
@ -507,7 +541,7 @@ include 'layout_header.php';
|
|||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<!-- Gráfico de Ventas -->
|
<!-- Gráfico de Ventas -->
|
||||||
<div class="col-md-8 mb-4">
|
<div class="col-md-7 mb-4">
|
||||||
<div class="card shadow">
|
<div class="card shadow">
|
||||||
<div class="card-header bg-white">
|
<div class="card-header bg-white">
|
||||||
<h5 class="mb-0">Tendencia de Ventas (<?php echo $label_period; ?>)</h5>
|
<h5 class="mb-0">Tendencia de Ventas (<?php echo $label_period; ?>)</h5>
|
||||||
@ -518,7 +552,7 @@ include 'layout_header.php';
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Gráfico de Estados -->
|
<!-- Gráfico de Estados -->
|
||||||
<div class="col-md-4 mb-4">
|
<div class="col-md-5 mb-4">
|
||||||
<div class="card shadow">
|
<div class="card shadow">
|
||||||
<div class="card-header bg-white">
|
<div class="card-header bg-white">
|
||||||
<h5 class="mb-0">Distribución de Estados</h5>
|
<h5 class="mb-0">Distribución de Estados</h5>
|
||||||
@ -640,6 +674,44 @@ include 'layout_header.php';
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<!-- Rendimiento Detallado por Producto en Provincia -->
|
||||||
|
<div class="col-md-6 mb-4">
|
||||||
|
<div class="card shadow border-left-primary h-100">
|
||||||
|
<div class="card-header bg-white d-flex justify-content-between align-items-center">
|
||||||
|
<h5 class="mb-0 text-primary"><i class="fas fa-chart-bar me-2"></i> Rendimiento Producto (Provincia)</h5>
|
||||||
|
<span class="badge bg-primary text-white">Top 10</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div style="height: 350px;">
|
||||||
|
<canvas id="rendimientoProdProvChart"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 small text-muted text-center">
|
||||||
|
<i class="fas fa-info-circle me-1"></i> Completados vs Gestiones en Provincia.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Rendimiento Detallado por Producto en Contraentrega -->
|
||||||
|
<div class="col-md-6 mb-4">
|
||||||
|
<div class="card shadow border-left-warning h-100">
|
||||||
|
<div class="card-header bg-white d-flex justify-content-between align-items-center">
|
||||||
|
<h5 class="mb-0 text-warning"><i class="fas fa-chart-bar me-2"></i> Rendimiento Producto (Contraentrega)</h5>
|
||||||
|
<span class="badge bg-warning text-dark">Top 10</span>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div style="height: 350px;">
|
||||||
|
<canvas id="rendimientoProdCEChart"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class="mt-3 small text-muted text-center">
|
||||||
|
<i class="fas fa-info-circle me-1"></i> Éxito vs Retorno en Contraentrega.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<!-- Ventas por Asesor -->
|
<!-- Ventas por Asesor -->
|
||||||
<div class="col-md-12 mb-4">
|
<div class="col-md-12 mb-4">
|
||||||
@ -656,22 +728,32 @@ include 'layout_header.php';
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.0.0"></script>
|
||||||
<script>
|
<script>
|
||||||
|
// Registrar el plugin de etiquetas de datos
|
||||||
|
Chart.register(ChartDataLabels);
|
||||||
|
|
||||||
// Gráfico de Provincia (Doughnut)
|
// Gráfico de Provincia (Doughnut)
|
||||||
const ctxProvincia = document.getElementById('provinciaPieChart').getContext('2d');
|
const ctxProvincia = document.getElementById('provinciaPieChart').getContext('2d');
|
||||||
new Chart(ctxProvincia, {
|
new Chart(ctxProvincia, {
|
||||||
type: 'doughnut',
|
type: 'doughnut',
|
||||||
data: {
|
data: {
|
||||||
labels: ['ROTULADO 📦', 'EN TRANSITO 🚛', 'EN DESTINO 🏬', 'COMPLETADO ✅', 'RETORNADO'],
|
labels: [
|
||||||
|
'ROTULADO 📦 (<?php echo $canalesResumen['Provincia']['estados']['ROTULADO 📦'] ?? 0; ?>)',
|
||||||
|
'EN TRANSITO 🚛 (<?php echo $canalesResumen['Provincia']['estados']['EN TRANSITO 🚛'] ?? 0; ?>)',
|
||||||
|
'EN DESTINO 🏬 (<?php echo $canalesResumen['Provincia']['estados']['EN DESTINO 🏬'] ?? 0; ?>)',
|
||||||
|
'COMPLETADO ✅ (<?php echo $canalesResumen['Provincia']['estados']['COMPLETADO ✅'] ?? 0; ?>)',
|
||||||
|
'GESTIONES (<?php echo $canalesResumen['Provincia']['estados']['GESTIONES'] ?? 0; ?>)'
|
||||||
|
],
|
||||||
datasets: [{
|
datasets: [{
|
||||||
data: [
|
data: [
|
||||||
<?php echo $canalesResumen['Provincia']['estados']['ROTULADO 📦'] ?? 0; ?>,
|
<?php echo $canalesResumen['Provincia']['estados']['ROTULADO 📦'] ?? 0; ?>,
|
||||||
<?php echo $canalesResumen['Provincia']['estados']['EN TRANSITO 🚛'] ?? 0; ?>,
|
<?php echo $canalesResumen['Provincia']['estados']['EN TRANSITO 🚛'] ?? 0; ?>,
|
||||||
<?php echo $canalesResumen['Provincia']['estados']['EN DESTINO 🏬'] ?? 0; ?>,
|
<?php echo $canalesResumen['Provincia']['estados']['EN DESTINO 🏬'] ?? 0; ?>,
|
||||||
<?php echo $canalesResumen['Provincia']['estados']['COMPLETADO ✅'] ?? 0; ?>,
|
<?php echo $canalesResumen['Provincia']['estados']['COMPLETADO ✅'] ?? 0; ?>,
|
||||||
<?php echo $canalesResumen['Provincia']['estados']['RETORNADO'] ?? 0; ?>
|
<?php echo $canalesResumen['Provincia']['estados']['GESTIONES'] ?? 0; ?>
|
||||||
],
|
],
|
||||||
backgroundColor: ['#ffc107', '#0dcaf0', '#6610f2', '#198754', '#dc3545'],
|
backgroundColor: ['#ffc107', '#0dcaf0', '#6610f2', '#198754', '#6c757d'],
|
||||||
hoverOffset: 10,
|
hoverOffset: 10,
|
||||||
borderWidth: 0,
|
borderWidth: 0,
|
||||||
cutout: '70%'
|
cutout: '70%'
|
||||||
@ -681,7 +763,27 @@ include 'layout_header.php';
|
|||||||
responsive: true,
|
responsive: true,
|
||||||
maintainAspectRatio: false,
|
maintainAspectRatio: false,
|
||||||
plugins: {
|
plugins: {
|
||||||
legend: { display: false }
|
legend: {
|
||||||
|
display: true,
|
||||||
|
position: 'right',
|
||||||
|
labels: {
|
||||||
|
boxWidth: 15,
|
||||||
|
padding: 20,
|
||||||
|
color: '#000',
|
||||||
|
font: { size: 14, weight: 'bold' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
datalabels: {
|
||||||
|
color: '#fff',
|
||||||
|
font: { weight: 'bold', size: 16 },
|
||||||
|
formatter: (value, ctx) => {
|
||||||
|
let sum = 0;
|
||||||
|
let dataArr = ctx.chart.data.datasets[0].data;
|
||||||
|
dataArr.map(data => { sum += data; });
|
||||||
|
let percentage = (value * 100 / sum).toFixed(0) + "%";
|
||||||
|
return value > 0 ? percentage : '';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -691,7 +793,11 @@ include 'layout_header.php';
|
|||||||
new Chart(ctxContraentrega, {
|
new Chart(ctxContraentrega, {
|
||||||
type: 'doughnut',
|
type: 'doughnut',
|
||||||
data: {
|
data: {
|
||||||
labels: ['RUTA_CONTRAENTREGA', 'ENTREGA EXITOSA', 'RETORNADO'],
|
labels: [
|
||||||
|
'RUTA CE (<?php echo $canalesResumen['Contraentrega']['estados']['RUTA_CONTRAENTREGA'] ?? 0; ?>)',
|
||||||
|
'EXITOSA ✅ (<?php echo $canalesResumen['Contraentrega']['estados']['ENTREGA EXITOSA'] ?? 0; ?>)',
|
||||||
|
'RETORNADO (<?php echo $canalesResumen['Contraentrega']['estados']['RETORNADO'] ?? 0; ?>)'
|
||||||
|
],
|
||||||
datasets: [{
|
datasets: [{
|
||||||
data: [
|
data: [
|
||||||
<?php echo $canalesResumen['Contraentrega']['estados']['RUTA_CONTRAENTREGA'] ?? 0; ?>,
|
<?php echo $canalesResumen['Contraentrega']['estados']['RUTA_CONTRAENTREGA'] ?? 0; ?>,
|
||||||
@ -708,7 +814,27 @@ include 'layout_header.php';
|
|||||||
responsive: true,
|
responsive: true,
|
||||||
maintainAspectRatio: false,
|
maintainAspectRatio: false,
|
||||||
plugins: {
|
plugins: {
|
||||||
legend: { display: false }
|
legend: {
|
||||||
|
display: true,
|
||||||
|
position: 'right',
|
||||||
|
labels: {
|
||||||
|
boxWidth: 15,
|
||||||
|
padding: 20,
|
||||||
|
color: '#000',
|
||||||
|
font: { size: 14, weight: 'bold' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
datalabels: {
|
||||||
|
color: '#fff',
|
||||||
|
font: { weight: 'bold', size: 16 },
|
||||||
|
formatter: (value, ctx) => {
|
||||||
|
let sum = 0;
|
||||||
|
let dataArr = ctx.chart.data.datasets[0].data;
|
||||||
|
dataArr.map(data => { sum += data; });
|
||||||
|
let percentage = (value * 100 / sum).toFixed(0) + "%";
|
||||||
|
return value > 0 ? percentage : '';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -759,11 +885,43 @@ include 'layout_header.php';
|
|||||||
new Chart(ctxEstados, {
|
new Chart(ctxEstados, {
|
||||||
type: 'doughnut',
|
type: 'doughnut',
|
||||||
data: {
|
data: {
|
||||||
labels: <?php echo json_encode(array_column($estadosData, 'estado')); ?>,
|
labels: <?php
|
||||||
|
$labelsConValores = array_map(function($item) {
|
||||||
|
return $item['estado'] . ' (' . $item['total'] . ')';
|
||||||
|
}, $estadosData);
|
||||||
|
echo json_encode($labelsConValores);
|
||||||
|
?>,
|
||||||
datasets: [{
|
datasets: [{
|
||||||
data: <?php echo json_encode(array_column($estadosData, 'total')); ?>,
|
data: <?php echo json_encode(array_column($estadosData, 'total')); ?>,
|
||||||
backgroundColor: ['#ffc107', '#0dcaf0', '#198754', '#dc3545', '#6c757d', '#0d6efd', '#20c997', '#6610f2']
|
backgroundColor: ['#ffc107', '#0dcaf0', '#198754', '#dc3545', '#6c757d', '#0d6efd', '#20c997', '#6610f2'],
|
||||||
|
borderWidth: 0
|
||||||
}]
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
display: true,
|
||||||
|
position: 'right',
|
||||||
|
labels: {
|
||||||
|
boxWidth: 15,
|
||||||
|
padding: 15,
|
||||||
|
color: '#000',
|
||||||
|
font: { size: 12, weight: 'bold' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
datalabels: {
|
||||||
|
color: '#fff',
|
||||||
|
font: { weight: 'bold', size: 14 },
|
||||||
|
formatter: (value, ctx) => {
|
||||||
|
let sum = 0;
|
||||||
|
let dataArr = ctx.chart.data.datasets[0].data;
|
||||||
|
dataArr.map(data => { sum += data; });
|
||||||
|
let percentage = (value * 100 / sum).toFixed(0) + "%";
|
||||||
|
return value > 0 ? percentage : '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -803,6 +961,124 @@ include 'layout_header.php';
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Gráfico de Rendimiento por Producto en Contraentrega (Barras Apiladas - Vertical)
|
||||||
|
const ctxRendimientoCE = document.getElementById('rendimientoProdCEChart').getContext('2d');
|
||||||
|
new Chart(ctxRendimientoCE, {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: <?php echo json_encode(array_map(function($p) {
|
||||||
|
return strlen($p['producto']) > 15 ? substr($p['producto'], 0, 15) . '...' : $p['producto'];
|
||||||
|
}, $prodRendimientoCE)); ?>,
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: 'Exitosa ✅',
|
||||||
|
data: <?php echo json_encode(array_column($prodRendimientoCE, 'exitosas')); ?>,
|
||||||
|
backgroundColor: '#198754',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Retornado ❌',
|
||||||
|
data: <?php echo json_encode(array_column($prodRendimientoCE, 'retornados')); ?>,
|
||||||
|
backgroundColor: '#dc3545',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'En Ruta 🚛',
|
||||||
|
data: <?php echo json_encode(array_column($prodRendimientoCE, 'en_ruta')); ?>,
|
||||||
|
backgroundColor: '#0d6efd',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
indexAxis: 'x',
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
stacked: true,
|
||||||
|
ticks: {
|
||||||
|
maxRotation: 45,
|
||||||
|
minRotation: 45,
|
||||||
|
color: '#000',
|
||||||
|
font: { size: 10, weight: 'bold' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
stacked: true,
|
||||||
|
title: { display: true, text: 'Cantidad' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
position: 'top',
|
||||||
|
labels: { boxWidth: 12, font: { size: 11 } }
|
||||||
|
},
|
||||||
|
datalabels: {
|
||||||
|
color: '#fff',
|
||||||
|
font: { weight: 'bold', size: 10 },
|
||||||
|
formatter: (value) => value > 0 ? value : ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Gráfico de Rendimiento por Producto en Provincia (Barras Apiladas - Vertical)
|
||||||
|
const ctxRendimientoProv = document.getElementById('rendimientoProdProvChart').getContext('2d');
|
||||||
|
new Chart(ctxRendimientoProv, {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: <?php echo json_encode(array_map(function($p) {
|
||||||
|
return strlen($p['producto']) > 15 ? substr($p['producto'], 0, 15) . '...' : $p['producto'];
|
||||||
|
}, $prodRendimientoProv)); ?>,
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: 'Completado ✅',
|
||||||
|
data: <?php echo json_encode(array_column($prodRendimientoProv, 'completados')); ?>,
|
||||||
|
backgroundColor: '#198754',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Gestiones ⚠️',
|
||||||
|
data: <?php echo json_encode(array_column($prodRendimientoProv, 'gestiones')); ?>,
|
||||||
|
backgroundColor: '#6c757d',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'En Proceso 🚛',
|
||||||
|
data: <?php echo json_encode(array_column($prodRendimientoProv, 'en_proceso')); ?>,
|
||||||
|
backgroundColor: '#0dcaf0',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
indexAxis: 'x',
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
stacked: true,
|
||||||
|
ticks: {
|
||||||
|
maxRotation: 45,
|
||||||
|
minRotation: 45,
|
||||||
|
color: '#000',
|
||||||
|
font: { size: 10, weight: 'bold' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
stacked: true,
|
||||||
|
title: { display: true, text: 'Cantidad' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
position: 'top',
|
||||||
|
labels: { boxWidth: 12, font: { size: 11 } }
|
||||||
|
},
|
||||||
|
datalabels: {
|
||||||
|
color: '#fff',
|
||||||
|
font: { weight: 'bold', size: 10 },
|
||||||
|
formatter: (value) => value > 0 ? value : ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Gráfico de Asesores
|
// Gráfico de Asesores
|
||||||
const ctxAsesores = document.getElementById('asesoresChart').getContext('2d');
|
const ctxAsesores = document.getElementById('asesoresChart').getContext('2d');
|
||||||
new Chart(ctxAsesores, {
|
new Chart(ctxAsesores, {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user