producstion pause
This commit is contained in:
@@ -286,6 +286,7 @@ if (!empty($_GET['ajax'])) {
|
||||
}
|
||||
|
||||
.kpi-card {
|
||||
position: relative;
|
||||
background: #fff;
|
||||
border-radius: 1rem;
|
||||
padding: 1.1rem 1.2rem;
|
||||
@@ -339,6 +340,7 @@ if (!empty($_GET['ajax'])) {
|
||||
}
|
||||
|
||||
.chart-card {
|
||||
position: relative;
|
||||
background: #fff;
|
||||
border-radius: 1rem;
|
||||
padding: 1.1rem 1.2rem;
|
||||
@@ -354,6 +356,7 @@ if (!empty($_GET['ajax'])) {
|
||||
color: #1e293b;
|
||||
margin: 0 0 .8rem;
|
||||
font-size: .95rem;
|
||||
padding-right: 1.8rem;
|
||||
}
|
||||
|
||||
.chart-wrap {
|
||||
@@ -362,6 +365,7 @@ if (!empty($_GET['ajax'])) {
|
||||
}
|
||||
|
||||
.table-card {
|
||||
position: relative;
|
||||
background: #fff;
|
||||
border-radius: 1rem;
|
||||
padding: 1.1rem 1.2rem;
|
||||
@@ -374,6 +378,7 @@ if (!empty($_GET['ajax'])) {
|
||||
font-weight: 700;
|
||||
color: #1e293b;
|
||||
margin: 0 0 .8rem;
|
||||
padding-right: 1.8rem;
|
||||
}
|
||||
|
||||
table.stats-table {
|
||||
@@ -442,6 +447,69 @@ if (!empty($_GET['ajax'])) {
|
||||
padding: 3rem;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
/* --- PULSANTINO "?" INFO --- */
|
||||
.info-btn {
|
||||
position: absolute;
|
||||
top: .6rem;
|
||||
right: .6rem;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
background: #e2e8f0;
|
||||
color: #475569;
|
||||
font-size: .72rem;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
transition: .15s;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.info-btn:hover {
|
||||
background: #dc2626;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.info-pop {
|
||||
position: absolute;
|
||||
top: 2.1rem;
|
||||
right: .6rem;
|
||||
width: 250px;
|
||||
max-width: 80vw;
|
||||
background: #0f172a;
|
||||
color: #f1f5f9;
|
||||
border-radius: .6rem;
|
||||
padding: .7rem .8rem;
|
||||
font-size: .8rem;
|
||||
line-height: 1.4;
|
||||
font-weight: 400;
|
||||
text-transform: none;
|
||||
letter-spacing: normal;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, .25);
|
||||
z-index: 50;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.info-pop.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.info-pop strong {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.info-pop .info-pop-title {
|
||||
display: block;
|
||||
font-weight: 800;
|
||||
margin-bottom: .25rem;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
@@ -496,28 +564,34 @@ if (!empty($_GET['ajax'])) {
|
||||
|
||||
<div class="charts-grid" id="chartsGrid" style="display:none;">
|
||||
<div class="chart-card wide">
|
||||
<button type="button" class="info-btn" data-title="Pareto delle causali" data-info="Il grafico più utile. Le barre sono le ore perse per ogni causa, ordinate dalla peggiore. La linea sale e mostra la somma progressiva in percentuale. Regola pratica: poche cause fanno la maggior parte del tempo perso. Concentrati sulle prime 2-3 barre a sinistra.">?</button>
|
||||
<h6>Pareto causali — tempo perso e cumulata</h6>
|
||||
<div class="chart-wrap"><canvas id="chartPareto"></canvas></div>
|
||||
</div>
|
||||
<div class="chart-card">
|
||||
<button type="button" class="info-btn" data-title="Pianificato vs non pianificato" data-info="La fetta di tempo perso previsto (arancione, es. cambio turno, pulizia) contro quello imprevisto (rosso, es. guasti). Una torta sbilanciata verso il rosso significa molte perdite evitabili.">?</button>
|
||||
<h6>Ripartizione tempo: pianificato vs non pianificato</h6>
|
||||
<div class="chart-wrap"><canvas id="chartCat"></canvas></div>
|
||||
</div>
|
||||
<div class="chart-card">
|
||||
<button type="button" class="info-btn" data-title="Tempo perso per linea" data-info="Quale linea perde più ore di produzione a causa dei fermi. Individua la linea più problematica su cui concentrare le attenzioni.">?</button>
|
||||
<h6>Tempo perso per linea (ore)</h6>
|
||||
<div class="chart-wrap"><canvas id="chartLinea"></canvas></div>
|
||||
</div>
|
||||
<div class="chart-card">
|
||||
<button type="button" class="info-btn" data-title="Numero fermi per causale" data-info="Quante volte si verifica ogni causa (la frequenza, non la durata). Una causa che compare tante volte anche se breve indica un problema ricorrente da eliminare alla radice.">?</button>
|
||||
<h6>Numero fermi per causale</h6>
|
||||
<div class="chart-wrap"><canvas id="chartCount"></canvas></div>
|
||||
</div>
|
||||
<div class="chart-card">
|
||||
<button type="button" class="info-btn" data-title="Andamento giornaliero" data-info="Le ore perse giorno per giorno. Individua le giornate nere e cerca cosa è successo (un guasto grave, una fornitura mancata).">?</button>
|
||||
<h6>Andamento fermi giornaliero (ore)</h6>
|
||||
<div class="chart-wrap"><canvas id="chartGiorno"></canvas></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-card" id="tableCard" style="display:none;">
|
||||
<button type="button" class="info-btn" data-title="Dettaglio eventi" data-info="Ogni riga è un singolo fermo: inizio, fine, durata, motivo, tipo (Problema o Normale), categoria (Pianificato o Non pianificato), linea, matrice e la nota dell'operatore. Il massimo dettaglio per ricostruire cosa è successo in un momento preciso.">?</button>
|
||||
<h6>Dettaglio eventi di pausa</h6>
|
||||
<table class="stats-table">
|
||||
<thead>
|
||||
@@ -579,15 +653,49 @@ if (!empty($_GET['ajax'])) {
|
||||
}
|
||||
}
|
||||
|
||||
// Testi spiegazione per i KPI
|
||||
const KPI_INFO = {
|
||||
n_pause: {
|
||||
t: "Fermi totali",
|
||||
d: "Quante volte le linee si sono fermate in pausa nel periodo. Sotto, quante lavorazioni sono state coinvolte."
|
||||
},
|
||||
tot: {
|
||||
t: "Tempo perso",
|
||||
d: "Il totale di tutte le pause sommate: il costo in tempo complessivo dei fermi. Confrontalo tra periodi per vedere se migliora."
|
||||
},
|
||||
media: {
|
||||
t: "Durata media",
|
||||
d: "Quanto dura in media un singolo fermo (accanto, il fermo più lungo). Se il massimo è molto più alto della media, c'è stato un episodio eccezionale da approfondire."
|
||||
},
|
||||
problemi: {
|
||||
t: "Problemi tecnici",
|
||||
d: "Quanti fermi erano dovuti a un guasto o anomalia vera, e la loro percentuale sul totale. È la spia della salute degli impianti."
|
||||
},
|
||||
planned: {
|
||||
t: "Pianificato",
|
||||
d: "Il tempo dei fermi previsti (cambio turno, pulizia, manutenzione programmata...). È tempo normale, in parte inevitabile."
|
||||
},
|
||||
unplanned: {
|
||||
t: "Non pianificato",
|
||||
d: "Il tempo dei fermi imprevisti (guasti, mancanza materiale, qualità...). È QUESTO il tempo da ridurre: sono le perdite evitabili."
|
||||
},
|
||||
};
|
||||
|
||||
function infoBtn(key) {
|
||||
const i = KPI_INFO[key];
|
||||
if (!i) return '';
|
||||
return `<button type="button" class="info-btn" data-title="${i.t}" data-info="${i.d.replace(/"/g,'"')}">?</button>`;
|
||||
}
|
||||
|
||||
function renderKpi(k) {
|
||||
const pctProblemi = k.n_pause > 0 ? Math.round(k.n_problemi / k.n_pause * 100) : 0;
|
||||
$('#kpiGrid').html(`
|
||||
<div class="kpi-card"><div class="kpi-label">Fermi totali</div><div class="kpi-value">${k.n_pause}</div><div class="kpi-sub">${k.n_prod_con_pause} produzioni coinvolte</div></div>
|
||||
<div class="kpi-card"><div class="kpi-label">Tempo perso</div><div class="kpi-value" style="font-size:1.25rem;">${secToHms(k.tot_s)}</div><div class="kpi-sub">totale fermi</div></div>
|
||||
<div class="kpi-card slate"><div class="kpi-label">Durata media</div><div class="kpi-value" style="font-size:1.25rem;">${secToHms(k.media_s)}</div><div class="kpi-sub">max ${secToHms(k.max_s)}</div></div>
|
||||
<div class="kpi-card red"><div class="kpi-label">Problemi tecnici</div><div class="kpi-value">${k.n_problemi}</div><div class="kpi-sub">${pctProblemi}% dei fermi</div></div>
|
||||
<div class="kpi-card green"><div class="kpi-label">Pianificato</div><div class="kpi-value" style="font-size:1.25rem;">${secToHms(k.planned_s)}</div><div class="kpi-sub">fermi previsti</div></div>
|
||||
<div class="kpi-card amber"><div class="kpi-label">Non pianificato</div><div class="kpi-value" style="font-size:1.25rem;">${secToHms(k.unplanned_s)}</div><div class="kpi-sub">da ridurre</div></div>
|
||||
<div class="kpi-card">${infoBtn('n_pause')}<div class="kpi-label">Fermi totali</div><div class="kpi-value">${k.n_pause}</div><div class="kpi-sub">${k.n_prod_con_pause} produzioni coinvolte</div></div>
|
||||
<div class="kpi-card">${infoBtn('tot')}<div class="kpi-label">Tempo perso</div><div class="kpi-value" style="font-size:1.25rem;">${secToHms(k.tot_s)}</div><div class="kpi-sub">totale fermi</div></div>
|
||||
<div class="kpi-card slate">${infoBtn('media')}<div class="kpi-label">Durata media</div><div class="kpi-value" style="font-size:1.25rem;">${secToHms(k.media_s)}</div><div class="kpi-sub">max ${secToHms(k.max_s)}</div></div>
|
||||
<div class="kpi-card red">${infoBtn('problemi')}<div class="kpi-label">Problemi tecnici</div><div class="kpi-value">${k.n_problemi}</div><div class="kpi-sub">${pctProblemi}% dei fermi</div></div>
|
||||
<div class="kpi-card green">${infoBtn('planned')}<div class="kpi-label">Pianificato</div><div class="kpi-value" style="font-size:1.25rem;">${secToHms(k.planned_s)}</div><div class="kpi-sub">fermi previsti</div></div>
|
||||
<div class="kpi-card amber">${infoBtn('unplanned')}<div class="kpi-label">Non pianificato</div><div class="kpi-value" style="font-size:1.25rem;">${secToHms(k.unplanned_s)}</div><div class="kpi-sub">da ridurre</div></div>
|
||||
`);
|
||||
}
|
||||
|
||||
@@ -802,6 +910,7 @@ if (!empty($_GET['ajax'])) {
|
||||
$('#kpiGrid').html('<div class="empty">Errore di comunicazione con il server.</div>');
|
||||
});
|
||||
}
|
||||
|
||||
$(function() {
|
||||
const today = new Date(),
|
||||
past = new Date();
|
||||
@@ -823,6 +932,24 @@ if (!empty($_GET['ajax'])) {
|
||||
$('#fDateFrom').val(past.toISOString().slice(0, 10));
|
||||
loadStats();
|
||||
});
|
||||
|
||||
// --- POPOVER INFO (delegato: funziona anche sui box creati via JS) ---
|
||||
$(document).on('click', '.info-btn', function(e) {
|
||||
e.stopPropagation();
|
||||
const $btn = $(this);
|
||||
const alreadyOpen = $btn.next('.info-pop').length && $btn.next('.info-pop').hasClass('show');
|
||||
$('.info-pop').remove();
|
||||
if (alreadyOpen) return;
|
||||
const title = $btn.data('title') || '';
|
||||
const text = $btn.data('info') || '';
|
||||
const $pop = $('<div class="info-pop show"></div>');
|
||||
$pop.html('<span class="info-pop-title">' + title + '</span>' + text);
|
||||
$btn.after($pop);
|
||||
});
|
||||
$(document).on('click', function() {
|
||||
$('.info-pop').remove();
|
||||
});
|
||||
|
||||
loadStats();
|
||||
});
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user