Files
html/lean-6sigma.html
Opus c7994d48be
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
phase45 doctrine 183 inject 29 pages PRIO3 - 121 pages UX total
29 pages PRIO3 enrichies via inject-d60-direct.py:
registries: wtp-orphans-registry agents-unified-registry ia-sovereign-registry
hubs: wevia-hub vsm-hub wevads-hub weval-data-hub wevia-unified-hub tools-hub toolhub
dashboards: office-365-dashboard-live crm-pipeline-live orphans-dashboard
           medreach-dashboard wevia-director-dashboard security-dashboard
           wevia-memory-dashboard
monitors: sso-monitor monitoring
centers: mega-command-center trust-center
studios: bpmn-studio-live admin-saas
others: ethica-hcp-manager ops-screens-live vsm-pipelines lean-6sigma
        office-admins weval-live-ops

Cumul session Opus:
- 121 pages UX doctrine 60 (92 + 29)
- 31 tags Opus (avec phase45)
- 28 doctrines vault (146-183)

Handler inject-d60-direct.py prouve robuste sur 65+ pages consecutives.
ZERO regression. ZERO ecrasement. NR 153/153 invariant.
2026-04-24 14:25:37 +02:00

229 lines
17 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html><html lang="fr"><head><meta charset="UTF-8"><title>Lean 6σ Dashboard — WEVIA EM</title><style>
*{box-sizing:border-box;margin:0;padding:0}body{font-family:-apple-system,sans-serif;background:#0a0e1a;color:#e2e8f0;padding:20px}
.hd{background:linear-gradient(135deg,#dc2626,#991b1b);padding:22px 28px;border-radius:12px;margin-bottom:20px}
.hd h1{color:white;font-size:26px}.hd .sub{color:rgba(255,255,255,.85);margin-top:6px;font-size:13px}
.maturity{display:grid;grid-template-columns:1fr auto;gap:20px;align-items:center;background:linear-gradient(135deg,#7c2d12,#431407);padding:20px;border-radius:12px;margin-bottom:20px}
.maturity .label{font-size:13px;color:#fcd34d}
.maturity .score{font-size:56px;font-weight:900;color:#fbbf24;font-family:monospace}
.maturity .bar{height:8px;background:#1e293b;border-radius:4px;overflow:hidden;margin-top:8px}
.maturity .bar-fill{height:100%;background:linear-gradient(90deg,#dc2626,#fbbf24,#22c55e);transition:width .5s}
.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px;margin-bottom:20px}
.card{background:#111827;border:1px solid #1e293b;border-radius:10px;padding:16px;position:relative;transition:all .2s}
.card:hover{border-color:#dc2626;transform:translateY(-2px)}
.card h3{font-size:13px;color:#fbbf24;text-transform:uppercase;letter-spacing:1px;margin-bottom:8px}
.card .n{font-size:32px;font-weight:800;color:#e2e8f0;font-family:monospace}
.card .unit{font-size:14px;color:#64748b;margin-left:4px}
.card .l{font-size:11px;color:#94a3b8;margin-top:6px}
.card .icon{position:absolute;top:16px;right:16px;font-size:22px;opacity:.7}
.section{margin-top:28px}
.section h2{color:#fbbf24;font-size:16px;margin-bottom:12px;border-bottom:1px solid #1e293b;padding-bottom:6px}
table{width:100%;border-collapse:collapse;background:#111827;border-radius:8px;overflow:hidden}
th{background:#1e293b;color:#fbbf24;text-align:left;padding:10px;font-size:11px;text-transform:uppercase;letter-spacing:1px}
td{padding:10px;border-top:1px solid #1e293b;font-size:12px}
.badge{padding:2px 8px;border-radius:4px;font-size:10px;font-weight:600}
.sev-5{background:rgba(220,38,38,.2);color:#f87171}
.sev-4{background:rgba(234,88,12,.2);color:#fb923c}
.sev-3{background:rgba(234,179,8,.2);color:#facc15}
.sev-2{background:rgba(34,197,94,.2);color:#4ade80}
.sev-1{background:rgba(59,130,246,.2);color:#60a5fa}
.status-completed{background:rgba(34,197,94,.2);color:#22c55e}
.status-in-progress{background:rgba(234,179,8,.2);color:#facc15}
.status-identified{background:rgba(59,130,246,.2);color:#60a5fa}
.status-analyzed{background:rgba(168,85,247,.2);color:#c084fc}
.status-fixed{background:rgba(34,197,94,.2);color:#22c55e}
.status-fixing{background:rgba(234,179,8,.2);color:#facc15}
.status-planned{background:rgba(107,114,128,.2);color:#9ca3af}
.andon-red{color:#f87171}.andon-yellow{color:#facc15}.andon-green{color:#4ade80}
.tabs{display:flex;gap:6px;margin:20px 0;border-bottom:1px solid #1e293b;overflow-x:auto}
.tab{padding:10px 16px;cursor:pointer;border-bottom:3px solid transparent;font-size:12px;font-weight:600;color:#94a3b8;white-space:nowrap}
.tab.active{border-color:#fbbf24;color:#fbbf24}
.panel{display:none}.panel.active{display:block}
.tenant-sel{display:flex;gap:10px;align-items:center;margin-bottom:16px}
.tenant-sel select{padding:8px;background:#111827;border:1px solid #1e293b;color:#e2e8f0;border-radius:6px}
</style><!-- DOCTRINE-60-UX-ENRICH direct-inject-20260424-142453 -->
<style id="doctrine60-ux-direct">
/* DOCTRINE-60-UX-ENRICH injected-direct */
body::before {
content: '';
position: fixed;
top: 0; left: 0; width: 100vw; height: 100vh;
background: radial-gradient(circle at 50% 50%, rgba(100,180,255,0.08), transparent 60%);
pointer-events: none;
z-index: -1;
}
.card, .kpi, .panel, .btn {
transition: all 0.3s cubic-bezier(0.2,0,0.1,1);
}
.card:hover, .kpi:hover, .panel:hover {
box-shadow: 0 4px 20px rgba(100,180,255,0.2);
border-color: rgba(100,180,255,0.5);
}
@keyframes pulseD60 {
0%,100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.7; transform: scale(1.05); }
}
.pulse, .live-indicator, .active, .online {
animation: pulseD60 3s ease-in-out infinite;
}
.modal, .chat, .speech, .overlay {
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
}
.enter-stagger {
animation: enterStagD60 0.5s cubic-bezier(0.2,0,0.1,1) forwards;
}
@keyframes enterStagD60 {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
</style>
</head><body>
<div class="hd"><h1>🎯 Lean 6σ Dashboard</h1><div class="sub">Muda · Poka-Yoke · Kaizen · Gemba · PDCA · Andon · 5S · A3 — pilotage opérationnel WEVIA EM</div></div>
<div class="tenant-sel"><label>Tenant:</label><select id="tenant" onchange="reload()"></select></div>
<div class="maturity">
<div>
<div class="label">MATURITY SCORE (Lean 6σ global)</div>
<div class="bar"><div class="bar-fill" id="mat-bar" style="width:0%"></div></div>
<div style="font-size:11px;color:#fcd34d;margin-top:6px">Composé de: 5S (30%) + Poka-Yoke efficiency (30%) + Kaizen volume (20%) + Gemba frequency (20%)</div>
</div>
<div class="score" id="mat-score">-</div>
</div>
<div class="grid" id="stats">Chargement...</div>
<div class="tabs">
<div class="tab active" onclick="swt(event,'muda')">🗑️ Muda</div>
<div class="tab" onclick="swt(event,'poka')">🛡️ Poka-Yoke</div>
<div class="tab" onclick="swt(event,'kaizen')">📈 Kaizen</div>
<div class="tab" onclick="swt(event,'gemba')">🚶 Gemba</div>
<div class="tab" onclick="swt(event,'pdca')">🔄 PDCA</div>
<div class="tab" onclick="swt(event,'andon')">🚨 Andon</div>
<div class="tab" onclick="swt(event,'5s')">🧹 5S</div>
<div class="tab" onclick="swt(event,'a3')">📋 A3</div>
</div>
<div id="panel-muda" class="panel active"><table><thead><tr><th>Type</th><th>Sev</th><th>Description</th><th>VS</th><th>Impact €</th><th>Status</th></tr></thead><tbody id="muda-body"></tbody></table></div>
<div id="panel-poka" class="panel"><table><thead><tr><th>Process</th><th>Device</th><th>Mécanisme</th><th>Validation</th><th>Efficacité</th></tr></thead><tbody id="poka-body"></tbody></table></div>
<div id="panel-kaizen" class="panel"><table><thead><tr><th>Titre</th><th>Dept</th><th>Problème</th><th>Savings €</th><th>Savings h</th><th>Durée</th><th>Status</th></tr></thead><tbody id="kaizen-body"></tbody></table></div>
<div id="panel-gemba" class="panel"><table><thead><tr><th>Date</th><th>Location</th><th>Walker</th><th>Observations</th><th>Actions</th><th>Muda</th><th>Durée</th></tr></thead><tbody id="gemba-body"></tbody></table></div>
<div id="panel-pdca" class="panel"><table><thead><tr><th>Titre</th><th>Phase</th><th>KPI</th><th>Baseline</th><th>Target</th><th>Actual</th><th>Gap</th></tr></thead><tbody id="pdca-body"></tbody></table></div>
<div id="panel-andon" class="panel"><table><thead><tr><th>Station</th><th>Sev</th><th>Message</th><th>Status</th><th>Résolution</th><th>Time</th></tr></thead><tbody id="andon-body"></tbody></table></div>
<div id="panel-5s" class="panel"><table><thead><tr><th>Area</th><th>Seiri</th><th>Seiton</th><th>Seiso</th><th>Seiketsu</th><th>Shitsuke</th><th>Total /25</th><th>Auditeur</th></tr></thead><tbody id="fives-body"></tbody></table></div>
<div id="panel-a3" class="panel"><table><thead><tr><th>Titre</th><th>Status</th><th>Background</th><th>Gap Analysis</th><th>Root Causes</th><th>Owner</th></tr></thead><tbody id="a3-body"></tbody></table></div>
<script>
const T=()=>document.getElementById('tenant').value||'weval';
async function loadTenants(){const r=await fetch('/api/em/tenant');const d=await r.json();const s=document.getElementById('tenant');s.innerHTML=(d.tenants||[]).map(t=>`<option value="${t.tenant_id}">${t.tenant_id}${t.name}</option>`).join('')}
function swt(e,p){document.querySelectorAll('.tab').forEach(x=>x.classList.remove('active'));e.target.classList.add('active');document.querySelectorAll('.panel').forEach(x=>x.classList.remove('active'));document.getElementById('panel-'+p).classList.add('active')}
async function loadDash(){
const d=await fetch(`/api/em/lean6sigma-dashboard?tenant=${T()}`).then(r=>r.json());
const m=d.maturity_score||0;
document.getElementById('mat-score').textContent=m;
document.getElementById('mat-bar').style.width=m+'%';
document.getElementById('stats').innerHTML=`
<div class="card"><div class="icon">🗑️</div><h3>Muda</h3><div class="n">${d.muda?.count||0}</div><div class="l">${(d.muda?.impact_euro||0).toLocaleString()}€ impact · ${d.muda?.impact_hours||0}h</div></div>
<div class="card"><div class="icon">🛡️</div><h3>Poka-Yoke</h3><div class="n">${d.poka_yoke?.count||0}</div><div class="l">${d.poka_yoke?.avg_efficiency_pct||0}% efficacité moyenne</div></div>
<div class="card"><div class="icon">📈</div><h3>Kaizen</h3><div class="n">${d.kaizen?.count||0}</div><div class="l">${(d.kaizen?.total_savings_euro||0).toLocaleString()}€ économisés</div></div>
<div class="card"><div class="icon">🚶</div><h3>Gemba</h3><div class="n">${d.gemba?.walks||0}</div><div class="l">${d.gemba?.muda_spotted||0} muda spotted</div></div>
<div class="card"><div class="icon">🔄</div><h3>PDCA Active</h3><div class="n">${d.pdca_active||0}</div><div class="l">Cycles Plan/Do/Check</div></div>
<div class="card"><div class="icon">🚨</div><h3>Andon Open</h3><div class="n">${d.andon_open||0}</div><div class="l">Alertes actives</div></div>
<div class="card"><div class="icon">🧹</div><h3>5S Avg</h3><div class="n">${d.five_s_avg_score||0}<span class="unit">/25</span></div><div class="l">Maturité 5S</div></div>
<div class="card"><div class="icon">📋</div><h3>A3 Open</h3><div class="n">${d.a3_open||0}</div><div class="l">Problem-solving actifs</div></div>`;
}
async function loadMuda(){const d=await fetch(`/api/em/muda?tenant=${T()}`).then(r=>r.json());document.getElementById('muda-body').innerHTML=(d.entries||[]).map(e=>`<tr><td>${e.muda_type}</td><td><span class="badge sev-${e.severity}">sev${e.severity}</span></td><td>${e.description}</td><td>${e.vs_id||'-'}</td><td>${Number(e.impact_euro||0).toLocaleString()}€</td><td><span class="badge status-${e.status}">${e.status}</span></td></tr>`).join('')}
async function loadPoka(){const d=await fetch(`/api/em/poka-yoke?tenant=${T()}`).then(r=>r.json());document.getElementById('poka-body').innerHTML=(d.devices||[]).map(p=>`<tr><td>${p.process}</td><td><span class="badge">${p.device_type}</span></td><td>${p.mechanism}</td><td>${p.validation}</td><td>${p.efficiency_pct}%</td></tr>`).join('')}
async function loadKaizen(){const d=await fetch(`/api/em/kaizen?tenant=${T()}`).then(r=>r.json());document.getElementById('kaizen-body').innerHTML=(d.events||[]).map(k=>`<tr><td>${k.title}</td><td>${k.dept}</td><td>${k.problem}</td><td>${Number(k.savings_euro||0).toLocaleString()}€</td><td>${k.savings_hours||0}h</td><td>${k.duration_days||0}j</td><td><span class="badge status-${k.status}">${k.status}</span></td></tr>`).join('')}
async function loadGemba(){const d=await fetch(`/api/em/gemba?tenant=${T()}`).then(r=>r.json());document.getElementById('gemba-body').innerHTML=(d.walks||[]).map(w=>`<tr><td>${new Date(w.created_at).toLocaleDateString()}</td><td>${w.location}</td><td>${w.walker}</td><td>${(w.observations||[]).length} obs</td><td>${(w.actions||[]).length} actions</td><td>${w.muda_spotted}</td><td>${w.walk_duration_min}min</td></tr>`).join('')}
async function loadPdca(){const d=await fetch(`/api/em/pdca?tenant=${T()}`).then(r=>r.json());document.getElementById('pdca-body').innerHTML=(d.cycles||[]).map(p=>{const gap=p.actual&&p.target?((p.actual-p.target)/Math.max(1,p.target)*100).toFixed(1)+'%':'-';return `<tr><td>${p.title}</td><td><span class="badge">${p.phase}</span></td><td>${p.kpi_name}</td><td>${p.baseline}</td><td>${p.target}</td><td>${p.actual||'-'}</td><td>${gap}</td></tr>`}).join('')}
async function loadAndon(){const d=await fetch(`/api/em/andon?tenant=${T()}`).then(r=>r.json());document.getElementById('andon-body').innerHTML=(d.alerts||[]).map(a=>`<tr><td>${a.station}</td><td class="andon-${a.severity}">●${a.severity}</td><td>${a.message}</td><td><span class="badge status-${a.status==='open'?'in-progress':'completed'}">${a.status}</span></td><td>${a.resolved_by||'-'}</td><td>${a.resolution_time_min||'-'}min</td></tr>`).join('')}
async function loadFiveS(){const d=await fetch(`/api/em/five-s?tenant=${T()}`).then(r=>r.json());document.getElementById('fives-body').innerHTML=(d.audits||[]).map(a=>`<tr><td>${a.area}</td><td>${a.seiri}</td><td>${a.seiton}</td><td>${a.seiso}</td><td>${a.seiketsu}</td><td>${a.shitsuke}</td><td><strong>${a.total_score}/25</strong></td><td>${a.auditor}</td></tr>`).join('')}
async function loadA3(){const d=await fetch(`/api/em/a3?tenant=${T()}`).then(r=>r.json());document.getElementById('a3-body').innerHTML=(d.reports||[]).map(r=>`<tr><td>${r.title}</td><td><span class="badge status-${r.status}">${r.status}</span></td><td>${(r.background||'').substring(0,100)}...</td><td>${(r.gap_analysis||'').substring(0,80)}...</td><td>${(r.root_causes||[]).length} causes</td><td>${r.owner}</td></tr>`).join('')}
async function reload(){await loadDash();await loadMuda();await loadPoka();await loadKaizen();await loadGemba();await loadPdca();await loadAndon();await loadFiveS();await loadA3()}
(async()=>{await loadTenants();await reload()})();
</script>
<!-- === OPUS UNIVERSAL DRILL-DOWN v1 19avr — append-only, doctrine #14 === -->
<script>
(function(){
if (window.__opusUniversalDrill) return; window.__opusUniversalDrill = true;
var d = document;
var m = d.createElement('div');
m.id = 'opus-udrill';
m.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,0.82);backdrop-filter:blur(6px);display:none;align-items:center;justify-content:center;z-index:99995;padding:20px;cursor:pointer';
var inner = d.createElement('div');
inner.id = 'opus-udrill-in';
inner.style.cssText = 'max-width:900px;width:100%;max-height:90vh;overflow:auto;background:#0b0d15;border:1px solid rgba(99,102,241,0.35);border-radius:14px;padding:28px;cursor:default;box-shadow:0 20px 60px rgba(0,0,0,0.6);color:#e2e8f0;font:14px/1.55 Inter,system-ui,sans-serif';
inner.addEventListener('click', function(e){ e.stopPropagation(); });
m.appendChild(inner);
m.addEventListener('click', function(){ m.style.display='none'; });
d.addEventListener('keydown', function(e){ if(e.key==='Escape') m.style.display='none'; });
(d.body || d.documentElement).appendChild(m);
function openCard(card) {
// Clone card content + show close btn + increase font-size
var html = '<div style="display:flex;justify-content:flex-end;margin-bottom:14px"><button id="opus-udrill-close" style="padding:6px 14px;background:#171b2a;border:1px solid rgba(99,102,241,0.25);color:#e2e8f0;border-radius:8px;cursor:pointer;font-size:12px">✕ Fermer (Esc)</button></div>';
html += '<div style="transform-origin:top left;font-size:1.05em">' + card.outerHTML + '</div>';
inner.innerHTML = html;
d.getElementById('opus-udrill-close').onclick = function(){ m.style.display='none'; };
m.style.display = 'flex';
}
function wire(root) {
var sels = '.card,[class*="card"],.kpi,[class*="kpi"],.stat,[class*="stat"],.tile,[class*="tile"],.metric,[class*="metric"],.widget,[class*="widget"]';
var cards = root.querySelectorAll(sels);
for (var i = 0; i < cards.length; i++) {
var c = cards[i];
if (c.__opusWired) continue;
if (c.closest('button, a, input, select, textarea, #opus-udrill')) continue;
var r = c.getBoundingClientRect();
if (r.width < 60 || r.height < 40) continue;
c.__opusWired = true;
c.style.cursor = 'pointer';
c.setAttribute('role','button');
c.setAttribute('tabindex','0');
c.addEventListener('click', function(ev){
// If a more-specific drill is already active (e.g. pp-card custom), let it handle
if (ev.target.closest('[data-pp-id]') && window.__opusDrillInit) return;
if (ev.target.closest('a,button,input,select')) return;
ev.preventDefault(); ev.stopPropagation();
openCard(this);
});
c.addEventListener('keydown', function(ev){ if(ev.key==='Enter'||ev.key===' '){ev.preventDefault();openCard(this);} });
}
}
// Initial + mutation observer
var initRun = function(){ wire(d.body || d.documentElement); };
if (d.readyState === 'loading') d.addEventListener('DOMContentLoaded', initRun);
else initRun();
var mo = new MutationObserver(function(muts){
var newCard = false;
for (var i=0;i<muts.length;i++) if (muts[i].addedNodes.length) { newCard = true; break; }
if (newCard) initRun();
});
mo.observe(d.body || d.documentElement, {childList:true, subtree:true});
})();
</script>
<!-- === OPUS UNIVERSAL DRILL-DOWN END === -->
<script src="/api/archi-meta-badge.js" defer></script>
<script src="/api/a11y-auto-enhancer.js" defer></script>
<!-- WTP_UDOCK_V1 (Opus 21-avr t34final) --><script src="/wtp-unified-dock.js" defer></script>
<script src="/opus-antioverlap-doctrine.js?v=1776776094" defer></script>
<!-- DOCTRINE-60-UX-JS --><script id="doctrine60-ux-js-direct">
// DOCTRINE-60-UX-JS staggered entrance
(function(){
if (!('IntersectionObserver' in window)) return;
const obs = new IntersectionObserver((entries) => {
entries.forEach((e, i) => {
if (e.isIntersecting) {
setTimeout(() => e.target.classList.add('enter-stagger'), i * 80);
obs.unobserve(e.target);
}
});
});
document.querySelectorAll('.card, .kpi, .panel').forEach(el => obs.observe(el));
})();
</script>
</body></html>