fixed sommario and added queue mago

This commit is contained in:
2026-10-20 12:08:35 +02:00
parent b6145e0553
commit 89e5388b75
12 changed files with 2558 additions and 7 deletions
+185 -3
View File
@@ -389,6 +389,56 @@ if ($action === 'data') {
return $m['delta'] < 0;
}));
// ---------------- ORDINI IN ARRIVO: oggi, 7 giorni, 30 giorni (vs periodo precedente) ----------------
$fl = MagoSalesStats::fetchAllQ($pdo, "
SELECT
SUM(x.order_date = CURDATE()) AS n0,
SUM(CASE WHEN x.order_date = CURDATE() THEN x.taxable_amount ELSE 0 END) AS v0,
SUM(x.order_date = CURDATE() - INTERVAL 7 DAY) AS n0p,
SUM(CASE WHEN x.order_date = CURDATE() - INTERVAL 7 DAY THEN x.taxable_amount ELSE 0 END) AS v0p,
SUM(x.order_date > CURDATE() - INTERVAL 7 DAY) AS n7,
SUM(CASE WHEN x.order_date > CURDATE() - INTERVAL 7 DAY THEN x.taxable_amount ELSE 0 END) AS v7,
SUM(x.order_date <= CURDATE() - INTERVAL 7 DAY AND x.order_date > CURDATE() - INTERVAL 14 DAY) AS n7p,
SUM(CASE WHEN x.order_date <= CURDATE() - INTERVAL 7 DAY AND x.order_date > CURDATE() - INTERVAL 14 DAY THEN x.taxable_amount ELSE 0 END) AS v7p,
SUM(x.order_date > CURDATE() - INTERVAL 30 DAY) AS n30,
SUM(CASE WHEN x.order_date > CURDATE() - INTERVAL 30 DAY THEN x.taxable_amount ELSE 0 END) AS v30,
SUM(x.order_date <= CURDATE() - INTERVAL 30 DAY AND x.order_date > CURDATE() - INTERVAL 60 DAY) AS n30p,
SUM(CASE WHEN x.order_date <= CURDATE() - INTERVAL 30 DAY AND x.order_date > CURDATE() - INTERVAL 60 DAY THEN x.taxable_amount ELSE 0 END) AS v30p,
COUNT(DISTINCT CASE WHEN x.order_date > CURDATE() - INTERVAL 30 DAY THEN x.customer END) AS c30
FROM $from
WHERE x.status <> 'annullato' AND x.order_date > CURDATE() - INTERVAL 60 DAY AND x.order_date <= CURDATE()
", [])[0];
$flow = [
[
'key' => 'today',
'title' => 'Oggi',
'n' => (int)$fl['n0'],
'v' => (float)$fl['v0'],
'np' => (int)$fl['n0p'],
'vp' => (float)$fl['v0p'],
'vs' => 'stesso giorno della settimana scorsa'
],
[
'key' => 'week',
'title' => 'Ultimi 7 giorni',
'n' => (int)$fl['n7'],
'v' => (float)$fl['v7'],
'np' => (int)$fl['n7p'],
'vp' => (float)$fl['v7p'],
'vs' => '7 giorni precedenti'
],
[
'key' => 'month',
'title' => 'Ultimi 30 giorni',
'n' => (int)$fl['n30'],
'v' => (float)$fl['v30'],
'np' => (int)$fl['n30p'],
'vp' => (float)$fl['v30p'],
'vs' => '30 giorni precedenti',
'customers' => (int)$fl['c30']
],
];
// ---------------- GIUDIZIO COMPLESSIVO ----------------
$score = ['green' => 0, 'yellow' => 0, 'red' => 0, 'grey' => 0];
foreach ($T as $t) $score[$t['light']]++;
@@ -402,6 +452,7 @@ if ($action === 'data') {
'year' => $curY,
'inv_ok' => $invOk,
'tiles' => $T,
'flow' => $flow,
'score' => $score,
'points' => $points === null ? null : round($points),
'overall' => $overall,
@@ -1290,6 +1341,99 @@ if ($action === 'data') {
margin-top: 4px;
}
.flow-head {
font-weight: 900;
font-size: 1.05rem;
color: var(--c-ink);
margin: 4px 0 10px;
}
.flow-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 14px;
}
.fl-card {
display: block;
text-decoration: none;
color: inherit;
background: linear-gradient(135deg, #eff6ff, #fff);
border: 1px solid #dbeafe;
border-radius: 16px;
padding: 14px 16px;
box-shadow: 0 6px 18px rgba(15, 23, 42, .05);
transition: transform .15s ease, box-shadow .15s ease;
}
.fl-card:hover {
transform: translateY(-2px);
box-shadow: 0 12px 26px rgba(15, 23, 42, .1);
color: inherit;
}
.fl-t {
font-size: .78rem;
font-weight: 800;
text-transform: uppercase;
letter-spacing: .5px;
color: #1d4ed8;
}
.fl-row {
display: flex;
justify-content: space-between;
align-items: flex-end;
gap: 10px;
margin-top: 6px;
}
.fl-n {
font-size: 2.1rem;
font-weight: 900;
line-height: 1;
color: var(--c-ink);
}
.fl-v {
font-size: 1.35rem;
font-weight: 800;
color: var(--c-ink);
line-height: 1.1;
}
.fl-l {
font-size: .8rem;
color: var(--c-muted);
margin-top: 4px;
}
.fl-d {
font-weight: 800;
margin-left: 4px;
white-space: nowrap;
}
.fl-d.up {
color: #16a34a;
}
.fl-d.down {
color: #dc2626;
}
.fl-d.flat {
color: #64748b;
}
.fl-vs {
font-size: .76rem;
color: var(--c-muted);
margin-top: 8px;
border-top: 1px dashed #dbeafe;
padding-top: 6px;
}
.goodbad {
display: grid;
grid-template-columns: 1fr 1fr;
@@ -1688,6 +1832,10 @@ if ($action === 'data') {
<div class="ring" id="heroRing" style="--p:0;"><span id="heroPoints">—<small>PUNTEGGIO</small></span></div>
</div>
<!-- ORDINI IN ARRIVO -->
<div class="flow-head"><span data-help="sm.flow"><i class="fa-solid fa-inbox me-2"></i>Nuovi ordini</span></div>
<div class="flow-grid mb-3" id="flow"></div>
<div class="goodbad mb-2">
<div class="gb-card good">
<h6><i class="fa-solid fa-circle-check me-1"></i> Cosa va bene</h6>
@@ -1720,7 +1868,7 @@ if ($action === 'data') {
<div class="legend-strip">
<span><span class="dot green"></span> Bene</span>
<span><span class="dot yellow"></span> Così così: da tenere d'occhio</span>
<span><span class="dot red"></span> Da Migliorare: serve un intervento</span>
<span><span class="dot red"></span> Male: serve un intervento</span>
<span><span class="dot grey"></span> Dato non disponibile</span>
<span class="ms-auto">Clicca una tessera per i dettagli · ⓘ per la spiegazione</span>
</div>
@@ -1754,7 +1902,7 @@ if ($action === 'data') {
const LIGHT_LABEL = {
green: 'Bene',
yellow: 'Così così',
red: 'Da Migliorare',
red: 'Male',
grey: 'n.d.'
};
const LIGHT_ICON = {
@@ -1816,6 +1964,7 @@ if ($action === 'data') {
}
$('#content').show();
renderHero(d);
renderFlow(d);
renderGoodBad(d);
renderTiles(d);
renderLists(d);
@@ -1859,6 +2008,39 @@ if ($action === 'data') {
$('#heroPoints').html(`${d.points === null ? '—' : d.points}<small>SU 100</small>`);
}
/* ---------------- NUOVI ORDINI ---------------- */
function arrow(cur, prev) {
if (!prev && !cur) return '<span class="fl-d flat">= come prima</span>';
if (!prev) return '<span class="fl-d up">▲ nuovo</span>';
const p = (cur - prev) / Math.abs(prev) * 100;
const r = Math.round(p);
if (Math.abs(r) < 1) return '<span class="fl-d flat">= stabile</span>';
return `<span class="fl-d ${r > 0 ? 'up' : 'down'}">${r > 0 ? '▲' : '▼'} ${Math.abs(r)}%</span>`;
}
function renderFlow(d) {
const icons = {
today: 'fa-sun',
week: 'fa-calendar-week',
month: 'fa-calendar'
};
$('#flow').html((d.flow || []).map(f => `
<a class="fl-card" href="sales_orders_stats.php" title="Apri Andamento ordini">
<div class="fl-top"><span class="fl-t"><i class="fa-solid ${icons[f.key]} me-1"></i>${esc(f.title)}</span></div>
<div class="fl-row">
<div>
<div class="fl-n">${f.n.toLocaleString('it-IT')}</div>
<div class="fl-l">ordini ${arrow(f.n, f.np)}</div>
</div>
<div class="text-end">
<div class="fl-v">${fmtEurShort(f.v)}</div>
<div class="fl-l">valore ${arrow(f.v, f.vp)}</div>
</div>
</div>
<div class="fl-vs">vs ${esc(f.vs)}: ${f.np.toLocaleString('it-IT')} ordini · ${fmtEurShort(f.vp)}${f.customers !== undefined ? ` · ${f.customers} clienti nel mese` : ''}</div>
</a>`).join(''));
}
function renderGoodBad(d) {
const ok = d.tiles.filter(t => t.light === 'green' && t.verdict);
const ko = d.tiles.filter(t => (t.light === 'red' || t.light === 'yellow') && t.verdict)
@@ -2019,7 +2201,7 @@ if ($action === 'data') {
});
})();
</script>
<script src="sales_help.js?v=2"></script>
<script src="sales_help.js?v=3"></script>
</body>
</html>