feat: adicionar somatorias de peso nos 4 cards de KPIs do mapa termico de kits

This commit is contained in:
2026-10-20 15:53:21 -03:00
parent 9ade5d0d5a
commit 8a707894e0
2 changed files with 126 additions and 38 deletions
@@ -120,6 +120,12 @@ export const MapaTermicoKitsView: React.FC<MapaTermicoKitsViewProps> = ({
});
}, [listaKits, selectedFase, filtroStatus, busca]);
// Formatação de pesos em kg
const formatarKg = (valorKg: number) => {
if (!valorKg || valorKg <= 0) return '0 kg';
return `${valorKg.toLocaleString('pt-BR', { minimumFractionDigits: 1, maximumFractionDigits: 1 })} kg`;
};
// KPIs calculados com base nas peças filtradas
const resumoExibido = useMemo(() => {
let total100 = 0;
@@ -127,18 +133,30 @@ export const MapaTermicoKitsView: React.FC<MapaTermicoKitsViewProps> = ({
let totalTravados = 0;
let pesoTot = 0;
let pesoCort = 0;
let peso100 = 0;
let pesoUnLiberadas = 0;
let pesoParciais = 0;
let pesoNaoIniciados = 0;
let unTot = 0;
let unLib = 0;
pecasFiltradas.forEach((item) => {
unTot += item.quantidade_total;
unLib += item.kits_completos_cortados;
pesoTot += item.peso_total_componentes;
pesoTot += item.peso_total_peca;
pesoCort += item.peso_cortado_componentes;
pesoUnLiberadas += item.peso_kits_liberados;
if (item.status_termico === 'verde') total100++;
else if (item.status_termico === 'verde_parcial' || item.status_termico === 'amarelo') totalParciais++;
else totalTravados++;
if (item.status_termico === 'verde') {
total100++;
peso100 += item.peso_total_peca;
} else if (item.status_termico === 'verde_parcial' || item.status_termico === 'amarelo') {
totalParciais++;
pesoParciais += item.peso_total_peca;
} else {
totalTravados++;
pesoNaoIniciados += item.peso_total_peca;
}
});
return {
@@ -148,6 +166,10 @@ export const MapaTermicoKitsView: React.FC<MapaTermicoKitsViewProps> = ({
totalKitsNaoIniciados: totalTravados,
pesoTotalOFKg: pesoTot,
pesoCortadoTotalKg: pesoCort,
peso100PorcentoKg: peso100,
pesoUnidadesLiberadasKg: pesoUnLiberadas,
pesoParciaisKg: pesoParciais,
pesoNaoIniciadosKg: pesoNaoIniciados,
percentualGeralOF: pesoTot > 0 ? Math.min(100, Math.round((pesoCort / pesoTot) * 100)) : 0,
totalUnidadesTotal: unTot,
totalUnidadesLiberadasSolda: unLib,
@@ -268,72 +290,92 @@ export const MapaTermicoKitsView: React.FC<MapaTermicoKitsViewProps> = ({
<div className="grid grid-cols-2 md:grid-cols-4 gap-2.5 sm:gap-3">
{/* KPI 1: 100% Liberadas */}
<div className="p-3.5 rounded-2xl bg-emerald-50/80 dark:bg-emerald-950/40 border border-emerald-200 dark:border-emerald-800 shadow-sm flex items-center justify-between">
<div>
<div className="text-[11px] font-black uppercase text-emerald-700 dark:text-emerald-400">
100% Liberadas
<div className="min-w-0">
<div className="flex items-center gap-1.5 flex-wrap">
<span className="text-[11px] font-black uppercase text-emerald-700 dark:text-emerald-400">
100% Liberadas
</span>
<span className="text-[11px] font-black text-emerald-800 dark:text-emerald-300 bg-emerald-200/80 dark:bg-emerald-900/70 px-1.5 py-0.5 rounded-md border border-emerald-300/80 dark:border-emerald-700 shadow-2xs">
{formatarKg(resumoExibido.peso100PorcentoKg)}
</span>
</div>
<div className="text-2xl font-black text-emerald-900 dark:text-emerald-100 mt-0.5">
<div className="text-2xl font-black text-emerald-900 dark:text-emerald-100 mt-1">
{resumoExibido.totalKits100Porcento}
</div>
<div className="text-[10px] text-emerald-700/80 dark:text-emerald-400/80 font-medium">
<div className="text-[10px] text-emerald-700/80 dark:text-emerald-400/80 font-medium truncate">
peças com todos os kits cortados
</div>
</div>
<div className="p-2.5 rounded-xl bg-emerald-100 text-emerald-700 dark:bg-emerald-900/60 dark:text-emerald-300">
<div className="p-2.5 rounded-xl bg-emerald-100 text-emerald-700 dark:bg-emerald-900/60 dark:text-emerald-300 shrink-0 ml-2">
<CheckCircle2 className="w-6 h-6" />
</div>
</div>
{/* KPI 2: Kits Montáveis Liberados */}
<div className="p-3.5 rounded-2xl bg-blue-50/80 dark:bg-blue-950/40 border border-blue-200 dark:border-blue-800 shadow-sm flex items-center justify-between">
<div>
<div className="text-[11px] font-black uppercase text-blue-700 dark:text-blue-400">
Unidades Liberadas
<div className="min-w-0">
<div className="flex items-center gap-1.5 flex-wrap">
<span className="text-[11px] font-black uppercase text-blue-700 dark:text-blue-400">
Unidades Liberadas
</span>
<span className="text-[11px] font-black text-blue-800 dark:text-blue-300 bg-blue-200/80 dark:bg-blue-900/70 px-1.5 py-0.5 rounded-md border border-blue-300/80 dark:border-blue-700 shadow-2xs">
{formatarKg(resumoExibido.pesoUnidadesLiberadasKg)}
</span>
</div>
<div className="text-2xl font-black text-blue-900 dark:text-blue-100 mt-0.5">
<div className="text-2xl font-black text-blue-900 dark:text-blue-100 mt-1">
{resumoExibido.totalUnidadesLiberadasSolda} <span className="text-xs text-blue-600 font-bold">/ {resumoExibido.totalUnidadesTotal} un</span>
</div>
<div className="text-[10px] text-blue-700/80 dark:text-blue-400/80 font-medium">
<div className="text-[10px] text-blue-700/80 dark:text-blue-400/80 font-medium truncate">
kits prontos na bancada de solda
</div>
</div>
<div className="p-2.5 rounded-xl bg-blue-100 text-blue-700 dark:bg-blue-900/60 dark:text-blue-300">
<div className="p-2.5 rounded-xl bg-blue-100 text-blue-700 dark:bg-blue-900/60 dark:text-blue-300 shrink-0 ml-2">
<PackageCheck className="w-6 h-6" />
</div>
</div>
{/* KPI 3: Em Andamento / Quase Prontos */}
<div className="p-3.5 rounded-2xl bg-amber-50/80 dark:bg-amber-950/40 border border-amber-200 dark:border-amber-800 shadow-sm flex items-center justify-between">
<div>
<div className="text-[11px] font-black uppercase text-amber-700 dark:text-amber-400">
Corte em Andamento
<div className="min-w-0">
<div className="flex items-center gap-1.5 flex-wrap">
<span className="text-[11px] font-black uppercase text-amber-700 dark:text-amber-400">
Corte em Andamento
</span>
<span className="text-[11px] font-black text-amber-800 dark:text-amber-300 bg-amber-200/80 dark:bg-amber-900/70 px-1.5 py-0.5 rounded-md border border-amber-300/80 dark:border-amber-700 shadow-2xs">
{formatarKg(resumoExibido.pesoParciaisKg)}
</span>
</div>
<div className="text-2xl font-black text-amber-900 dark:text-amber-100 mt-0.5">
<div className="text-2xl font-black text-amber-900 dark:text-amber-100 mt-1">
{resumoExibido.totalKitsParciais}
</div>
<div className="text-[10px] text-amber-700/80 dark:text-amber-400/80 font-medium">
<div className="text-[10px] text-amber-700/80 dark:text-amber-400/80 font-medium truncate">
kits parciais (prioridade de corte)
</div>
</div>
<div className="p-2.5 rounded-xl bg-amber-100 text-amber-700 dark:bg-amber-900/60 dark:text-amber-300">
<div className="p-2.5 rounded-xl bg-amber-100 text-amber-700 dark:bg-amber-900/60 dark:text-amber-300 shrink-0 ml-2">
<Clock className="w-6 h-6" />
</div>
</div>
{/* KPI 4: Travados / 0% */}
<div className="p-3.5 rounded-2xl bg-rose-50/80 dark:bg-rose-950/40 border border-rose-200 dark:border-rose-800 shadow-sm flex items-center justify-between">
<div>
<div className="text-[11px] font-black uppercase text-rose-700 dark:text-rose-400">
Não Iniciados
<div className="min-w-0">
<div className="flex items-center gap-1.5 flex-wrap">
<span className="text-[11px] font-black uppercase text-rose-700 dark:text-rose-400">
Não Iniciados
</span>
<span className="text-[11px] font-black text-rose-800 dark:text-rose-300 bg-rose-200/80 dark:bg-rose-900/70 px-1.5 py-0.5 rounded-md border border-rose-300/80 dark:border-rose-700 shadow-2xs">
{formatarKg(resumoExibido.pesoNaoIniciadosKg)}
</span>
</div>
<div className="text-2xl font-black text-rose-900 dark:text-rose-100 mt-0.5">
<div className="text-2xl font-black text-rose-900 dark:text-rose-100 mt-1">
{resumoExibido.totalKitsNaoIniciados}
</div>
<div className="text-[10px] text-rose-700/80 dark:text-rose-400/80 font-medium">
<div className="text-[10px] text-rose-700/80 dark:text-rose-400/80 font-medium truncate">
sem nenhum componente cortado
</div>
</div>
<div className="p-2.5 rounded-xl bg-rose-100 text-rose-700 dark:bg-rose-900/60 dark:text-rose-300">
<div className="p-2.5 rounded-xl bg-rose-100 text-rose-700 dark:bg-rose-900/60 dark:text-rose-300 shrink-0 ml-2">
<AlertTriangle className="w-6 h-6" />
</div>
</div>
@@ -485,8 +527,13 @@ export const MapaTermicoKitsView: React.FC<MapaTermicoKitsViewProps> = ({
)}
</div>
<div className="text-xs text-slate-500 dark:text-slate-400 line-clamp-1">
{peca.descricao || 'Peça Estrutural'}
<div className="text-xs text-slate-500 dark:text-slate-400 flex items-center gap-1.5 flex-wrap">
<span className="line-clamp-1">{peca.descricao || 'Peça Estrutural'}</span>
{peca.peso_unitario > 0 && (
<span className="font-semibold text-slate-600 dark:text-slate-400 whitespace-nowrap">
• {peca.peso_unitario.toFixed(1)} kg/un (Total: {peca.peso_total_peca.toFixed(1)} kg)
</span>
)}
</div>
</div>
</div>