fix: correcao de peso fabricado para pecas soltas, barras de processo concluidas em verde e legenda de cores
This commit is contained in:
@@ -185,9 +185,17 @@ export const OFCardOptimized: React.FC<OFCardOptimizedProps> = ({ ofData }) => {
|
|||||||
|
|
||||||
{/* Resumo Comparativo dos Processos - Layout Responsivo com espaçamento reduzido */}
|
{/* Resumo Comparativo dos Processos - Layout Responsivo com espaçamento reduzido */}
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<h3 className="text-base sm:text-lg font-semibold text-foreground border-b border-border pb-1" style={{ fontSize: 'clamp(1rem, 2.5vw, 1.125rem)' }}>
|
<div className="flex items-center justify-between border-b border-border pb-1">
|
||||||
Resumo Comparativo dos Processos
|
<h3 className="text-base sm:text-lg font-semibold text-foreground" style={{ fontSize: 'clamp(1rem, 2.5vw, 1.125rem)' }}>
|
||||||
</h3>
|
Resumo Comparativo dos Processos
|
||||||
|
</h3>
|
||||||
|
<div className="flex items-center gap-1.5 text-[10px] text-muted-foreground" title="Legenda: Azul = Adiantado | Verde = No Prazo/Concluído | Amarelo = Atenção | Vermelho = Atrasado">
|
||||||
|
<span className="w-2 h-2 rounded-full bg-blue-500" />
|
||||||
|
<span className="w-2 h-2 rounded-full bg-emerald-500" />
|
||||||
|
<span className="w-2 h-2 rounded-full bg-amber-500" />
|
||||||
|
<span className="w-2 h-2 rounded-full bg-rose-500" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{/* Grid responsivo: 1 coluna em mobile, 2 colunas em telas maiores */}
|
{/* Grid responsivo: 1 coluna em mobile, 2 colunas em telas maiores */}
|
||||||
<div className="
|
<div className="
|
||||||
grid grid-cols-1
|
grid grid-cols-1
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { X, ChevronLeft, ChevronRight, Play, Pause } from 'lucide-react';
|
import { X, ChevronLeft, ChevronRight, Play, Pause, Info } from 'lucide-react';
|
||||||
|
|
||||||
interface PainelHeaderProps {
|
interface PainelHeaderProps {
|
||||||
totalPages: number;
|
totalPages: number;
|
||||||
@@ -23,58 +22,94 @@ export const PainelHeader: React.FC<PainelHeaderProps> = ({
|
|||||||
onClose
|
onClose
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-between items-center">
|
<div className="mb-4 sm:mb-6">
|
||||||
<div>
|
<div className="flex flex-col lg:flex-row justify-between items-start lg:items-center gap-4">
|
||||||
<h1 className="text-4xl font-bold text-foreground mb-2">Painel Industrial</h1>
|
<div>
|
||||||
<p className="text-lg text-muted-foreground">
|
<h1 className="text-3xl sm:text-4xl font-black text-foreground tracking-tight">Painel Industrial</h1>
|
||||||
Acompanhamento comparativo em tempo real dos contratos.
|
<p className="text-sm sm:text-base text-muted-foreground mt-0.5">
|
||||||
</p>
|
Acompanhamento comparativo em tempo real dos contratos e processos de fabricação.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-2 sm:gap-3 self-stretch lg:self-auto justify-between lg:justify-end">
|
||||||
|
{totalPages > 1 && (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={onToggleAutoRotate}
|
||||||
|
className="flex items-center gap-2"
|
||||||
|
>
|
||||||
|
{autoRotate ? <Pause className="h-4 w-4" /> : <Play className="h-4 w-4" />}
|
||||||
|
{autoRotate ? 'Pausar' : 'Auto'}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={onPrevPage}
|
||||||
|
>
|
||||||
|
<ChevronLeft className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<span className="text-sm font-medium text-foreground px-1">
|
||||||
|
{currentPage + 1} de {totalPages}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
onClick={onNextPage}
|
||||||
|
>
|
||||||
|
<ChevronRight className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
variant="destructive"
|
||||||
|
size="sm"
|
||||||
|
onClick={onClose}
|
||||||
|
className="flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<X className="h-4 w-4" />
|
||||||
|
Fechar
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-4">
|
{/* Barra de Legendas de Cores dos Processos */}
|
||||||
{totalPages > 1 && (
|
<div className="mt-3 py-2 px-3.5 bg-card border border-border/80 rounded-lg shadow-sm flex flex-wrap items-center justify-between gap-y-2 gap-x-4 text-xs sm:text-sm">
|
||||||
<>
|
<div className="flex items-center gap-2 text-foreground font-semibold">
|
||||||
<Button
|
<Info className="h-4 w-4 text-primary shrink-0" />
|
||||||
variant="outline"
|
<span>Legenda das Cores dos Processos:</span>
|
||||||
size="lg"
|
</div>
|
||||||
onClick={onToggleAutoRotate}
|
|
||||||
className="flex items-center gap-2"
|
|
||||||
>
|
|
||||||
{autoRotate ? <Pause className="h-5 w-5" /> : <Play className="h-5 w-5" />}
|
|
||||||
{autoRotate ? 'Pausar' : 'Auto'}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<Button
|
<div className="flex flex-wrap items-center gap-x-4 sm:gap-x-6 gap-y-1.5">
|
||||||
variant="outline"
|
<div className="flex items-center gap-1.5">
|
||||||
size="lg"
|
<span className="w-2.5 h-2.5 rounded-full bg-blue-500 shadow-sm inline-block" />
|
||||||
onClick={onPrevPage}
|
<span className="font-semibold text-blue-500 dark:text-blue-400">Azul:</span>
|
||||||
>
|
<span className="text-muted-foreground text-xs">Adiantado (ritmo acima do cronograma)</span>
|
||||||
<ChevronLeft className="h-5 w-5" />
|
</div>
|
||||||
</Button>
|
|
||||||
|
|
||||||
<span className="text-lg font-medium text-foreground">
|
<div className="flex items-center gap-1.5">
|
||||||
{currentPage + 1} de {totalPages}
|
<span className="w-2.5 h-2.5 rounded-full bg-emerald-500 shadow-sm inline-block" />
|
||||||
</span>
|
<span className="font-semibold text-emerald-600 dark:text-emerald-400">Verde:</span>
|
||||||
|
<span className="text-muted-foreground text-xs">No Prazo / Concluído (100%)</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Button
|
<div className="flex items-center gap-1.5">
|
||||||
variant="outline"
|
<span className="w-2.5 h-2.5 rounded-full bg-amber-500 shadow-sm inline-block" />
|
||||||
size="lg"
|
<span className="font-semibold text-amber-500 dark:text-amber-400">Amarelo:</span>
|
||||||
onClick={onNextPage}
|
<span className="text-muted-foreground text-xs">Atenção (60% a 80% do ritmo planejado)</span>
|
||||||
>
|
</div>
|
||||||
<ChevronRight className="h-5 w-5" />
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Button
|
<div className="flex items-center gap-1.5">
|
||||||
variant="destructive"
|
<span className="w-2.5 h-2.5 rounded-full bg-rose-500 shadow-sm inline-block" />
|
||||||
size="lg"
|
<span className="font-semibold text-rose-500 dark:text-rose-400">Vermelho:</span>
|
||||||
onClick={onClose}
|
<span className="text-muted-foreground text-xs">Atrasado (<60% ou prazo do processo expirado)</span>
|
||||||
className="flex items-center gap-2"
|
</div>
|
||||||
>
|
</div>
|
||||||
<X className="h-5 w-5" />
|
|
||||||
Fechar
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ export const useDashboardProducaoOtimizado = (ofNumber: string) => {
|
|||||||
// 3. Buscar peças cadastradas para calcular peso total e peso soldável (peças com componentes)
|
// 3. Buscar peças cadastradas para calcular peso total e peso soldável (peças com componentes)
|
||||||
const { data: pecasData, error: pecasError } = await supabase
|
const { data: pecasData, error: pecasError } = await supabase
|
||||||
.from('pecas')
|
.from('pecas')
|
||||||
.select('peso_unitario, quantidade, tem_componentes')
|
.select('id, peso_unitario, quantidade, tem_componentes')
|
||||||
.eq('of_number', ofNumber);
|
.eq('of_number', ofNumber);
|
||||||
|
|
||||||
if (pecasError) {
|
if (pecasError) {
|
||||||
@@ -150,36 +150,64 @@ export const useDashboardProducaoOtimizado = (ofNumber: string) => {
|
|||||||
|
|
||||||
console.log('Apontamentos encontrados:', apontamentosData);
|
console.log('Apontamentos encontrados:', apontamentosData);
|
||||||
|
|
||||||
// 5. Calcular peso total fabricado - apenas processo de solda
|
// 5. Calcular peso total fabricado:
|
||||||
|
// - Para peças com componentes (tem_componentes = true): são finalizadas na SOLDA
|
||||||
|
// - Para peças soltas (tem_componentes = false): são finalizadas no CORTE (não passam por solda)
|
||||||
let pesoTotalFabricado = 0;
|
let pesoTotalFabricado = 0;
|
||||||
|
|
||||||
// Buscar ID do processo de solda
|
|
||||||
const processoSolda = await supabase
|
const processoSolda = await supabase
|
||||||
.from('processos_fabricacao')
|
.from('processos_fabricacao')
|
||||||
.select('id')
|
.select('id')
|
||||||
.ilike('nome', '%solda%')
|
.ilike('nome', '%solda%')
|
||||||
.single();
|
.single();
|
||||||
|
|
||||||
if (!processoSolda.error && processoSolda.data) {
|
const processoCorte = await supabase
|
||||||
const apontamentosSolda = apontamentosData.filter(a => a.processo_id === processoSolda.data.id);
|
.from('processos_fabricacao')
|
||||||
|
.select('id')
|
||||||
|
.ilike('nome', '%corte%')
|
||||||
|
.single();
|
||||||
|
|
||||||
|
const processoSoldaId = processoSolda.data?.id;
|
||||||
|
const processoCorteId = processoCorte.data?.id;
|
||||||
|
const pecasInfoMap = new Map((pecasData || []).map(p => [p.id, p]));
|
||||||
|
|
||||||
|
// 1. Somar peças com componentes apontadas na Solda
|
||||||
|
if (processoSoldaId) {
|
||||||
|
const apontamentosSolda = apontamentosData.filter(a => a.processo_id === processoSoldaId);
|
||||||
apontamentosSolda.forEach(apontamento => {
|
apontamentosSolda.forEach(apontamento => {
|
||||||
let pesoUnitario = 0;
|
let pesoUnitario = 0;
|
||||||
|
|
||||||
if (apontamento.tipo_apontamento === 'componente' && apontamento.componente?.peso_unitario) {
|
if (apontamento.tipo_apontamento === 'componente' && apontamento.componente?.peso_unitario) {
|
||||||
pesoUnitario = Number(apontamento.componente.peso_unitario);
|
pesoUnitario = Number(apontamento.componente.peso_unitario);
|
||||||
} else if (apontamento.tipo_apontamento === 'peca' && apontamento.peca?.peso_unitario) {
|
} else if (apontamento.tipo_apontamento === 'peca' && apontamento.peca?.peso_unitario) {
|
||||||
pesoUnitario = Number(apontamento.peca.peso_unitario);
|
pesoUnitario = Number(apontamento.peca.peso_unitario);
|
||||||
}
|
}
|
||||||
|
const pesoApontamento = pesoUnitario * Number(apontamento.quantidade_produzida || 0);
|
||||||
const pesoApontamento = pesoUnitario * Number(apontamento.quantidade_produzida);
|
|
||||||
pesoTotalFabricado += pesoApontamento;
|
pesoTotalFabricado += pesoApontamento;
|
||||||
|
|
||||||
console.log(`Apontamento Solda ID: ${apontamento.id}, Tipo: ${apontamento.tipo_apontamento}, Peso unitário: ${pesoUnitario} kg, Quantidade: ${apontamento.quantidade_produzida}, Peso total: ${pesoApontamento} kg`);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Peso total fabricado (apenas solda):', pesoTotalFabricado, 'kg');
|
// 2. Somar peças SOLTAS (sem componentes) apontadas no Corte
|
||||||
|
if (processoCorteId) {
|
||||||
|
const apontamentosCorte = apontamentosData.filter(a => a.processo_id === processoCorteId);
|
||||||
|
apontamentosCorte.forEach(apontamento => {
|
||||||
|
if (apontamento.tipo_apontamento === 'peca' && apontamento.peca_id) {
|
||||||
|
const peca = pecasInfoMap.get(apontamento.peca_id);
|
||||||
|
const temComponentes = peca?.tem_componentes === true;
|
||||||
|
if (!temComponentes && apontamento.peca?.peso_unitario) {
|
||||||
|
const pesoUnitario = Number(apontamento.peca.peso_unitario);
|
||||||
|
const pesoApontamento = pesoUnitario * Number(apontamento.quantidade_produzida || 0);
|
||||||
|
pesoTotalFabricado += pesoApontamento;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evita que ultrapasse o planejado por arredondamento
|
||||||
|
if (pesoTotalPlanejado > 0) {
|
||||||
|
pesoTotalFabricado = Math.min(pesoTotalFabricado, pesoTotalPlanejado);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Peso total fabricado (Solda p/ compostas + Corte p/ soltas):', pesoTotalFabricado, 'kg');
|
||||||
|
|
||||||
// 6. Calcular progresso geral - será recalculado após processar todos os processos
|
// 6. Calcular progresso geral - será recalculado após processar todos os processos
|
||||||
let progressoGeral = 0;
|
let progressoGeral = 0;
|
||||||
@@ -219,7 +247,7 @@ export const useDashboardProducaoOtimizado = (ofNumber: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 10. Buscar cronograma da OF para calcular progresso esperado correto
|
// 10. Buscar cronograma da OF para calcular progresso esperado correto
|
||||||
const { data: cronogramaOf } = await supabase
|
const { data: cronogramaRaw } = await supabase
|
||||||
.from('cronogramas_of')
|
.from('cronogramas_of')
|
||||||
.select(`
|
.select(`
|
||||||
id,
|
id,
|
||||||
@@ -233,19 +261,22 @@ export const useDashboardProducaoOtimizado = (ofNumber: string) => {
|
|||||||
.eq('of_id', ofData.id)
|
.eq('of_id', ofData.id)
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
|
|
||||||
|
const cronogramaOf = cronogramaRaw as any;
|
||||||
console.log('Cronograma da OF encontrado:', cronogramaOf);
|
console.log('Cronograma da OF encontrado:', cronogramaOf);
|
||||||
|
|
||||||
// Função para obter percentual esperado baseado nas datas do cronograma
|
// Função auxiliar para calcular progresso esperado baseado no cronograma
|
||||||
const calcularProgressoEsperado = (nomeProcesso: string): number => {
|
const calcularProgressoEsperado = (nomeProcesso: string): number => {
|
||||||
if (!cronogramaOf?.processos_cronograma) return 0;
|
if (!cronogramaOf?.processos_cronograma || cronogramaOf.processos_cronograma.length === 0) {
|
||||||
|
console.log(`Cronograma não encontrado para processo ${nomeProcesso}`);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const hoje = new Date();
|
const hoje = new Date();
|
||||||
let processoCronograma;
|
let processoCronograma;
|
||||||
|
|
||||||
// Mapear nomes dos processos para os do cronograma
|
// Mapear nomes dos processos para os do cronograma
|
||||||
if (nomeProcesso.toLowerCase().includes('corte') || nomeProcesso.toLowerCase().includes('solda')) {
|
if (nomeProcesso.toLowerCase().includes('corte') || nomeProcesso.toLowerCase().includes('solda')) {
|
||||||
// Usar datas do processo "Fabricação"
|
processoCronograma = cronogramaOf.processos_cronograma.find((p: any) =>
|
||||||
processoCronograma = cronogramaOf.processos_cronograma.find(p =>
|
|
||||||
p.nome_processo.toLowerCase().includes('fabricação') ||
|
p.nome_processo.toLowerCase().includes('fabricação') ||
|
||||||
p.nome_processo.toLowerCase().includes('fabricacao')
|
p.nome_processo.toLowerCase().includes('fabricacao')
|
||||||
);
|
);
|
||||||
@@ -253,13 +284,13 @@ export const useDashboardProducaoOtimizado = (ofNumber: string) => {
|
|||||||
nomeProcesso.toLowerCase().includes('expedição') || nomeProcesso.toLowerCase().includes('expedicao') ||
|
nomeProcesso.toLowerCase().includes('expedição') || nomeProcesso.toLowerCase().includes('expedicao') ||
|
||||||
nomeProcesso.toLowerCase().includes('montagem')) {
|
nomeProcesso.toLowerCase().includes('montagem')) {
|
||||||
// Usar datas do processo "Instalação" (incluindo "montagem")
|
// Usar datas do processo "Instalação" (incluindo "montagem")
|
||||||
processoCronograma = cronogramaOf.processos_cronograma.find(p =>
|
processoCronograma = cronogramaOf.processos_cronograma.find((p: any) =>
|
||||||
p.nome_processo.toLowerCase().includes('instalação') ||
|
p.nome_processo.toLowerCase().includes('instalação') ||
|
||||||
p.nome_processo.toLowerCase().includes('instalacao')
|
p.nome_processo.toLowerCase().includes('instalacao')
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Buscar processo com nome exato ou similar
|
// Buscar processo com nome exato ou similar
|
||||||
processoCronograma = cronogramaOf.processos_cronograma.find(p =>
|
processoCronograma = cronogramaOf.processos_cronograma.find((p: any) =>
|
||||||
p.nome_processo.toLowerCase().includes(nomeProcesso.toLowerCase()) ||
|
p.nome_processo.toLowerCase().includes(nomeProcesso.toLowerCase()) ||
|
||||||
nomeProcesso.toLowerCase().includes(p.nome_processo.toLowerCase())
|
nomeProcesso.toLowerCase().includes(p.nome_processo.toLowerCase())
|
||||||
);
|
);
|
||||||
@@ -350,13 +381,20 @@ export const useDashboardProducaoOtimizado = (ofNumber: string) => {
|
|||||||
// Determinar status baseado na comparação entre progresso real e esperado
|
// Determinar status baseado na comparação entre progresso real e esperado
|
||||||
let status: 'verde' | 'amarelo' | 'vermelho' | 'azul';
|
let status: 'verde' | 'amarelo' | 'vermelho' | 'azul';
|
||||||
|
|
||||||
// Se o progresso esperado chegou a 100% (passou da data fim), usar cor vermelha na barra
|
// Tolerância de conclusão: 99.5% ou mais é considerado 100% concluído (evita erros por dízimas em somas de peso)
|
||||||
if (progressoEsperado >= 100) {
|
const isConcluido = progressoReal >= 99.5;
|
||||||
if (progressoReal >= 100) {
|
|
||||||
status = 'verde'; // Concluído no prazo
|
if (isConcluido) {
|
||||||
|
// Se já concluiu 100%:
|
||||||
|
// Se concluiu antes do prazo final (progressoEsperado < 100), fica azul (Adiantado), senão verde (Concluído)
|
||||||
|
if (progressoEsperado < 100) {
|
||||||
|
status = 'azul'; // Adiantado
|
||||||
} else {
|
} else {
|
||||||
status = 'vermelho'; // Atrasado (passou da data fim mas não concluído)
|
status = 'verde'; // Concluído no prazo
|
||||||
}
|
}
|
||||||
|
} else if (progressoEsperado >= 100) {
|
||||||
|
// Passou da data fim e ainda não concluiu: Atrasado
|
||||||
|
status = 'vermelho';
|
||||||
} else if (progressoEsperado > 0) {
|
} else if (progressoEsperado > 0) {
|
||||||
// Comparar progresso real com esperado
|
// Comparar progresso real com esperado
|
||||||
if (progressoReal > progressoEsperado) {
|
if (progressoReal > progressoEsperado) {
|
||||||
@@ -391,19 +429,19 @@ export const useDashboardProducaoOtimizado = (ofNumber: string) => {
|
|||||||
|
|
||||||
// Mapear nomes dos processos para os do cronograma
|
// Mapear nomes dos processos para os do cronograma
|
||||||
if (processo.nome.toLowerCase().includes('corte') || processo.nome.toLowerCase().includes('solda')) {
|
if (processo.nome.toLowerCase().includes('corte') || processo.nome.toLowerCase().includes('solda')) {
|
||||||
processoCronograma = cronogramaOf.processos_cronograma.find(p =>
|
processoCronograma = cronogramaOf.processos_cronograma.find((p: any) =>
|
||||||
p.nome_processo.toLowerCase().includes('fabricação') ||
|
p.nome_processo.toLowerCase().includes('fabricação') ||
|
||||||
p.nome_processo.toLowerCase().includes('fabricacao')
|
p.nome_processo.toLowerCase().includes('fabricacao')
|
||||||
);
|
);
|
||||||
} else if (processo.nome.toLowerCase().includes('pint') || processo.nome.toLowerCase().includes('galv') ||
|
} else if (processo.nome.toLowerCase().includes('pint') || processo.nome.toLowerCase().includes('galv') ||
|
||||||
processo.nome.toLowerCase().includes('expedição') || processo.nome.toLowerCase().includes('expedicao') ||
|
processo.nome.toLowerCase().includes('expedição') || processo.nome.toLowerCase().includes('expedicao') ||
|
||||||
processo.nome.toLowerCase().includes('montagem')) {
|
processo.nome.toLowerCase().includes('montagem')) {
|
||||||
processoCronograma = cronogramaOf.processos_cronograma.find(p =>
|
processoCronograma = cronogramaOf.processos_cronograma.find((p: any) =>
|
||||||
p.nome_processo.toLowerCase().includes('instalação') ||
|
p.nome_processo.toLowerCase().includes('instalação') ||
|
||||||
p.nome_processo.toLowerCase().includes('instalacao')
|
p.nome_processo.toLowerCase().includes('instalacao')
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
processoCronograma = cronogramaOf.processos_cronograma.find(p =>
|
processoCronograma = cronogramaOf.processos_cronograma.find((p: any) =>
|
||||||
p.nome_processo.toLowerCase().includes(processo.nome.toLowerCase()) ||
|
p.nome_processo.toLowerCase().includes(processo.nome.toLowerCase()) ||
|
||||||
processo.nome.toLowerCase().includes(p.nome_processo.toLowerCase())
|
processo.nome.toLowerCase().includes(p.nome_processo.toLowerCase())
|
||||||
);
|
);
|
||||||
@@ -537,7 +575,11 @@ export const useDashboardProducaoOtimizado = (ofNumber: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Recalcular status do processo "Concluído"
|
// Recalcular status do processo "Concluído"
|
||||||
if (processo.progressoEsperado > 0) {
|
if (processo.progressoReal >= 99.5) {
|
||||||
|
processo.status = 'verde'; // Concluído
|
||||||
|
} else if (processo.progressoEsperado >= 100) {
|
||||||
|
processo.status = 'vermelho'; // Atrasado (prazo expirou e ainda não finalizou)
|
||||||
|
} else if (processo.progressoEsperado > 0) {
|
||||||
if (processo.progressoReal > processo.progressoEsperado) {
|
if (processo.progressoReal > processo.progressoEsperado) {
|
||||||
processo.status = 'azul'; // Adiantado
|
processo.status = 'azul'; // Adiantado
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user