109 lines
4.3 KiB
HTML
109 lines
4.3 KiB
HTML
<!DOCTYPE html>
|
|
<html><head><meta charset="UTF-8">
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.23.9/babel.min.js"></script>
|
|
<style>body{font-family:system-ui;padding:20px;background:#f8fafc}
|
|
.card{background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:20px;margin:10px;display:inline-block;min-width:200px;text-align:center}
|
|
.value{font-size:32px;font-weight:700;color:#6366f1}
|
|
.label{font-size:13px;color:#64748b;margin-top:4px}
|
|
h2{color:#1e293b}
|
|
#error{color:red;padding:10px;background:#fef2f2;border-radius:8px;display:none}
|
|
</style>
|
|
</head><body>
|
|
<div id="error"></div>
|
|
<div id="root"><p>Chargement...</p></div>
|
|
|
|
<script>
|
|
// Debug: check what's available
|
|
var debug = [];
|
|
debug.push('React: ' + (typeof React));
|
|
debug.push('ReactDOM: ' + (typeof ReactDOM));
|
|
debug.push('Babel: ' + (typeof Babel));
|
|
console.log(debug.join(', '));
|
|
</script>
|
|
|
|
<script type="text/babel">
|
|
const {useState, useEffect} = React;
|
|
|
|
const data = [
|
|
{mois: 'Jan', commandes: 120, livraisons: 95, retards: 8},
|
|
{mois: 'Fev', commandes: 145, livraisons: 110, retards: 12},
|
|
{mois: 'Mar', commandes: 160, livraisons: 140, retards: 5},
|
|
{mois: 'Avr', commandes: 180, livraisons: 155, retards: 10},
|
|
{mois: 'Mai', commandes: 200, livraisons: 175, retards: 7},
|
|
];
|
|
|
|
function Dashboard() {
|
|
const [selected, setSelected] = useState('all');
|
|
|
|
const totalCmd = data.reduce((a,d) => a + d.commandes, 0);
|
|
const totalLiv = data.reduce((a,d) => a + d.livraisons, 0);
|
|
const totalRet = data.reduce((a,d) => a + d.retards, 0);
|
|
const satisfaction = ((totalLiv / totalCmd) * 100).toFixed(1);
|
|
|
|
return (
|
|
<div>
|
|
<h2>Dashboard KPI Supply Chain</h2>
|
|
<div style={{display:'flex',gap:'16px',flexWrap:'wrap'}}>
|
|
<div className="card">
|
|
<div className="value">{totalCmd}</div>
|
|
<div className="label">Commandes</div>
|
|
</div>
|
|
<div className="card">
|
|
<div className="value">{totalLiv}</div>
|
|
<div className="label">Livraisons</div>
|
|
</div>
|
|
<div className="card">
|
|
<div className="value" style={{color:'#ef4444'}}>{totalRet}</div>
|
|
<div className="label">Retards</div>
|
|
</div>
|
|
<div className="card">
|
|
<div className="value" style={{color:'#10b981'}}>{satisfaction}%</div>
|
|
<div className="label">Satisfaction</div>
|
|
</div>
|
|
</div>
|
|
<h3 style={{marginTop:'24px'}}>Donnees mensuelles</h3>
|
|
<table style={{width:'100%',borderCollapse:'collapse',marginTop:'8px'}}>
|
|
<thead>
|
|
<tr style={{background:'#f1f5f9'}}>
|
|
<th style={{padding:'8px',border:'1px solid #e2e8f0'}}>Mois</th>
|
|
<th style={{padding:'8px',border:'1px solid #e2e8f0'}}>Commandes</th>
|
|
<th style={{padding:'8px',border:'1px solid #e2e8f0'}}>Livraisons</th>
|
|
<th style={{padding:'8px',border:'1px solid #e2e8f0'}}>Retards</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{data.map((d, i) => (
|
|
<tr key={i}>
|
|
<td style={{padding:'8px',border:'1px solid #e2e8f0',fontWeight:'600'}}>{d.mois}</td>
|
|
<td style={{padding:'8px',border:'1px solid #e2e8f0'}}>{d.commandes}</td>
|
|
<td style={{padding:'8px',border:'1px solid #e2e8f0'}}>{d.livraisons}</td>
|
|
<td style={{padding:'8px',border:'1px solid #e2e8f0',color: d.retards > 10 ? '#ef4444' : '#10b981'}}>{d.retards}</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
<div style={{marginTop:'16px',padding:'12px',background:'#f0fdf4',borderRadius:'8px',color:'#166534',fontSize:'13px'}}>
|
|
Dashboard genere par WEVIA Engine - Donnees en temps reel
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
try {
|
|
ReactDOM.render(React.createElement(Dashboard), document.getElementById('root'));
|
|
} catch(e) {
|
|
document.getElementById('error').style.display = 'block';
|
|
document.getElementById('error').textContent = 'Error: ' + e.message;
|
|
}
|
|
</script>
|
|
|
|
<script>
|
|
// Fallback error handler
|
|
window.onerror = function(msg) {
|
|
var el = document.getElementById('error');
|
|
if (el) { el.style.display = 'block'; el.textContent += msg + '\n'; }
|
|
};
|
|
</script>
|
|
</body></html> |