diff --git a/src/components/apontamento/kits/MapaTermicoKitsView.tsx b/src/components/apontamento/kits/MapaTermicoKitsView.tsx index 8cb651b..67c5047 100644 --- a/src/components/apontamento/kits/MapaTermicoKitsView.tsx +++ b/src/components/apontamento/kits/MapaTermicoKitsView.tsx @@ -120,6 +120,12 @@ export const MapaTermicoKitsView: React.FC = ({ }); }, [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 = ({ 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 = ({ 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 = ({
{/* KPI 1: 100% Liberadas */}
-
-
- 100% Liberadas +
+
+ + 100% Liberadas + + + {formatarKg(resumoExibido.peso100PorcentoKg)} +
-
+
{resumoExibido.totalKits100Porcento}
-
+
peças com todos os kits cortados
-
+
{/* KPI 2: Kits Montáveis Liberados */}
-
-
- Unidades Liberadas +
+
+ + Unidades Liberadas + + + {formatarKg(resumoExibido.pesoUnidadesLiberadasKg)} +
-
+
{resumoExibido.totalUnidadesLiberadasSolda} / {resumoExibido.totalUnidadesTotal} un
-
+
kits prontos na bancada de solda
-
+
{/* KPI 3: Em Andamento / Quase Prontos */}
-
-
- Corte em Andamento +
+
+ + Corte em Andamento + + + {formatarKg(resumoExibido.pesoParciaisKg)} +
-
+
{resumoExibido.totalKitsParciais}
-
+
kits parciais (prioridade de corte)
-
+
{/* KPI 4: Travados / 0% */}
-
-
- Não Iniciados +
+
+ + Não Iniciados + + + {formatarKg(resumoExibido.pesoNaoIniciadosKg)} +
-
+
{resumoExibido.totalKitsNaoIniciados}
-
+
sem nenhum componente cortado
-
+
@@ -485,8 +527,13 @@ export const MapaTermicoKitsView: React.FC = ({ )}
-
- {peca.descricao || 'Peça Estrutural'} +
+ {peca.descricao || 'Peça Estrutural'} + {peca.peso_unitario > 0 && ( + + • {peca.peso_unitario.toFixed(1)} kg/un (Total: {peca.peso_total_peca.toFixed(1)} kg) + + )}
diff --git a/src/hooks/useKitsProducao.ts b/src/hooks/useKitsProducao.ts index e235f65..419bc0d 100644 --- a/src/hooks/useKitsProducao.ts +++ b/src/hooks/useKitsProducao.ts @@ -26,6 +26,9 @@ export interface PecaKitInfo { quantidade_total: number; etapa_fase: string; tem_componentes: boolean; + peso_unitario: number; + peso_total_peca: number; + peso_kits_liberados: number; componentes: ComponenteKitInfo[]; kits_completos_cortados: number; // Quantidade de kits 100% montáveis liberados percentual_termico: number; // 0 a 100% @@ -46,6 +49,10 @@ export interface ResumoKitsOF { totalKitsNaoIniciados: number; pesoTotalOFKg: number; pesoCortadoTotalKg: number; + peso100PorcentoKg: number; + pesoUnidadesLiberadasKg: number; + pesoParciaisKg: number; + pesoNaoIniciadosKg: number; percentualGeralOF: number; totalUnidadesTotal: number; totalUnidadesLiberadasSolda: number; @@ -64,6 +71,8 @@ export const calcularKitsOF = ( quantidade: number; etapa_fase?: string | null; tem_componentes?: boolean | null; + peso_unitario?: number | null; + peso_total?: number | null; }>, componentes: Array<{ id: string; @@ -153,12 +162,17 @@ export const calcularKitsOF = ( const temComps = peca.tem_componentes !== false && compsRaw.length > 0; const jaApontadoSolda = apontadoNaSoldaPorPeca.get(peca.id) || 0; + const pesoUnitPeca = Number(peca.peso_unitario) || (qtdTotalPeca > 0 && peca.peso_total ? Number(peca.peso_total) / qtdTotalPeca : 0); + const pesoTotalPeca = Number(peca.peso_total) || (qtdTotalPeca * pesoUnitPeca); + // Cenário A: Peça sem componentes (monobloco / S/M) if (!temComps) { const qtdCortada = cortadoPecaNoCorte.get(peca.id) || 0; const kitsCompletos = Math.min(qtdTotalPeca, qtdCortada); const pct = qtdTotalPeca > 0 ? Math.min(100, Math.round((kitsCompletos / qtdTotalPeca) * 100)) : 0; const saldoSolda = Math.max(0, kitsCompletos - jaApontadoSolda); + const pesoCortado = kitsCompletos * pesoUnitPeca; + const pesoLiberado = kitsCompletos * pesoUnitPeca; mapaKits.set(peca.id, { peca_id: peca.id, @@ -168,6 +182,9 @@ export const calcularKitsOF = ( quantidade_total: qtdTotalPeca, etapa_fase: fase, tem_componentes: false, + peso_unitario: pesoUnitPeca, + peso_total_peca: pesoTotalPeca, + peso_kits_liberados: pesoLiberado, componentes: [], kits_completos_cortados: kitsCompletos, percentual_termico: pct, @@ -180,8 +197,8 @@ export const calcularKitsOF = ( ? 'amarelo' : 'vermelho', componente_gargalo: null, - peso_total_componentes: 0, - peso_cortado_componentes: 0, + peso_total_componentes: pesoTotalPeca, + peso_cortado_componentes: pesoCortado, ja_apontado_solda: jaApontadoSolda, saldo_disponivel_solda: peca.tem_componentes === false ? 0 : saldoSolda, bloqueado_para_solda: peca.tem_componentes === false || saldoSolda <= 0, @@ -293,6 +310,11 @@ export const calcularKitsOF = ( } } + const pesoUnitComps = pesoTotalComps > 0 && qtdTotalPeca > 0 ? pesoTotalComps / qtdTotalPeca : 0; + const pesoUnitPecaFinal = Number(peca.peso_unitario) || pesoUnitComps; + const pesoTotalPecaFinal = pesoTotalComps > 0 ? pesoTotalComps : (Number(peca.peso_total) || (qtdTotalPeca * pesoUnitPecaFinal)); + const pesoLiberadoFinal = kitsCompletos * pesoUnitPecaFinal; + mapaKits.set(peca.id, { peca_id: peca.id, marca: peca.marca, @@ -301,12 +323,15 @@ export const calcularKitsOF = ( quantidade_total: qtdTotalPeca, etapa_fase: fase, tem_componentes: true, + peso_unitario: pesoUnitPecaFinal, + peso_total_peca: pesoTotalPecaFinal, + peso_kits_liberados: pesoLiberadoFinal, componentes: listaCompsInfo, kits_completos_cortados: kitsCompletos, percentual_termico: percentualTermico, status_termico: statusTermico, componente_gargalo: gargaloComp, - peso_total_componentes: pesoTotalComps, + peso_total_componentes: pesoTotalPecaFinal, peso_cortado_componentes: pesoCortadoComps, ja_apontado_solda: jaApontadoSolda, saldo_disponivel_solda: saldoSolda, @@ -345,7 +370,7 @@ export const useKitsProducao = (ofNumber?: string, fase?: string) => { // 2. Buscar peças da OF let pecasQuery = supabase .from('pecas') - .select('id, marca, descricao, perfil_principal, quantidade, etapa_fase, tem_componentes') + .select('id, marca, descricao, perfil_principal, quantidade, etapa_fase, tem_componentes, peso_unitario, peso_total') .eq('of_number', ofNumber); if (fase && fase !== 'all' && fase !== 'Todas as fases' && fase !== 'todas') { @@ -411,18 +436,30 @@ export const useKitsProducao = (ofNumber?: string, fase?: string) => { 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; lista.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; + } }); const resumo: ResumoKitsOF = { @@ -432,6 +469,10 @@ export const useKitsProducao = (ofNumber?: string, fase?: string) => { totalKitsNaoIniciados: totalTravados, pesoTotalOFKg: pesoTot, pesoCortadoTotalKg: pesoCort, + peso100PorcentoKg: peso100, + pesoUnidadesLiberadasKg: pesoUnLiberadas, + pesoParciaisKg: pesoParciais, + pesoNaoIniciadosKg: pesoNaoIniciados, percentualGeralOF: pesoTot > 0 ? Math.round((pesoCortadoTotalKg(pesoTot, pesoCort)) * 100) : 0, totalUnidadesTotal: unTot, totalUnidadesLiberadasSolda: unLib,