172 lines
8.7 KiB
PHP
172 lines
8.7 KiB
PHP
<?php
|
|
// V80 WEVIA Products KPI Dashboard Widget - Drill-down cards embedded
|
|
header("Content-Type: text/html; charset=utf-8");
|
|
|
|
// Fetch products data
|
|
$ch = curl_init("http://127.0.0.1/api/wevia-products-kpi-v80.php?action=summary");
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_RETURNTRANSFER => true,
|
|
CURLOPT_TIMEOUT => 10,
|
|
CURLOPT_SSL_VERIFYPEER => false,
|
|
CURLOPT_HTTPHEADER => ["Host: weval-consulting.com"]
|
|
]);
|
|
$body = curl_exec($ch); curl_close($ch);
|
|
$data = json_decode($body, true);
|
|
|
|
$products = $data["products"] ?? [];
|
|
$summary = $data["summary"] ?? [];
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>V80 Products KPI Dashboard — Drill-down</title>
|
|
<style>
|
|
:root{--bg:#0a0e1a;--bg2:#131a2b;--fg:#e4e8f0;--muted:#8899af;--ok:#48bb78;--warn:#f6ad55;--fail:#fc8181;--ac:#6c9ef8;--bd:rgba(255,255,255,.08);}
|
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
body{background:var(--bg);color:var(--fg);font-family:'DM Sans',sans-serif;padding:20px;min-height:100vh}
|
|
.hdr{display:flex;justify-content:space-between;align-items:center;margin-bottom:20px;padding-bottom:15px;border-bottom:1px solid var(--bd)}
|
|
.hdr h1{font-size:22px;font-weight:700;color:var(--ac)}
|
|
.hdr .sub{font-size:12px;color:var(--muted);margin-top:4px}
|
|
.summary{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:12px;margin-bottom:24px}
|
|
.summary .s{background:var(--bg2);padding:12px;border-radius:10px;border:1px solid var(--bd)}
|
|
.summary .v{font-size:26px;font-weight:700;color:var(--ac)}
|
|
.summary .l{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.5px;margin-top:4px}
|
|
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:16px}
|
|
.card{background:linear-gradient(135deg,var(--bg2),rgba(108,158,248,.05));border:1px solid var(--bd);border-radius:12px;padding:14px;cursor:pointer;transition:all .2s}
|
|
.card:hover{border-color:var(--ac);transform:translateY(-2px);box-shadow:0 4px 16px rgba(108,158,248,.15)}
|
|
.card-head{display:flex;align-items:center;gap:10px;margin-bottom:10px;padding-bottom:10px;border-bottom:1px solid var(--bd)}
|
|
.card-icon{font-size:24px}
|
|
.card-name{font-size:14px;font-weight:700}
|
|
.card-cat{font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:.5px}
|
|
.card-kpis{display:flex;flex-direction:column;gap:8px}
|
|
.kpi{display:flex;justify-content:space-between;align-items:center;font-size:12px}
|
|
.kpi-label{color:var(--muted)}
|
|
.kpi-val{font-weight:700;font-size:13px}
|
|
.kpi-val.ok{color:var(--ok)}
|
|
.kpi-val.warn{color:var(--warn)}
|
|
.kpi-val.fail{color:var(--fail)}
|
|
.kpi-unit{font-size:10px;color:var(--muted);margin-left:4px}
|
|
.drill{margin-top:10px;padding-top:8px;border-top:1px solid var(--bd);display:flex;justify-content:space-between;align-items:center}
|
|
.drill-btn{background:var(--ac);color:#000;padding:4px 10px;border-radius:4px;text-decoration:none;font-size:11px;font-weight:600}
|
|
.drill-btn:hover{background:#4a7dcc}
|
|
.modal{display:none;position:fixed;inset:0;background:rgba(0,0,0,.8);z-index:9999;align-items:center;justify-content:center;padding:20px}
|
|
.modal.active{display:flex}
|
|
.modal-content{background:var(--bg2);border:1px solid var(--bd);border-radius:12px;padding:24px;max-width:600px;width:100%;max-height:80vh;overflow-y:auto}
|
|
.modal-close{float:right;background:var(--fail);color:#fff;padding:4px 12px;border-radius:4px;border:0;cursor:pointer;font-size:12px}
|
|
.modal h3{margin-bottom:14px}
|
|
.modal pre{background:var(--bg);padding:12px;border-radius:6px;font-size:11px;overflow-x:auto;color:var(--muted)}
|
|
.status-dot{width:10px;height:10px;border-radius:50%;display:inline-block;margin-right:4px}
|
|
.status-dot.ok{background:var(--ok);box-shadow:0 0 8px var(--ok)}
|
|
.status-dot.warn{background:var(--warn)}
|
|
.status-dot.fail{background:var(--fail)}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="hdr">
|
|
<div>
|
|
<h1>🎯 V80 Products KPI Dashboard — Drill-down</h1>
|
|
<div class="sub">Cliquer sur chaque carte pour voir détails · Updated: <?= date("H:i") ?></div>
|
|
</div>
|
|
<a href="/weval-technology-platform.html" style="color:var(--ac);text-decoration:none;font-size:13px">← Back to ERP Portal</a>
|
|
</div>
|
|
|
|
<div class="summary">
|
|
<div class="s"><div class="v"><?= $summary["total_products"] ?? 0 ?></div><div class="l">Products</div></div>
|
|
<div class="s"><div class="v"><?= $summary["total_kpis"] ?? 0 ?></div><div class="l">KPIs tracked</div></div>
|
|
<div class="s"><div class="v" style="color:var(--ok)"><?= $summary["ok"] ?? 0 ?></div><div class="l">OK (on target)</div></div>
|
|
<div class="s"><div class="v" style="color:var(--warn)"><?= $summary["warn"] ?? 0 ?></div><div class="l">WARN (below target)</div></div>
|
|
<div class="s"><div class="v" style="color:var(--fail)"><?= $summary["fail"] ?? 0 ?></div><div class="l">FAIL (broken)</div></div>
|
|
<div class="s"><div class="v" style="color:var(--ac)"><?= $summary["health_pct"] ?? 0 ?>%</div><div class="l">Overall health</div></div>
|
|
</div>
|
|
|
|
<div class="grid">
|
|
<?php foreach ($products as $id => $p): ?>
|
|
<div class="card" onclick="drillDown('<?= htmlspecialchars($id) ?>')">
|
|
<div class="card-head">
|
|
<div class="card-icon"><?= $p["icon"] ?></div>
|
|
<div>
|
|
<div class="card-name"><?= htmlspecialchars($p["name"]) ?></div>
|
|
<div class="card-cat"><?= htmlspecialchars($p["category"]) ?></div>
|
|
</div>
|
|
</div>
|
|
<div class="card-kpis">
|
|
<?php foreach ($p["kpis"] as $kpi): ?>
|
|
<div class="kpi">
|
|
<span class="kpi-label"><span class="status-dot <?= $kpi["status"] ?>"></span><?= htmlspecialchars($kpi["label"]) ?></span>
|
|
<span class="kpi-val <?= $kpi["status"] ?>"><?= htmlspecialchars($kpi["value"]) ?><span class="kpi-unit"><?= htmlspecialchars($kpi["unit"]) ?></span></span>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<div class="drill">
|
|
<span style="font-size:10px;color:var(--muted)">Target: <?= count($p["kpis"]) ?> KPIs</span>
|
|
<a href="<?= htmlspecialchars($p["drill_url"] ?? $p["page"]) ?>" class="drill-btn" onclick="event.stopPropagation()" target="_blank">Drill →</a>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
|
|
<!-- Drill-down modal -->
|
|
<div class="modal" id="drillModal">
|
|
<div class="modal-content">
|
|
<button class="modal-close" onclick="closeDrill()">Close</button>
|
|
<h3 id="modalTitle">Product Details</h3>
|
|
<div id="modalBody">Loading...</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
async function drillDown(productId){
|
|
const modal = document.getElementById('drillModal');
|
|
const body = document.getElementById('modalBody');
|
|
const title = document.getElementById('modalTitle');
|
|
|
|
modal.classList.add('active');
|
|
body.innerHTML = 'Loading drill-down data...';
|
|
|
|
try {
|
|
const r = await fetch('/api/wevia-products-kpi-v80.php?action=drill&product=' + productId);
|
|
const d = await r.json();
|
|
if (d.ok && d.product) {
|
|
const p = d.product;
|
|
title.textContent = p.icon + ' ' + p.name;
|
|
body.innerHTML = `
|
|
<div style="margin-bottom:14px">
|
|
<div><b>Category:</b> ${p.category}</div>
|
|
<div><b>Page:</b> <a href="${p.page}" target="_blank" style="color:#6c9ef8">${p.page}</a></div>
|
|
<div><b>Drill URL:</b> <a href="${p.drill_url || p.page}" target="_blank" style="color:#6c9ef8">${p.drill_url || p.page}</a></div>
|
|
</div>
|
|
<h4>KPIs Detail:</h4>
|
|
<table style="width:100%;margin-top:10px;border-collapse:collapse">
|
|
<thead><tr style="border-bottom:1px solid rgba(255,255,255,.1)"><th style="padding:8px;text-align:left">Label</th><th style="padding:8px;text-align:right">Value</th><th style="padding:8px;text-align:right">Target</th><th style="padding:8px;text-align:center">Status</th><th style="padding:8px">Action</th></tr></thead>
|
|
<tbody>
|
|
${p.kpis.map(k => `
|
|
<tr style="border-bottom:1px solid rgba(255,255,255,.05)">
|
|
<td style="padding:8px">${k.label}</td>
|
|
<td style="padding:8px;text-align:right;font-weight:700">${k.value} ${k.unit}</td>
|
|
<td style="padding:8px;text-align:right;color:#8899af">${k.target}</td>
|
|
<td style="padding:8px;text-align:center"><span class="status-dot ${k.status}"></span>${k.status.toUpperCase()}</td>
|
|
<td style="padding:8px"><a href="${k.drill || p.drill_url || p.page}" target="_blank" style="color:#6c9ef8;font-size:11px">Explore →</a></td>
|
|
</tr>
|
|
`).join('')}
|
|
</tbody>
|
|
</table>
|
|
`;
|
|
} else {
|
|
body.innerHTML = 'Failed to load: ' + (d.error || 'unknown');
|
|
}
|
|
} catch(e) {
|
|
body.innerHTML = 'Error: ' + e.message;
|
|
}
|
|
}
|
|
function closeDrill(){
|
|
document.getElementById('drillModal').classList.remove('active');
|
|
}
|
|
document.getElementById('drillModal').addEventListener('click', function(e){
|
|
if (e.target === this) closeDrill();
|
|
});
|
|
</script>
|
|
<script src="/api/archi-meta-badge.js" defer></script>
|
|
</body>
|
|
</html>
|