fix: seletor de OFs no Mapa Termico de Kits
This commit is contained in:
@@ -20,7 +20,7 @@ import {
|
||||
Scissors
|
||||
} from 'lucide-react';
|
||||
import { useKitsProducao, PecaKitInfo } from '@/hooks/useKitsProducao';
|
||||
import { useOFs } from '@/hooks/useOFs';
|
||||
import { useOFsAtivas, OFAtiva } from '@/hooks/useOFsAtivas';
|
||||
|
||||
interface MapaTermicoKitsViewProps {
|
||||
initialOF?: string;
|
||||
@@ -35,8 +35,8 @@ export const MapaTermicoKitsView: React.FC<MapaTermicoKitsViewProps> = ({
|
||||
readOnlyOF = false,
|
||||
onSelectPecaParaApontar,
|
||||
}) => {
|
||||
const { ofs, loading: loadingOFs } = useOFs();
|
||||
const [selectedOF, setSelectedOF] = useState<string>(initialOF || (ofs[0]?.of_number || ''));
|
||||
const { ofsAtivas, isLoading: loadingOFs } = useOFsAtivas();
|
||||
const [selectedOF, setSelectedOF] = useState<string>(initialOF || '');
|
||||
const [selectedFase, setSelectedFase] = useState<string>(initialFase);
|
||||
const [busca, setBusca] = useState<string>('');
|
||||
const [filtroStatus, setFiltroStatus] = useState<'todos' | 'liberados' | 'parciais' | 'travados'>('todos');
|
||||
@@ -44,18 +44,20 @@ export const MapaTermicoKitsView: React.FC<MapaTermicoKitsViewProps> = ({
|
||||
|
||||
// Atualizar OF padrão se carregar depois
|
||||
React.useEffect(() => {
|
||||
if (!selectedOF && ofs.length > 0) {
|
||||
setSelectedOF(ofs[0].of_number);
|
||||
if (initialOF) {
|
||||
setSelectedOF(initialOF);
|
||||
} else if (!selectedOF && ofsAtivas.length > 0) {
|
||||
setSelectedOF(ofsAtivas[0].of_number);
|
||||
}
|
||||
}, [ofs, selectedOF]);
|
||||
}, [initialOF, ofsAtivas, selectedOF]);
|
||||
|
||||
const { listaKits, resumoKits, loading, refetch } = useKitsProducao(selectedOF, selectedFase);
|
||||
const { listaKits, resumoKits, loading, refetch } = useKitsProducao(selectedOF);
|
||||
|
||||
// Extrair fases únicas da lista de kits carregada
|
||||
// Extrair fases únicas da lista de kits carregada de toda a OF
|
||||
const fasesDisponiveis = useMemo(() => {
|
||||
const s = new Set<string>();
|
||||
listaKits.forEach((k) => {
|
||||
if (k.etapa_fase) s.add(k.etapa_fase);
|
||||
if (k.etapa_fase && k.etapa_fase.trim()) s.add(k.etapa_fase.trim());
|
||||
});
|
||||
return Array.from(s).sort((a, b) => a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' }));
|
||||
}, [listaKits]);
|
||||
@@ -81,9 +83,14 @@ export const MapaTermicoKitsView: React.FC<MapaTermicoKitsViewProps> = ({
|
||||
setPecasExpandidas(new Set());
|
||||
};
|
||||
|
||||
// Filtragem
|
||||
// Filtragem combinada (Fase + Status + Busca textual)
|
||||
const pecasFiltradas = useMemo(() => {
|
||||
return listaKits.filter((item) => {
|
||||
// Filtro de fase
|
||||
if (selectedFase && selectedFase !== 'all' && selectedFase !== 'todas') {
|
||||
if (item.etapa_fase !== selectedFase) return false;
|
||||
}
|
||||
|
||||
// Filtro de status
|
||||
if (filtroStatus === 'liberados') {
|
||||
if (item.kits_completos_cortados <= 0) return false;
|
||||
@@ -111,7 +118,41 @@ export const MapaTermicoKitsView: React.FC<MapaTermicoKitsViewProps> = ({
|
||||
|
||||
return true;
|
||||
});
|
||||
}, [listaKits, filtroStatus, busca]);
|
||||
}, [listaKits, selectedFase, filtroStatus, busca]);
|
||||
|
||||
// KPIs calculados com base nas peças filtradas
|
||||
const resumoExibido = useMemo(() => {
|
||||
let total100 = 0;
|
||||
let totalParciais = 0;
|
||||
let totalTravados = 0;
|
||||
let pesoTot = 0;
|
||||
let pesoCort = 0;
|
||||
let unTot = 0;
|
||||
let unLib = 0;
|
||||
|
||||
pecasFiltradas.forEach((item) => {
|
||||
unTot += item.quantidade_total;
|
||||
unLib += item.kits_completos_cortados;
|
||||
pesoTot += item.peso_total_componentes;
|
||||
pesoCort += item.peso_cortado_componentes;
|
||||
|
||||
if (item.status_termico === 'verde') total100++;
|
||||
else if (item.status_termico === 'verde_parcial' || item.status_termico === 'amarelo') totalParciais++;
|
||||
else totalTravados++;
|
||||
});
|
||||
|
||||
return {
|
||||
totalPecas: pecasFiltradas.length,
|
||||
totalKits100Porcento: total100,
|
||||
totalKitsParciais: totalParciais,
|
||||
totalKitsNaoIniciados: totalTravados,
|
||||
pesoTotalOFKg: pesoTot,
|
||||
pesoCortadoTotalKg: pesoCort,
|
||||
percentualGeralOF: pesoTot > 0 ? Math.min(100, Math.round((pesoCort / pesoTot) * 100)) : 0,
|
||||
totalUnidadesTotal: unTot,
|
||||
totalUnidadesLiberadasSolda: unLib,
|
||||
};
|
||||
}, [pecasFiltradas]);
|
||||
|
||||
return (
|
||||
<div className="space-y-4 w-full">
|
||||
@@ -159,14 +200,23 @@ export const MapaTermicoKitsView: React.FC<MapaTermicoKitsViewProps> = ({
|
||||
OF {selectedOF}
|
||||
</div>
|
||||
) : (
|
||||
<Select value={selectedOF} onValueChange={setSelectedOF} disabled={loadingOFs}>
|
||||
<Select
|
||||
value={selectedOF}
|
||||
onValueChange={(val) => {
|
||||
setSelectedOF(val);
|
||||
setSelectedFase('all');
|
||||
}}
|
||||
disabled={loadingOFs}
|
||||
>
|
||||
<SelectTrigger className="h-9 text-xs font-semibold">
|
||||
<SelectValue placeholder="Selecione uma OF..." />
|
||||
<SelectValue placeholder={loadingOFs ? "Carregando OFs..." : "Selecione uma OF..."}>
|
||||
{selectedOF ? `OF ${selectedOF}` : undefined}
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{ofs.map((o) => (
|
||||
<SelectItem key={o.id} value={o.of_number}>
|
||||
OF {o.of_number} {o.cliente ? `• ${o.cliente}` : ''}
|
||||
<SelectContent className="max-h-72">
|
||||
{ofsAtivas.map((o) => (
|
||||
<SelectItem key={o.of_number} value={o.of_number}>
|
||||
OF {o.of_number} {o.cliente ? `• ${o.cliente}` : o.descricao_resumida ? `• ${o.descricao_resumida}` : ''}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
@@ -214,7 +264,7 @@ export const MapaTermicoKitsView: React.FC<MapaTermicoKitsViewProps> = ({
|
||||
</Card>
|
||||
|
||||
{/* ──────────────── Cards de KPIs do Mapa Térmico ──────────────── */}
|
||||
{resumoKits && (
|
||||
{resumoExibido && (
|
||||
<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">
|
||||
@@ -223,7 +273,7 @@ export const MapaTermicoKitsView: React.FC<MapaTermicoKitsViewProps> = ({
|
||||
100% Liberadas
|
||||
</div>
|
||||
<div className="text-2xl font-black text-emerald-900 dark:text-emerald-100 mt-0.5">
|
||||
{resumoKits.totalKits100Porcento}
|
||||
{resumoExibido.totalKits100Porcento}
|
||||
</div>
|
||||
<div className="text-[10px] text-emerald-700/80 dark:text-emerald-400/80 font-medium">
|
||||
peças com todos os kits cortados
|
||||
@@ -241,7 +291,7 @@ export const MapaTermicoKitsView: React.FC<MapaTermicoKitsViewProps> = ({
|
||||
Unidades Liberadas
|
||||
</div>
|
||||
<div className="text-2xl font-black text-blue-900 dark:text-blue-100 mt-0.5">
|
||||
{resumoKits.totalUnidadesLiberadasSolda} <span className="text-xs text-blue-600 font-bold">/ {resumoKits.totalUnidadesTotal} un</span>
|
||||
{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">
|
||||
kits prontos na bancada de solda
|
||||
@@ -259,7 +309,7 @@ export const MapaTermicoKitsView: React.FC<MapaTermicoKitsViewProps> = ({
|
||||
Corte em Andamento
|
||||
</div>
|
||||
<div className="text-2xl font-black text-amber-900 dark:text-amber-100 mt-0.5">
|
||||
{resumoKits.totalKitsParciais}
|
||||
{resumoExibido.totalKitsParciais}
|
||||
</div>
|
||||
<div className="text-[10px] text-amber-700/80 dark:text-amber-400/80 font-medium">
|
||||
kits parciais (prioridade de corte)
|
||||
@@ -277,7 +327,7 @@ export const MapaTermicoKitsView: React.FC<MapaTermicoKitsViewProps> = ({
|
||||
Não Iniciados
|
||||
</div>
|
||||
<div className="text-2xl font-black text-rose-900 dark:text-rose-100 mt-0.5">
|
||||
{resumoKits.totalKitsNaoIniciados}
|
||||
{resumoExibido.totalKitsNaoIniciados}
|
||||
</div>
|
||||
<div className="text-[10px] text-rose-700/80 dark:text-rose-400/80 font-medium">
|
||||
sem nenhum componente cortado
|
||||
|
||||
Reference in New Issue
Block a user