fixed stats
This commit is contained in:
@@ -103,30 +103,31 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ===== KPI ===== -->
|
<!-- ===== KPI ===== -->
|
||||||
<div class="row row-cols-2 row-cols-md-3 row-cols-lg-6 g-3 kpi-row">
|
<div class="row row-cols-2 row-cols-md-3 row-cols-lg-5 g-3 kpi-row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="card radius-10 stat-card stat-card-extra h-100">
|
<div class="card radius-10 stat-card stat-card-extra h-100">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="stat-label">Export mese <span id="kpiMonthLabel"></span></div>
|
<div class="stat-label">Campioni mese <span id="kpiMonthLabel"></span></div>
|
||||||
<div class="stat-value text-primary" id="kpiExportMonth">0</div>
|
<div class="stat-value" id="kpiPartsMonth">0</div>
|
||||||
<small class="text-muted">Dati dal 16/07/2026</small>
|
<small class="text-muted">Commesse: <span id="kpiExportMonth">0</span> · dal 16/07/2026</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="card radius-10 stat-card stat-card-extra h-100">
|
<div class="card radius-10 stat-card stat-card-extra h-100">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="stat-label">Export anno <span id="kpiYearLabel"></span></div>
|
<div class="stat-label">Campioni anno <span id="kpiYearLabel"></span></div>
|
||||||
<div class="stat-value text-dark" id="kpiExportYear">0</div>
|
<div class="stat-value" id="kpiPartsYear">0</div>
|
||||||
<small class="text-muted">Dati dal 16/07/2026</small>
|
<small class="text-muted">Commesse: <span id="kpiExportYear">0</span> · dal 16/07/2026</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="card radius-10 stat-card h-100">
|
<div class="card radius-10 stat-card h-100">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="stat-label">Export giorno (status L)</div>
|
<div class="stat-label">Campioni esportati (giorno)</div>
|
||||||
<div class="stat-value text-primary" id="kpiExport">0</div>
|
<div class="stat-value text-primary" id="kpiParts">0</div>
|
||||||
|
<small class="text-muted">Commesse: <span id="kpiExport">0</span></small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -146,14 +147,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col">
|
|
||||||
<div class="card radius-10 stat-card h-100">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="stat-label">Clienti distinti</div>
|
|
||||||
<div class="stat-value text-warning" id="kpiClienti">0</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ===== DATO GIORNALIERO CAMPIONI LIMS ===== -->
|
<!-- ===== DATO GIORNALIERO CAMPIONI LIMS ===== -->
|
||||||
@@ -222,7 +215,8 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>ID Cliente</th>
|
<th>ID Cliente</th>
|
||||||
<th>Cliente</th>
|
<th>Cliente</th>
|
||||||
<th>Export</th>
|
<th>Campioni</th>
|
||||||
|
<th>Commesse</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody></tbody>
|
<tbody></tbody>
|
||||||
@@ -243,7 +237,8 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>ID Utente</th>
|
<th>ID Utente</th>
|
||||||
<th>Utente</th>
|
<th>Utente</th>
|
||||||
<th>Export</th>
|
<th>Campioni</th>
|
||||||
|
<th>Commesse</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody></tbody>
|
<tbody></tbody>
|
||||||
@@ -295,6 +290,10 @@
|
|||||||
data: 'clientname',
|
data: 'clientname',
|
||||||
defaultContent: '—'
|
defaultContent: '—'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
data: 'parts',
|
||||||
|
className: 'text-end'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
data: 'tot',
|
data: 'tot',
|
||||||
className: 'text-end'
|
className: 'text-end'
|
||||||
@@ -318,6 +317,10 @@
|
|||||||
data: 'username',
|
data: 'username',
|
||||||
defaultContent: '—'
|
defaultContent: '—'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
data: 'parts',
|
||||||
|
className: 'text-end'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
data: 'tot',
|
data: 'tot',
|
||||||
className: 'text-end'
|
className: 'text-end'
|
||||||
@@ -428,11 +431,13 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// KPI
|
// KPI — dato principale = parti/campioni, sotto le commesse
|
||||||
$('#kpiExport').text(res.totals.export);
|
$('#kpiParts').text(res.totals.parts ?? 0);
|
||||||
$('#kpiExportMonth').text(res.totalsMonth ? res.totalsMonth.export : 0);
|
$('#kpiExport').text(res.totals.export ?? 0);
|
||||||
$('#kpiExportYear').text(res.totalsYear ? res.totalsYear.export : 0);
|
$('#kpiPartsMonth').text(res.totalsMonth ? (res.totalsMonth.parts ?? 0) : 0);
|
||||||
$('#kpiClienti').text(res.byClient.length);
|
$('#kpiExportMonth').text(res.totalsMonth ? (res.totalsMonth.export ?? 0) : 0);
|
||||||
|
$('#kpiPartsYear').text(res.totalsYear ? (res.totalsYear.parts ?? 0) : 0);
|
||||||
|
$('#kpiExportYear').text(res.totalsYear ? (res.totalsYear.export ?? 0) : 0);
|
||||||
$('#kpiLimsSamples').text(res.limsSamples ?? 0);
|
$('#kpiLimsSamples').text(res.limsSamples ?? 0);
|
||||||
$('#limsSamplesInput').val(res.limsSamples ?? '');
|
$('#limsSamplesInput').val(res.limsSamples ?? '');
|
||||||
|
|
||||||
@@ -452,25 +457,26 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const limsTot = parseInt(res.limsSamples ?? 0, 10);
|
const limsTot = parseInt(res.limsSamples ?? 0, 10);
|
||||||
|
const partsTot = parseInt(res.totals.parts ?? 0, 10);
|
||||||
if (limsTot > 0) {
|
if (limsTot > 0) {
|
||||||
const perc = (res.totals.export / limsTot) * 100;
|
const perc = (partsTot / limsTot) * 100;
|
||||||
$('#kpiPerc').text(perc.toFixed(1) + '%');
|
$('#kpiPerc').text(perc.toFixed(1) + '%');
|
||||||
} else {
|
} else {
|
||||||
$('#kpiPerc').text('—');
|
$('#kpiPerc').text('—');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Torta esportati vs totale
|
// Torta parti esportate vs totale inserito nel LIMS
|
||||||
renderPie(res.totals.export, limsTot);
|
renderPie(partsTot, limsTot);
|
||||||
|
|
||||||
// Grafici
|
// Grafici — valori = campioni/parti
|
||||||
const clientTop = topN(res.byClient);
|
const clientTop = topN(res.byClient);
|
||||||
const userTop = topN(res.byUser);
|
const userTop = topN(res.byUser);
|
||||||
chartClienti = renderBarChart(chartClienti, 'chartClienti',
|
chartClienti = renderBarChart(chartClienti, 'chartClienti',
|
||||||
clientTop.map(r => r.clientname ? (r.clientname + ' (' + r.idclient + ')') : ('ID ' + r.idclient)),
|
clientTop.map(r => r.clientname ? (r.clientname + ' (' + r.idclient + ')') : ('ID ' + r.idclient)),
|
||||||
clientTop.map(r => r.tot), 'Export');
|
clientTop.map(r => r.parts), 'Campioni');
|
||||||
chartUtenti = renderBarChart(chartUtenti, 'chartUtenti',
|
chartUtenti = renderBarChart(chartUtenti, 'chartUtenti',
|
||||||
userTop.map(r => r.username ? (r.username + ' (' + r.user_id + ')') : ('ID ' + r.user_id)),
|
userTop.map(r => r.username ? (r.username + ' (' + r.user_id + ')') : ('ID ' + r.user_id)),
|
||||||
userTop.map(r => r.tot), 'Export');
|
userTop.map(r => r.parts), 'Campioni');
|
||||||
|
|
||||||
// Tabelle
|
// Tabelle
|
||||||
dtClienti.clear().rows.add(res.byClient).draw();
|
dtClienti.clear().rows.add(res.byClient).draw();
|
||||||
|
|||||||
@@ -15,14 +15,17 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- Export per cliente (status = 'l', giornata su export_date) ---
|
// --- Export per cliente (status = 'l', giornata su export_date) ---
|
||||||
|
// tot = numero commesse, parts = numero parti/campioni
|
||||||
$stmtC = $pdo->prepare("
|
$stmtC = $pdo->prepare("
|
||||||
SELECT d.idclient AS idclient,
|
SELECT d.idclient AS idclient,
|
||||||
COUNT(*) AS tot
|
COUNT(DISTINCT d.iddatadb) AS tot,
|
||||||
|
COUNT(ip.id) AS parts
|
||||||
FROM datadb d
|
FROM datadb d
|
||||||
|
LEFT JOIN identification_parts ip ON ip.iddatadb = d.iddatadb
|
||||||
WHERE d.status = 'l'
|
WHERE d.status = 'l'
|
||||||
AND DATE(d.export_date) = :d
|
AND DATE(d.export_date) = :d
|
||||||
GROUP BY d.idclient
|
GROUP BY d.idclient
|
||||||
ORDER BY tot DESC
|
ORDER BY parts DESC
|
||||||
");
|
");
|
||||||
$stmtC->execute(['d' => $date]);
|
$stmtC->execute(['d' => $date]);
|
||||||
$byClient = $stmtC->fetchAll(PDO::FETCH_ASSOC);
|
$byClient = $stmtC->fetchAll(PDO::FETCH_ASSOC);
|
||||||
@@ -38,16 +41,19 @@ try {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- Export per utente (status = 'l', giornata su export_date) ---
|
// --- Export per utente (status = 'l', giornata su export_date) ---
|
||||||
|
// tot = numero commesse, parts = numero parti/campioni
|
||||||
$stmtU = $pdo->prepare("
|
$stmtU = $pdo->prepare("
|
||||||
SELECT d.user_id AS user_id,
|
SELECT d.user_id AS user_id,
|
||||||
TRIM(CONCAT(COALESCE(u.first_name,''),' ',COALESCE(u.last_name,''))) AS username,
|
TRIM(CONCAT(COALESCE(u.first_name,''),' ',COALESCE(u.last_name,''))) AS username,
|
||||||
COUNT(*) AS tot
|
COUNT(DISTINCT d.iddatadb) AS tot,
|
||||||
|
COUNT(ip.id) AS parts
|
||||||
FROM datadb d
|
FROM datadb d
|
||||||
LEFT JOIN auth_users u ON u.id = d.user_id
|
LEFT JOIN auth_users u ON u.id = d.user_id
|
||||||
|
LEFT JOIN identification_parts ip ON ip.iddatadb = d.iddatadb
|
||||||
WHERE d.status = 'l'
|
WHERE d.status = 'l'
|
||||||
AND DATE(d.export_date) = :d
|
AND DATE(d.export_date) = :d
|
||||||
GROUP BY d.user_id, username
|
GROUP BY d.user_id, username
|
||||||
ORDER BY tot DESC
|
ORDER BY parts DESC
|
||||||
");
|
");
|
||||||
$stmtU->execute(['d' => $date]);
|
$stmtU->execute(['d' => $date]);
|
||||||
$byUser = $stmtU->fetchAll(PDO::FETCH_ASSOC);
|
$byUser = $stmtU->fetchAll(PDO::FETCH_ASSOC);
|
||||||
@@ -56,6 +62,7 @@ try {
|
|||||||
foreach ($byClient as &$r) {
|
foreach ($byClient as &$r) {
|
||||||
$r['idclient'] = $r['idclient'] !== null ? (int)$r['idclient'] : null;
|
$r['idclient'] = $r['idclient'] !== null ? (int)$r['idclient'] : null;
|
||||||
$r['tot'] = (int)$r['tot'];
|
$r['tot'] = (int)$r['tot'];
|
||||||
|
$r['parts'] = (int)$r['parts'];
|
||||||
$nm = $clientNames[$r['idclient']] ?? '';
|
$nm = $clientNames[$r['idclient']] ?? '';
|
||||||
$r['clientname'] = $nm !== '' ? $nm : null;
|
$r['clientname'] = $nm !== '' ? $nm : null;
|
||||||
}
|
}
|
||||||
@@ -63,6 +70,7 @@ try {
|
|||||||
foreach ($byUser as &$r) {
|
foreach ($byUser as &$r) {
|
||||||
$r['user_id'] = $r['user_id'] !== null ? (int)$r['user_id'] : null;
|
$r['user_id'] = $r['user_id'] !== null ? (int)$r['user_id'] : null;
|
||||||
$r['tot'] = (int)$r['tot'];
|
$r['tot'] = (int)$r['tot'];
|
||||||
|
$r['parts'] = (int)$r['parts'];
|
||||||
if (isset($r['username'])) $r['username'] = $r['username'] !== null && $r['username'] !== '' ? $r['username'] : null;
|
if (isset($r['username'])) $r['username'] = $r['username'] !== null && $r['username'] !== '' ? $r['username'] : null;
|
||||||
}
|
}
|
||||||
unset($r);
|
unset($r);
|
||||||
@@ -70,7 +78,19 @@ try {
|
|||||||
// --- Totale export della giornata ---
|
// --- Totale export della giornata ---
|
||||||
$totExport = array_sum(array_column($byClient, 'tot'));
|
$totExport = array_sum(array_column($byClient, 'tot'));
|
||||||
|
|
||||||
// --- Totale export del MESE della data selezionata (status = 'l') ---
|
// --- Totale PARTI/CAMPIONI della giornata (righe identification_parts legate
|
||||||
|
// ai datadb esportati status='l' in questa giornata) ---
|
||||||
|
$stmtP = $pdo->prepare("
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM identification_parts ip
|
||||||
|
INNER JOIN datadb d ON d.iddatadb = ip.iddatadb
|
||||||
|
WHERE d.status = 'l'
|
||||||
|
AND DATE(d.export_date) = :d
|
||||||
|
");
|
||||||
|
$stmtP->execute(['d' => $date]);
|
||||||
|
$totParts = (int)$stmtP->fetchColumn();
|
||||||
|
|
||||||
|
// --- Totale COMMESSE del MESE (status = 'l') ---
|
||||||
$stmtM = $pdo->prepare("
|
$stmtM = $pdo->prepare("
|
||||||
SELECT COUNT(*)
|
SELECT COUNT(*)
|
||||||
FROM datadb d
|
FROM datadb d
|
||||||
@@ -80,7 +100,18 @@ try {
|
|||||||
$stmtM->execute(['m' => $d->format('Y-m')]);
|
$stmtM->execute(['m' => $d->format('Y-m')]);
|
||||||
$totExportMonth = (int)$stmtM->fetchColumn();
|
$totExportMonth = (int)$stmtM->fetchColumn();
|
||||||
|
|
||||||
// --- Totale export dell'ANNO della data selezionata (status = 'l') ---
|
// --- Totale PARTI del MESE (status = 'l') ---
|
||||||
|
$stmtMP = $pdo->prepare("
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM identification_parts ip
|
||||||
|
INNER JOIN datadb d ON d.iddatadb = ip.iddatadb
|
||||||
|
WHERE d.status = 'l'
|
||||||
|
AND DATE_FORMAT(d.export_date, '%Y-%m') = :m
|
||||||
|
");
|
||||||
|
$stmtMP->execute(['m' => $d->format('Y-m')]);
|
||||||
|
$totPartsMonth = (int)$stmtMP->fetchColumn();
|
||||||
|
|
||||||
|
// --- Totale COMMESSE dell'ANNO (status = 'l') ---
|
||||||
$stmtY = $pdo->prepare("
|
$stmtY = $pdo->prepare("
|
||||||
SELECT COUNT(*)
|
SELECT COUNT(*)
|
||||||
FROM datadb d
|
FROM datadb d
|
||||||
@@ -90,6 +121,17 @@ try {
|
|||||||
$stmtY->execute(['y' => $d->format('Y')]);
|
$stmtY->execute(['y' => $d->format('Y')]);
|
||||||
$totExportYear = (int)$stmtY->fetchColumn();
|
$totExportYear = (int)$stmtY->fetchColumn();
|
||||||
|
|
||||||
|
// --- Totale PARTI dell'ANNO (status = 'l') ---
|
||||||
|
$stmtYP = $pdo->prepare("
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM identification_parts ip
|
||||||
|
INNER JOIN datadb d ON d.iddatadb = ip.iddatadb
|
||||||
|
WHERE d.status = 'l'
|
||||||
|
AND YEAR(d.export_date) = :y
|
||||||
|
");
|
||||||
|
$stmtYP->execute(['y' => $d->format('Y')]);
|
||||||
|
$totPartsYear = (int)$stmtYP->fetchColumn();
|
||||||
|
|
||||||
// --- Campioni totali inseriti nel LIMS per la giornata (tabella lims_daily_samples) ---
|
// --- Campioni totali inseriti nel LIMS per la giornata (tabella lims_daily_samples) ---
|
||||||
$stmtL = $pdo->prepare("SELECT total_samples FROM lims_daily_samples WHERE sample_date = :d LIMIT 1");
|
$stmtL = $pdo->prepare("SELECT total_samples FROM lims_daily_samples WHERE sample_date = :d LIMIT 1");
|
||||||
$stmtL->execute(['d' => $date]);
|
$stmtL->execute(['d' => $date]);
|
||||||
@@ -101,9 +143,9 @@ try {
|
|||||||
'date' => $date,
|
'date' => $date,
|
||||||
'month' => $d->format('Y-m'),
|
'month' => $d->format('Y-m'),
|
||||||
'year' => (int)$d->format('Y'),
|
'year' => (int)$d->format('Y'),
|
||||||
'totals' => ['export' => (int)$totExport],
|
'totals' => ['export' => (int)$totExport, 'parts' => $totParts],
|
||||||
'totalsMonth' => ['export' => $totExportMonth],
|
'totalsMonth' => ['export' => $totExportMonth, 'parts' => $totPartsMonth],
|
||||||
'totalsYear' => ['export' => $totExportYear],
|
'totalsYear' => ['export' => $totExportYear, 'parts' => $totPartsYear],
|
||||||
'byClient' => $byClient,
|
'byClient' => $byClient,
|
||||||
'byUser' => $byUser,
|
'byUser' => $byUser,
|
||||||
'limsSamples' => $limsSamples,
|
'limsSamples' => $limsSamples,
|
||||||
|
|||||||
Reference in New Issue
Block a user