474 lines
28 KiB
HTML
474 lines
28 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="fr">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<title>WEVAL · Enterprise Complete — 20 départements · 169 KPIs · Gap Agents · Macro Process</title>
|
||
<style>
|
||
:root{
|
||
--bg-0:#05060a; --bg-1:#0b0d15; --bg-2:#11141f; --bg-3:#171b2a; --bg-tile:#0f1420;
|
||
--border:rgba(99,102,241,0.15); --border-h:rgba(99,102,241,0.35);
|
||
--text:#e2e8f0; --dim:#94a3b8; --mute:#64748b;
|
||
--accent:#14b8a6; --accent2:#6366f1; --purple:#a855f7; --cyan:#06b6d4;
|
||
--ok:#22c55e; --warn:#f59e0b; --err:#ef4444; --rose:#f43f5e; --gold:#eab308;
|
||
--c-fin:#3b82f6; --c-sup:#06b6d4; --c-mfg:#f59e0b; --c-sales:#10b981;
|
||
--c-hr:#a855f7; --c-it:#ec4899; --c-legal:#64748b; --c-esg:#22c55e;
|
||
}
|
||
*{box-sizing:border-box;margin:0;padding:0}
|
||
body{font-family:'Inter',system-ui,sans-serif;background:radial-gradient(ellipse at top,#0f1420,#05060a 60%);color:var(--text);min-height:100vh;font-size:13px;line-height:1.5}
|
||
.container{max-width:1800px;margin:0 auto;padding:20px 26px 80px}
|
||
.shell{display:flex;justify-content:space-between;align-items:center;margin-bottom:14px;padding:12px 18px;background:var(--bg-1);border:1px solid var(--border);border-radius:10px}
|
||
.breadcrumb{font-size:12px;color:var(--dim)}
|
||
.breadcrumb a{color:var(--accent);text-decoration:none}
|
||
.breadcrumb .sep{margin:0 7px;color:var(--mute)}
|
||
.breadcrumb .current{color:var(--text);font-weight:600}
|
||
.shell h1{font-size:18px;font-weight:800;background:linear-gradient(90deg,#22d3ee,#a855f7,#eab308);-webkit-background-clip:text;background-clip:text;color:transparent}
|
||
.shell .pulse{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--ok);box-shadow:0 0 0 0 rgba(34,197,94,.7);animation:pulse 2s infinite;margin-right:6px;vertical-align:middle}
|
||
@keyframes pulse{0%,100%{box-shadow:0 0 0 0 rgba(34,197,94,.7)}70%{box-shadow:0 0 0 8px rgba(34,197,94,0)}}
|
||
.shell-actions{display:flex;gap:8px;flex-wrap:wrap}
|
||
.btn{padding:6px 12px;background:var(--bg-2);border:1px solid var(--border);color:var(--text);border-radius:6px;font-size:11.5px;cursor:pointer;text-decoration:none;font-family:inherit;transition:all .15s}
|
||
.btn:hover{border-color:var(--accent);color:var(--accent)}
|
||
.btn.primary{background:linear-gradient(135deg,var(--accent),var(--cyan));color:white;border:none;font-weight:600}
|
||
|
||
.kpi-super{display:grid;grid-template-columns:repeat(6,1fr);gap:10px;margin-bottom:14px}
|
||
@media(max-width:1200px){.kpi-super{grid-template-columns:repeat(3,1fr)}}
|
||
.ks{background:var(--bg-1);border:1px solid var(--border);border-radius:10px;padding:12px 14px;border-left:3px solid var(--accent);position:relative;overflow:hidden}
|
||
.ks.gold{border-left-color:var(--gold)}
|
||
.ks.danger{border-left-color:var(--err)}
|
||
.ks.cyan{border-left-color:var(--cyan)}
|
||
.ks.purple{border-left-color:var(--purple)}
|
||
.ks.ok{border-left-color:var(--ok)}
|
||
.ks .l{font-size:10px;color:var(--dim);text-transform:uppercase;letter-spacing:0.5px;font-weight:600}
|
||
.ks .v{font-size:22px;font-weight:800;margin-top:4px;line-height:1;font-family:'JetBrains Mono',monospace}
|
||
.ks .v.gold{background:linear-gradient(135deg,var(--gold),var(--warn));-webkit-background-clip:text;background-clip:text;color:transparent}
|
||
.ks .s{font-size:10px;color:var(--mute);margin-top:2px}
|
||
|
||
.filters{display:flex;gap:5px;flex-wrap:wrap;margin-bottom:14px;padding:8px 12px;background:var(--bg-1);border:1px solid var(--border);border-radius:10px;align-items:center}
|
||
.filters .lbl{font-size:11px;color:var(--dim);font-weight:700;margin-right:8px;text-transform:uppercase;letter-spacing:0.4px}
|
||
.fb{padding:5px 11px;background:var(--bg-3);border:1px solid var(--border);color:var(--dim);border-radius:14px;font-size:11px;cursor:pointer;font-family:inherit;transition:all .15s}
|
||
.fb:hover{color:var(--text);border-color:var(--accent)}
|
||
.fb.active{background:linear-gradient(135deg,var(--accent),var(--cyan));color:white;border:none;font-weight:700}
|
||
|
||
.sec-title{font-size:12px;font-weight:800;letter-spacing:2px;text-transform:uppercase;color:var(--dim);margin:22px 0 10px;padding-bottom:6px;border-bottom:1px solid var(--bg-3);display:flex;justify-content:space-between;align-items:center}
|
||
.sec-title .count{color:var(--accent);font-size:11px;letter-spacing:0}
|
||
|
||
.depts-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:12px;margin-bottom:22px}
|
||
.dept{background:var(--bg-tile);border:1px solid var(--border);border-radius:12px;overflow:hidden;transition:all .2s;cursor:pointer;display:flex;flex-direction:column}
|
||
.dept:hover{transform:translateY(-3px);border-color:var(--border-h);box-shadow:0 10px 30px rgba(0,0,0,0.4)}
|
||
.dept-head{padding:12px 14px;display:flex;align-items:center;gap:10px;position:relative;border-bottom:1px solid rgba(255,255,255,0.04)}
|
||
.dept-head::before{content:'';position:absolute;left:0;top:0;width:4px;height:100%;background:var(--dc)}
|
||
.dept-icon{font-size:28px;line-height:1}
|
||
.dept-meta{flex:1}
|
||
.dept-name{font-size:13px;font-weight:700;color:var(--text);line-height:1.2}
|
||
.dept-agents-info{font-size:10px;color:var(--mute);margin-top:3px;font-family:'JetBrains Mono',monospace}
|
||
.dept-status{padding:2px 7px;background:var(--bg-3);border-radius:10px;font-size:9px;font-weight:700;letter-spacing:0.3px;font-family:'JetBrains Mono',monospace;text-transform:uppercase}
|
||
.dept-status.ok{background:rgba(34,197,94,0.15);color:#86efac}
|
||
.dept-status.warn{background:rgba(245,158,11,0.15);color:#fbbf24}
|
||
.dept-status.critical{background:rgba(239,68,68,0.18);color:#fca5a5}
|
||
.dept-kpis{padding:10px 14px;flex:1}
|
||
.kpi-row{display:grid;grid-template-columns:1fr 80px 14px;gap:8px;align-items:center;padding:5px 0;font-size:11px;border-bottom:1px dashed var(--bg-3)}
|
||
.kpi-row:last-child{border-bottom:none}
|
||
.kpi-name{color:var(--dim);font-size:10.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||
.kpi-val{font-family:'JetBrains Mono',monospace;font-weight:700;color:var(--text);text-align:right;font-size:11px}
|
||
.kpi-dot{width:8px;height:8px;border-radius:50%}
|
||
.kpi-dot.ok{background:var(--ok)} .kpi-dot.warn{background:var(--warn)} .kpi-dot.critical{background:var(--err)}
|
||
.dept-footer{padding:10px 14px;background:rgba(0,0,0,0.25);border-top:1px solid rgba(255,255,255,0.04);display:flex;justify-content:space-between;align-items:center;gap:8px}
|
||
.dept-avatars{display:flex;align-items:center}
|
||
.dept-avatars img{width:26px;height:26px;border-radius:50%;border:2px solid var(--bg-tile);margin-left:-6px;background:var(--bg-3);object-fit:cover}
|
||
.dept-avatars img:first-child{margin-left:0}
|
||
.dept-avatars .more{width:26px;height:26px;border-radius:50%;background:var(--bg-3);color:var(--dim);font-size:9px;font-weight:800;display:inline-flex;align-items:center;justify-content:center;border:2px solid var(--bg-tile);margin-left:-6px}
|
||
.dept-cta{font-size:10.5px;color:var(--accent);font-weight:700;white-space:nowrap}
|
||
|
||
.gap-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:10px;margin-bottom:22px}
|
||
.gap{background:var(--bg-1);border:1px solid var(--border);border-radius:10px;padding:12px 14px;border-left:3px solid var(--purple);transition:all .2s}
|
||
.gap:hover{border-color:var(--border-h);transform:translateY(-2px)}
|
||
.gap.high{border-left-color:var(--warn)}
|
||
.gap.medium{border-left-color:var(--cyan)}
|
||
.gap-head{display:flex;align-items:center;gap:10px;margin-bottom:8px}
|
||
.gap-avatar{width:36px;height:36px;border-radius:50%;background:var(--bg-3);overflow:hidden;flex-shrink:0}
|
||
.gap-avatar img{width:100%;height:100%;object-fit:cover}
|
||
.gap-name{font-size:12.5px;font-weight:700;color:var(--text);line-height:1.2}
|
||
.gap-fw{display:inline-block;margin-top:2px;font-size:9.5px;padding:1px 6px;border-radius:4px;background:rgba(99,102,241,0.15);color:#a5b4fc;font-family:'JetBrains Mono',monospace}
|
||
.gap-role{font-size:10.5px;color:var(--dim);line-height:1.4;min-height:2.8em}
|
||
.gap-foot{display:flex;justify-content:space-between;align-items:center;margin-top:8px;padding-top:8px;border-top:1px dashed var(--bg-3)}
|
||
.gap-save{font-size:11px;color:var(--gold);font-family:'JetBrains Mono',monospace;font-weight:700}
|
||
.gap-status{font-size:9px;font-weight:700;padding:2px 7px;border-radius:5px;text-transform:uppercase;letter-spacing:0.3px}
|
||
.gap-status.to_build{background:rgba(245,158,11,0.15);color:#fbbf24}
|
||
.gap-status.partial{background:rgba(6,182,212,0.18);color:#7dd3fc}
|
||
.gap-status.deployed{background:rgba(34,197,94,0.18);color:#86efac}
|
||
|
||
.today{background:var(--bg-1);border:1px solid var(--border);border-radius:12px;padding:16px;margin-bottom:20px}
|
||
.today-head{font-size:12px;font-weight:800;letter-spacing:1.5px;text-transform:uppercase;color:var(--dim);margin-bottom:12px;display:flex;justify-content:space-between}
|
||
.today-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:8px}
|
||
.today-item{background:var(--bg-2);border-radius:8px;padding:10px 12px;border-left:3px solid var(--accent);transition:all .15s;cursor:pointer;text-decoration:none;color:var(--text);display:block}
|
||
.today-item:hover{background:var(--bg-3);transform:translateX(2px)}
|
||
.today-item .ver{font-size:9.5px;font-family:'JetBrains Mono',monospace;font-weight:700;color:var(--gold);margin-bottom:3px;letter-spacing:0.3px}
|
||
.today-item .name{font-size:11.5px;font-weight:700;color:var(--text);line-height:1.2;margin-bottom:3px}
|
||
.today-item .desc{font-size:10px;color:var(--dim);line-height:1.4;overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}
|
||
|
||
.proc-wrap{background:var(--bg-1);border:1px solid var(--border);border-radius:12px;padding:16px;margin-bottom:20px}
|
||
.proc-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:10px}
|
||
.proc{background:var(--bg-2);border-radius:8px;padding:10px 12px;border-left:2px solid var(--cyan)}
|
||
.proc-name{font-weight:700;font-size:11.5px;color:var(--text)}
|
||
.proc-steps{font-size:10px;color:var(--dim);margin-top:4px;line-height:1.45}
|
||
.proc-depts{font-size:9.5px;color:var(--mute);margin-top:5px;font-family:'JetBrains Mono',monospace}
|
||
|
||
.loading{text-align:center;padding:40px;color:var(--dim)}
|
||
.spinner{width:32px;height:32px;border:3px solid var(--bg-3);border-top-color:var(--accent);border-radius:50%;margin:0 auto 12px;animation:spin 1s linear infinite}
|
||
@keyframes spin{to{transform:rotate(360deg)}}
|
||
.clock{font-family:'JetBrains Mono',monospace;color:var(--accent);font-size:10.5px;margin-top:2px}
|
||
|
||
/* === OPUS RESPONSIVE FIX v2 19avr — append-only, doctrine #14 === */
|
||
@media(max-width: 480px) {
|
||
html, body { overflow-x: hidden !important; max-width: 100vw; }
|
||
body, main, section, article { word-break: break-word; overflow-wrap: anywhere; }
|
||
img, video, iframe, canvas, svg, table, pre, code { max-width: 100% !important; }
|
||
pre, code { white-space: pre-wrap; word-break: break-all; }
|
||
table { display: block; overflow-x: auto; }
|
||
.container, [class*="container"], [class*="wrapper"] { max-width: 100vw !important; padding-left: 12px !important; padding-right: 12px !important; }
|
||
[class*="grid"], [class*="-grid"] { grid-template-columns: 1fr !important; gap: 10px !important; }
|
||
[class*="kpi"], [class*="stats"], [class*="-cards"] { grid-template-columns: 1fr !important; }
|
||
header, nav, footer { flex-wrap: wrap !important; }
|
||
header > *, nav > *, footer > * { max-width: 100%; }
|
||
h1 { font-size: 22px !important; word-break: break-word; }
|
||
h2 { font-size: 18px !important; }
|
||
.pitch, [class*="pitch"], [class*="hero"] { word-break: break-word; overflow-wrap: anywhere; }
|
||
}
|
||
/* === OPUS RESPONSIVE FIX v2 END === */
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
|
||
<div class="shell">
|
||
<div>
|
||
<div class="breadcrumb">
|
||
<a href="/weval-technology-platform.html">🏠 WTP</a>
|
||
<span class="sep">›</span>
|
||
<span class="current">Enterprise Complete · V73</span>
|
||
</div>
|
||
<h1 style="margin-top:4px"><span class="pulse"></span>🏢 Enterprise Complete — 20 dépts · 169 KPIs · SAP/Oracle/Sage-class</h1>
|
||
<div class="clock" id="clock">—</div>
|
||
</div>
|
||
<div class="shell-actions">
|
||
<a href="/agents-archi.html" class="btn">🤖 Agents 3D</a>
|
||
<a href="/wevia-meeting-rooms.html" class="btn">👥 Meeting Rooms</a>
|
||
<a href="/enterprise-model.html" class="btn">🏢 Model</a>
|
||
<a href="/dg-command-center.html" class="btn">🎖 DG Center</a>
|
||
<a href="/sales-hub.html" class="btn primary">🚀 Sales Hub</a>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="kpi-super">
|
||
<div class="ks gold"><div class="l">Départements</div><div class="v gold" id="k-depts">—</div><div class="s">macro entreprise</div></div>
|
||
<div class="ks cyan"><div class="l">KPIs tracés</div><div class="v" id="k-kpis">—</div><div class="s">all-in-one ERP</div></div>
|
||
<div class="ks purple"><div class="l">Gap agents méthode</div><div class="v" id="k-gap">—</div><div class="s">Scrum/SAFe/Agile/DevOps</div></div>
|
||
<div class="ks ok"><div class="l">Agents déployés</div><div class="v" id="k-agents">—</div><div class="s">fleet WEVAL</div></div>
|
||
<div class="ks danger"><div class="l">Integrations ready</div><div class="v" id="k-int">—</div><div class="s">ERP/CRM/SaaS/DB</div></div>
|
||
<div class="ks"><div class="l">Innovations 24h</div><div class="v" id="k-inn">—</div><div class="s">WEVL Predict</div></div>
|
||
</div>
|
||
|
||
<div class="filters">
|
||
<span class="lbl">Catégorie</span>
|
||
<button class="fb active" data-cat="all">Tous (20)</button>
|
||
<button class="fb" data-cat="finance">💰 Finance (6)</button>
|
||
<button class="fb" data-cat="supply">📦 Supply (2)</button>
|
||
<button class="fb" data-cat="mfg">🏭 Production (3)</button>
|
||
<button class="fb" data-cat="sales">💼 Sales (3)</button>
|
||
<button class="fb" data-cat="hr">👥 RH (2)</button>
|
||
<button class="fb" data-cat="it">💻 IT (2)</button>
|
||
<button class="fb" data-cat="legal">⚖️ Legal (2)</button>
|
||
</div>
|
||
|
||
<div class="today">
|
||
<div class="today-head">
|
||
<span>⚡ Créations du jour · innovations WEVAL 18 avr 2026</span>
|
||
<span id="innov-count" style="font-family:'JetBrains Mono',monospace;font-weight:700;color:var(--accent)">—</span>
|
||
</div>
|
||
<div class="today-grid" id="today-grid"><div class="loading"><div class="spinner"></div></div></div>
|
||
</div>
|
||
|
||
<div class="sec-title">
|
||
<span>📊 Les 20 départements · KPIs macro + agents unifiés + status live</span>
|
||
<span class="count" id="depts-count">—</span>
|
||
</div>
|
||
<div class="depts-grid" id="depts-grid"><div class="loading"><div class="spinner"></div></div></div>
|
||
|
||
<div class="sec-title">
|
||
<span>🎭 Gap Agents Méthode · Scrum/SAFe/Agile/DevOps/OKR — à développer Q2</span>
|
||
<span class="count" id="gap-count">—</span>
|
||
</div>
|
||
<div class="gap-grid" id="gap-grid"><div class="loading"><div class="spinner"></div></div></div>
|
||
|
||
<div class="sec-title">
|
||
<span>⚙️ Macro processes par département · base SCOR + APQC</span>
|
||
<span class="count">8 macro streams</span>
|
||
</div>
|
||
<div class="proc-wrap">
|
||
<div class="proc-grid" id="proc-grid"></div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<script>
|
||
const API_V70 = '/api/wevia-v70-enterprise-complete.php';
|
||
const API_V71 = '/api/wevia-v71-intelligence-growth.php';
|
||
const AVATAR_API = '/api/agent-avatars.json';
|
||
|
||
let DATA70 = null, DATA71 = null, AVATARS = {};
|
||
let filter = 'all';
|
||
|
||
const DEPT_META = {
|
||
finance_general: {cat:'finance', color:'var(--c-fin)'},
|
||
controlling: {cat:'finance', color:'var(--c-fin)'},
|
||
treasury: {cat:'finance', color:'var(--c-fin)'},
|
||
billing_ar: {cat:'finance', color:'var(--c-fin)'},
|
||
accounts_payable: {cat:'finance', color:'var(--c-fin)'},
|
||
tax_compliance: {cat:'finance', color:'var(--c-fin)'},
|
||
supply_chain: {cat:'supply', color:'var(--c-sup)'},
|
||
procurement: {cat:'supply', color:'var(--c-sup)'},
|
||
manufacturing: {cat:'mfg', color:'var(--c-mfg)'},
|
||
quality_qhse: {cat:'mfg', color:'var(--c-mfg)'},
|
||
rd_innovation: {cat:'mfg', color:'var(--c-mfg)'},
|
||
sales: {cat:'sales', color:'var(--c-sales)'},
|
||
marketing: {cat:'sales', color:'var(--c-sales)'},
|
||
customer_success: {cat:'sales', color:'var(--c-sales)'},
|
||
hr: {cat:'hr', color:'var(--c-hr)'},
|
||
payroll: {cat:'hr', color:'var(--c-hr)'},
|
||
dsi_it: {cat:'it', color:'var(--c-it)'},
|
||
cybersecurity: {cat:'it', color:'var(--c-it)'},
|
||
legal_compliance: {cat:'legal', color:'var(--c-legal)'},
|
||
esg: {cat:'legal', color:'var(--c-esg)'}
|
||
};
|
||
|
||
const DEPT_AGENTS = {
|
||
finance_general: ['Fast Close Orchestrator','Cash Flow Predictor AI','Budget Variance Watchdog'],
|
||
controlling: ['Budget Variance Watchdog','Forecast AI'],
|
||
treasury: ['Cash Flow Predictor AI','FX Hedger'],
|
||
billing_ar: ['Collection AI Agent','Dunning Router'],
|
||
accounts_payable: ['Invoice Auto-Match','Duplicate Payment Detector'],
|
||
tax_compliance: ['Tax Validator','Audit Trail Watcher'],
|
||
supply_chain: ['Demand Forecast Pro','Stockout Prevention','OTD Optimizer'],
|
||
procurement: ['Supplier Risk Monitor','Contract Compliance'],
|
||
manufacturing: ['OEE Live','Predictive Maintenance','Takt Time Monitor'],
|
||
quality_qhse: ['CAPA Closer','Incident Watcher'],
|
||
rd_innovation: ['Patent Scanner','PoC Tracker'],
|
||
sales: ['Pipeline Scorer','Lead Qualifier','CPQ AI'],
|
||
marketing: ['Content Generator','CAC Optimizer'],
|
||
customer_success: ['Churn Predictor','NPS Analyzer'],
|
||
hr: ['Talent Scout','Attrition Predictor','Skills Matcher'],
|
||
payroll: ['Payroll Accuracy AI','Compliance Checker'],
|
||
dsi_it: ['DevOps','AutoFix','Fiability','Monitor'],
|
||
cybersecurity: ['Security','Fraud Detection Agent','MFA Enforcer'],
|
||
legal_compliance: ['Contract Watcher','GDPR Auditor'],
|
||
esg: ['Carbon Tracker','Sustainability Reporter']
|
||
};
|
||
|
||
const MACRO_PROCESSES = [
|
||
{name:'Record-to-Report (R2R)', steps:'Journal → Reconciliation → Close → Report', depts:['finance_general','controlling']},
|
||
{name:'Order-to-Cash (O2C)', steps:'Quote → Order → Ship → Invoice → Collect', depts:['sales','billing_ar']},
|
||
{name:'Procure-to-Pay (P2P)', steps:'Requisition → PO → Receipt → Invoice → Pay', depts:['procurement','accounts_payable']},
|
||
{name:'Plan-to-Produce', steps:'Demand → MRP → Production → QC → Stock', depts:['manufacturing','quality_qhse']},
|
||
{name:'Hire-to-Retire (H2R)', steps:'Recruit → Onboard → Manage → Separate', depts:['hr','payroll']},
|
||
{name:'Market-to-Lead (M2L)', steps:'Campaign → Traffic → MQL → SQL → Handoff', depts:['marketing','sales']},
|
||
{name:'Design-to-Deploy (D2D)', steps:'Ideate → Spec → Build → Test → Release', depts:['rd_innovation','dsi_it']},
|
||
{name:'Risk-to-Remediate', steps:'Identify → Assess → Mitigate → Monitor', depts:['legal_compliance','cybersecurity']}
|
||
];
|
||
|
||
function clockTick(){const d=new Date();document.getElementById('clock').textContent=d.toLocaleDateString('fr-FR')+' '+d.toLocaleTimeString('fr-FR')+' · auto-refresh 60s';}
|
||
setInterval(clockTick,1000); clockTick();
|
||
|
||
function avatarUrl(name) {
|
||
if (AVATARS[name]) return AVATARS[name];
|
||
return 'https://api.dicebear.com/9.x/adventurer/svg?seed=' + encodeURIComponent(name || 'default');
|
||
}
|
||
|
||
async function load() {
|
||
try {
|
||
const [av, d70, d71] = await Promise.all([
|
||
fetch(AVATAR_API+'?t='+Date.now()).then(r=>r.json()).catch(()=>({})),
|
||
fetch(API_V70+'?t='+Date.now()).then(r=>r.json()).catch(()=>null),
|
||
fetch(API_V71+'?t='+Date.now()).then(r=>r.json()).catch(()=>null)
|
||
]);
|
||
AVATARS = av || {};
|
||
DATA70 = d70;
|
||
DATA71 = d71;
|
||
render();
|
||
} catch(e){console.error('load err',e);}
|
||
}
|
||
|
||
function render() {
|
||
if (!DATA70) return;
|
||
const s70 = DATA70.summary;
|
||
document.getElementById('k-depts').textContent = s70.departments;
|
||
document.getElementById('k-kpis').textContent = s70.kpis_total;
|
||
document.getElementById('k-gap').textContent = DATA71 ? DATA71.summary.agility_agents_gap : '—';
|
||
// TRUTH SYNC (Opus Yacine 19avr) · fetch dynamically
|
||
document.getElementById('k-agents').textContent = 950; // fallback
|
||
fetch('/api/source-of-truth.json?t=' + Date.now(), {cache:'no-store'})
|
||
.then(r => r.json())
|
||
.then(d => {
|
||
var n = d.agents_count || d.agents_total || 950;
|
||
var el = document.getElementById('k-agents');
|
||
if (el) el.textContent = n;
|
||
})
|
||
.catch(e => {});
|
||
document.getElementById('k-int').textContent = s70.integrations_total;
|
||
document.getElementById('k-inn').textContent = DATA71 ? DATA71.summary.innovations_last_24h : '—';
|
||
|
||
// Today
|
||
if (DATA71) {
|
||
const innovs = DATA71.wevl_predict_innovations.innovations.filter(i => i.date === '2026-04-18');
|
||
document.getElementById('innov-count').textContent = innovs.length + ' créations aujourd\'hui';
|
||
document.getElementById('today-grid').innerHTML = innovs.map(i => `
|
||
<a href="${i.url}" class="today-item" target="_blank">
|
||
<div class="ver">${(i.type||'').toUpperCase()} · ${'★'.repeat(i.novelty||3)}</div>
|
||
<div class="name">${i.name}</div>
|
||
<div class="desc">${i.description||''}</div>
|
||
</a>
|
||
`).join('');
|
||
}
|
||
|
||
// Depts
|
||
const depts = DATA70.enterprise_departments;
|
||
const entries = Object.entries(depts);
|
||
const filtered = filter === 'all' ? entries : entries.filter(([k,v]) => (DEPT_META[k]||{}).cat === filter);
|
||
document.getElementById('depts-count').textContent = filtered.length + ' affichés / ' + entries.length;
|
||
|
||
document.getElementById('depts-grid').innerHTML = filtered.map(([key, d]) => {
|
||
const meta = DEPT_META[key] || {cat:'other', color:'var(--accent)'};
|
||
const agents = (DEPT_AGENTS[key] || []).slice(0,5);
|
||
const critCount = (d.kpis||[]).filter(k => k.s === 'critical').length;
|
||
const warnCount = (d.kpis||[]).filter(k => k.s === 'warn').length;
|
||
const status = critCount > 2 ? 'critical' : (warnCount > (d.kpis||[]).length/2 ? 'warn' : 'ok');
|
||
const topKpis = (d.kpis||[]).slice(0,4);
|
||
return `<div class="dept" style="--dc:${meta.color}" onclick="window.open('/dg-command-center.html','_blank')">
|
||
<div class="dept-head">
|
||
<span class="dept-icon">${d.icon||'📊'}</span>
|
||
<div class="dept-meta">
|
||
<div class="dept-name">${d.label}</div>
|
||
<div class="dept-agents-info">${(d.kpis||[]).length} KPIs · ${agents.length} agents · ${(d.integrations||[]).length} ERPs</div>
|
||
</div>
|
||
<span class="dept-status ${status}">${status}</span>
|
||
</div>
|
||
<div class="dept-kpis">
|
||
${topKpis.map(k => `<div class="kpi-row">
|
||
<div class="kpi-name" title="${k.k}">${k.k}</div>
|
||
<div class="kpi-val">${k.v}${k.u||''}</div>
|
||
<div class="kpi-dot ${k.s||'ok'}"></div>
|
||
</div>`).join('')}
|
||
</div>
|
||
<div class="dept-footer">
|
||
<div class="dept-avatars">
|
||
${agents.slice(0,4).map(a => `<img src="${avatarUrl(a)}" alt="${a}" title="${a}" onerror="this.style.display='none'">`).join('')}
|
||
${agents.length > 4 ? `<span class="more">+${agents.length-4}</span>` : ''}
|
||
</div>
|
||
<span class="dept-cta">→ pilotage</span>
|
||
</div>
|
||
</div>`;
|
||
}).join('');
|
||
|
||
// Gap agents
|
||
if (DATA71) {
|
||
const gaps = DATA71.agility_agents_gap.agents || [];
|
||
document.getElementById('gap-count').textContent = gaps.length + ' agents · ' + DATA71.agility_agents_gap.total_fte_saved_year + ' FTE savings/an';
|
||
document.getElementById('gap-grid').innerHTML = gaps.map(g => `
|
||
<div class="gap ${g.priority||'medium'}">
|
||
<div class="gap-head">
|
||
<div class="gap-avatar"><img src="${avatarUrl(g.name)}" alt="${g.name}" onerror="this.style.display='none'"></div>
|
||
<div style="flex:1">
|
||
<div class="gap-name">${g.name}</div>
|
||
<span class="gap-fw">${g.framework||''}</span>
|
||
</div>
|
||
</div>
|
||
<div class="gap-role">${g.role||''}</div>
|
||
<div class="gap-foot">
|
||
<span class="gap-save">💰 ${g.savings_fte_year||0} FTE/an</span>
|
||
<span class="gap-status ${g.status||'to_build'}">${(g.status||'to_build').replace('_',' ')}</span>
|
||
</div>
|
||
</div>
|
||
`).join('');
|
||
}
|
||
|
||
// Macro processes
|
||
document.getElementById('proc-grid').innerHTML = MACRO_PROCESSES.map(p => {
|
||
const deptLabels = p.depts.map(d => (depts[d]||{}).label || d).join(' + ');
|
||
return `<div class="proc">
|
||
<div class="proc-name">${p.name}</div>
|
||
<div class="proc-steps">${p.steps}</div>
|
||
<div class="proc-depts">${deptLabels}</div>
|
||
</div>`;
|
||
}).join('');
|
||
}
|
||
|
||
document.querySelectorAll('.fb').forEach(b => b.onclick = e => {
|
||
filter = e.target.dataset.cat;
|
||
document.querySelectorAll('.fb').forEach(x => x.classList.toggle('active', x.dataset.cat === filter));
|
||
render();
|
||
});
|
||
|
||
load();
|
||
setInterval(load, 60000);
|
||
</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) {
|
||
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 (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);} });
|
||
}
|
||
}
|
||
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 === -->
|
||
|
||
</body>
|
||
</html>
|