// Biểu đồ SVG thuần cho tab "Quản lý thời lượng". // Không thêm thư viện biểu đồ: cả frontend hiện chỉ có react + react-router, // mà mấy dạng ở đây (cột ngang, đường theo ngày) vẽ tay còn nhẹ và gọn hơn. // Mọi con số đều IN THẲNG lên biểu đồ, không bắt người xem ước lượng theo trục. // ── Định dạng ─────────────────────────────────────────────────── export function fmtDur(ms) { if (ms == null || Number.isNaN(ms)) return "—"; const s = Math.round(ms / 1000); if (s < 60) return `${s} giây`; const m = Math.floor(s / 60); if (m < 60) return s % 60 ? `${m} phút ${s % 60} giây` : `${m} phút`; const h = Math.floor(m / 60); return m % 60 ? `${h} giờ ${m % 60} phút` : `${h} giờ`; } export function fmtShort(ms) { if (ms == null || Number.isNaN(ms)) return "—"; const s = ms / 1000; if (s < 60) return `${s < 10 ? s.toFixed(1) : Math.round(s)}s`; const m = s / 60; if (m < 60) return `${m < 10 ? m.toFixed(1) : Math.round(m)}p`; return `${(m / 60).toFixed(1)}h`; } export const fmtPct = (v) => (v == null ? "—" : `${Math.round(v * 100)}%`); export const fmtNum = (v) => (v == null ? "—" : Number(v).toLocaleString("vi-VN")); export const fmtTime = (ts) => ts ? new Date(ts * 1000).toLocaleString("vi-VN", { day: "2-digit", month: "2-digit", hour: "2-digit", minute: "2-digit" }) : "—"; // ── Cột ngang ─────────────────────────────────────────────────── // data: [{ label, value, text?, sub? }] export function BarChart({ data, color = "", empty = "Chưa có dữ liệu" }) { const rows = (data || []).filter((d) => d && d.value != null); if (!rows.length) return
{empty}
; const max = Math.max(...rows.map((r) => Math.abs(r.value)), 1); return (Cần ít nhất 2 ngày dữ liệu để vẽ.
; } const W = 720, H = height, PADL = 38, PADR = 10, PADT = 12, PADB = 24; const max = Math.max(1, ...series.flatMap((s) => s.values.map((v) => v || 0))); const x = (i) => PADL + (i * (W - PADL - PADR)) / (pts.length - 1); const y = (v) => H - PADB - ((v || 0) / max) * (H - PADT - PADB); // Nhãn trục X: thưa ra để không chồng chữ. const stepX = Math.max(1, Math.ceil(pts.length / 8)); return (