// Sistema de Acompanhamento de Produção // Função para fazer requisições autenticadas async function apiRequest(url, options = {}) { const token = localStorage.getItem('token'); const finalOptions = { ...options, headers: { 'Authorization': `Bearer ${token}`, ...options.headers } }; const response = await fetch(url, finalOptions); if (response.status === 401) { // Token expirado, redirecionar para login localStorage.removeItem('token'); window.location.href = '/login.html'; throw new Error('Token expirado'); } return response; } // Função principal para carregar acompanhamento async function carregarAcompanhamento(container) { container.innerHTML = `

Acompanhamento de Produção

Sistema para acompanhar e atualizar o status das etapas de produção das máquinas.
Filtros
Ordens de Fabricação
Carregando...
`; // Carregar dados iniciais await buscarOrdensAcompanhamento(); await carregarEstatisticasAcompanhamento(); } // Buscar ordens para acompanhamento async function buscarOrdensAcompanhamento() { const tabelaContainer = document.getElementById('tabela-acompanhamento'); try { const empresa = document.getElementById('filtroEmpresaAcomp')?.value || ''; const matricula = document.getElementById('filtroMatriculaAcomp')?.value || ''; const status = document.getElementById('filtroStatusAcomp')?.value || ''; const params = new URLSearchParams(); if (empresa) params.append('empresa', empresa); if (matricula) params.append('matricula', matricula); if (status) params.append('status', status); const response = await apiRequest(`${API_BASE}/acompanhamento?${params}`); const data = await response.json(); if (data.status === 'success') { exibirTabelaAcompanhamento(data.data, tabelaContainer); } else { throw new Error(data.message); } } catch (error) { tabelaContainer.innerHTML = `
Erro ao buscar ordens: ${error.message}
`; } } // Exibir tabela de acompanhamento function exibirTabelaAcompanhamento(ordens, container) { if (ordens.length === 0) { container.innerHTML = '
Nenhuma ordem encontrada com os filtros aplicados
'; return; } container.innerHTML = `
${ordens.map(ordem => { const proximaEtapa = obterProximaEtapa(ordem); const statusAtual = obterStatusAtual(ordem); const isPrazoVencido = new Date(ordem.PrazoEntrega) < new Date(); return ` `; }).join('')}
Comessa Cliente Máquina Prazo Workflow Atual Próxima Etapa Responsável Ações
${ordem.idOF} ${ordem.Empresa || ordem.NomeCliente || '-'} ${ordem.Matricula || '-'} ${formatarData(ordem.PrazoEntrega)} ${isPrazoVencido ? '' : ''} ${statusAtual.texto} ${proximaEtapa.nome} ${proximaEtapa.responsavel || '-'}
Total: ${ordens.length} ordem(ns) encontrada(s)
`; } // Obter próxima etapa function obterProximaEtapa(ordem) { const etapas = [ { campo: 'OrdemFabricacao', nome: 'Ordem de Fabricação', responsavel: ordem.ResponsavelOrdemFabricacao }, { campo: 'AprovacaoLayout', nome: 'Aprovação Layout', responsavel: ordem.ResponsavelAprovacaoLayout }, { campo: 'LiberacaoListasMecanica', nome: 'Lista Mecânica', responsavel: ordem.ResponsavelLiberacaoListasMecanica }, { campo: 'LiberacaoListasEletrica', nome: 'Lista Elétrica', responsavel: ordem.ResponsavelLiberacaoListasEletrica }, { campo: 'Separacao', nome: 'Separação', responsavel: ordem.ResponsavelSeparacao }, { campo: 'PreMontagem', nome: 'Pré-Montagem', responsavel: ordem.ResponsavelPreMontagem }, { campo: 'PreMontagemMecanica', nome: 'Montagem Mecânica', responsavel: null }, { campo: 'PreMontagemEletrica', nome: 'Pré-Montagem Elétrica', responsavel: null }, { campo: 'PreMontagemPainel', nome: 'Painel Elétrico', responsavel: null }, { campo: 'EletricaMontagem', nome: 'Cabeamento', responsavel: null }, { campo: 'Testes', nome: 'Testes', responsavel: null }, { campo: 'FAT', nome: 'F.A.T.', responsavel: null }, { campo: 'PreparacaoExpedicao', nome: 'Prep. Expedição', responsavel: null }, { campo: 'Expedicao', nome: 'Expedição', responsavel: null } ]; for (const etapa of etapas) { if (!ordem[etapa.campo] || ordem[etapa.campo] === 0) { return etapa; } } return { nome: 'Concluída', responsavel: null }; } // Obter status atual function obterStatusAtual(ordem) { if (ordem.Expedicao === 1) { return { texto: 'Expedição', classe: 'bg-success' }; } if (ordem.PreparacaoExpedicao === 1) { return { texto: 'Prep. Expedição', classe: 'bg-info' }; } if (ordem.FAT === 1) { return { texto: 'F.A.T.', classe: 'bg-info' }; } if (ordem.Testes === 1) { return { texto: 'Testes', classe: 'bg-info' }; } if (ordem.EletricaMontagem === 1) { return { texto: 'Cabeamento', classe: 'bg-warning text-dark' }; } if (ordem.PreMontagemPainel === 1) { return { texto: 'Painel Elétrico', classe: 'bg-warning text-dark' }; } if (ordem.PreMontagemEletrica === 1) { return { texto: 'Pré-Mont. Elétrica', classe: 'bg-warning text-dark' }; } if (ordem.PreMontagemMecanica === 1) { return { texto: 'Mont. Mecânica', classe: 'bg-warning text-dark' }; } if (ordem.PreMontagem === 1) { return { texto: 'Pré-Montagem', classe: 'bg-warning text-dark' }; } if (ordem.Separacao === 1) { return { texto: 'Separação', classe: 'bg-warning text-dark' }; } if (ordem.LiberacaoListasEletrica === 1) { return { texto: 'Lista Elétrica', classe: 'bg-warning text-dark' }; } if (ordem.LiberacaoListasMecanica === 1) { return { texto: 'Lista Mecânica', classe: 'bg-warning text-dark' }; } if (ordem.AprovacaoLayout === 1) { return { texto: 'Layout Aprovado', classe: 'bg-warning text-dark' }; } if (ordem.OrdemFabricacao === 1) { return { texto: 'OF Criada', classe: 'bg-primary' }; } return { texto: 'Pendente', classe: 'bg-secondary' }; } // Abrir modal de acompanhamento function abrirModalAcompanhamento(ordem) { // Criar modal se não existir let modal = document.getElementById('modalAcompanhamento'); if (!modal) { const modalHtml = ` `; document.body.insertAdjacentHTML('beforeend', modalHtml); modal = document.getElementById('modalAcompanhamento'); } // Preencher modal com dados da ordem const modalBody = document.getElementById('corpo-modal-acompanhamento'); modalBody.innerHTML = gerarConteudoModalAcompanhamento(ordem); // Abrir modal const bsModal = new bootstrap.Modal(modal); bsModal.show(); // Armazenar ordem atual window.ordemAtualAcompanhamento = ordem; } // Gerar conteúdo do modal de acompanhamento function gerarConteudoModalAcompanhamento(ordem) { const etapas = [ { campo: 'OrdemFabricacao', nome: 'Ordem de Fabricação', responsavel: 'ResponsavelOrdemFabricacao', data: 'DataOrdemFabricacao' }, { campo: 'AprovacaoLayout', nome: 'Aprovação do Layout', responsavel: 'ResponsavelAprovacaoLayout', data: 'DataAprovacaoLayout' }, { campo: 'LiberacaoListasMecanica', nome: 'Liberação Lista Mecânica', responsavel: 'ResponsavelLiberacaoListasMecanica', data: 'DataLiberacaoListasMecanica' }, { campo: 'LiberacaoListasEletrica', nome: 'Liberação Lista Elétrica', responsavel: 'ResponsavelLiberacaoListasEletrica', data: 'DataLiberacaoListasEletrica' }, { campo: 'Separacao', nome: 'Separação', responsavel: 'ResponsavelSeparacao', data: 'DataSeparacao' }, { campo: 'PreMontagem', nome: 'Pré-Montagem', responsavel: 'ResponsavelPreMontagem', data: 'DataPreMontagem' }, { campo: 'PreMontagemMecanica', nome: 'Montagem Mecânica', data: 'DataPreMontagemMecanica' }, { campo: 'PreMontagemEletrica', nome: 'Pré-Montagem Elétrica (Painel)', data: 'DataPreMontagemEletrica' }, { campo: 'PreMontagemPainel', nome: 'Painel Elétrico e Conjuntos', data: 'DataPreMontagemPainel' }, { campo: 'EletricaMontagem', nome: 'Montagem Elétrica (Cabeamento)', data: 'DataEletricaMontagem' }, { campo: 'Testes', nome: 'Testes (Funções e Rotulagem)', data: 'DataTestes' }, { campo: 'FAT', nome: 'F.A.T.', data: 'DataFAT' }, { campo: 'PreparacaoExpedicao', nome: 'Preparação para Expedição', data: 'DataPreparacaoExpedicao' }, { campo: 'Expedicao', nome: 'Expedição', data: 'DataExpedicao' } ]; const isPrazoVencido = new Date(ordem.PrazoEntrega) < new Date(); return `
Comessa ${ordem.idOF} - ${ordem.Matricula} Prazo: ${formatarData(ordem.PrazoEntrega)} ${isPrazoVencido ? ' (VENCIDO)' : ''}
Cliente: ${ordem.Empresa || ordem.NomeCliente || '-'}
Data Pedido: ${formatarData(ordem.DataPedido)}
Código Máquina: ${ordem.Matricula || '-'}
Status: ${obterStatusAtual(ordem).texto}
Cronograma de Serviços
${etapas.map((etapa, index) => { const concluida = ordem[etapa.campo] === 1; const responsavelAtual = etapa.responsavel ? ordem[etapa.responsavel] : ''; const dataAtual = etapa.data ? ordem[etapa.data] : null; return ` `; }).join('')}
Status Etapa Responsável Data Prevista Ações
${etapa.nome} ${concluida ? '' : ''}
Observações
`; } // Alterar status de etapa async function alterarStatusEtapa(etapa, concluida) { // Esta função será chamada quando o checkbox for alterado // A atualização real será feita no salvar ou individualmente } // Atualizar etapa individual async function atualizarEtapaIndividual(etapa) { try { const ordem = window.ordemAtualAcompanhamento; const checkbox = document.getElementById(`etapa_${etapa}`); const responsavel = document.getElementById(`resp_${etapa}`).value; const data = document.getElementById(`data_${etapa}`).value; const dadosAtualizacao = { valor: checkbox.checked ? 1 : 0, responsavel: responsavel, data_termino: data || null }; const response = await apiRequest(`${API_BASE}/acompanhamento/${ordem.idOF}/etapa/${etapa}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(dadosAtualizacao) }); const result = await response.json(); if (result.status === 'success') { mostrarSucesso(`Etapa ${etapa} atualizada com sucesso!`); // Atualizar responsável se fornecido if (responsavel) { await atualizarResponsavelEtapa(ordem.idOF, etapa, responsavel); } } else { throw new Error(result.message); } } catch (error) { mostrarErro('Erro ao atualizar etapa: ' + error.message); } } // Atualizar responsável de etapa async function atualizarResponsavelEtapa(idOF, etapa, responsavel) { try { const response = await apiRequest(`${API_BASE}/acompanhamento/${idOF}/responsavel/${etapa}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ responsavel }) }); const result = await response.json(); if (result.status !== 'success') { console.log('Aviso ao atualizar responsável:', result.message); } } catch (error) { console.error('Erro ao atualizar responsável:', error); } } // Salvar todas as alterações do acompanhamento async function salvarAcompanhamento() { try { const ordem = window.ordemAtualAcompanhamento; let alteracoes = 0; // Percorrer todas as etapas e verificar alterações const etapas = [ 'OrdemFabricacao', 'AprovacaoLayout', 'LiberacaoListasMecanica', 'LiberacaoListasEletrica', 'Separacao', 'PreMontagem', 'PreMontagemMecanica', 'PreMontagemEletrica', 'PreMontagemPainel', 'EletricaMontagem', 'Testes', 'FAT', 'PreparacaoExpedicao', 'Expedicao' ]; for (const etapa of etapas) { const checkbox = document.getElementById(`etapa_${etapa}`); const responsavel = document.getElementById(`resp_${etapa}`)?.value; const data = document.getElementById(`data_${etapa}`)?.value; if (checkbox) { const novoValor = checkbox.checked ? 1 : 0; const valorOriginal = ordem[etapa] === 1 ? 1 : 0; if (novoValor !== valorOriginal || responsavel || data) { await atualizarEtapaIndividual(etapa); alteracoes++; } } } // Atualizar observações const observacoes = document.getElementById('observacoes-ordem').value; if (observacoes !== (ordem.Observacoes || '')) { await atualizarObservacoes(ordem.idOF, observacoes); alteracoes++; } if (alteracoes > 0) { mostrarSucesso(`${alteracoes} alteração(ões) salva(s) com sucesso!`); // Fechar modal const modal = bootstrap.Modal.getInstance(document.getElementById('modalAcompanhamento')); modal.hide(); // Recarregar lista await buscarOrdensAcompanhamento(); } else { mostrarInfo('Nenhuma alteração detectada.'); } } catch (error) { mostrarErro('Erro ao salvar alterações: ' + error.message); } } // Atualizar observações async function atualizarObservacoes(idOF, observacao) { try { const response = await apiRequest(`${API_BASE}/acompanhamento/${idOF}/observacao`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ observacao }) }); const result = await response.json(); if (result.status !== 'success') { throw new Error(result.message); } } catch (error) { console.error('Erro ao atualizar observações:', error); throw error; } } // Carregar estatísticas de acompanhamento async function carregarEstatisticasAcompanhamento() { try { const response = await apiRequest(`${API_BASE}/acompanhamento/relatorio`); const data = await response.json(); if (data.status === 'success') { exibirEstatisticasAcompanhamento(data.data); } } catch (error) { console.error('Erro ao carregar estatísticas:', error); } } // Exibir estatísticas function exibirEstatisticasAcompanhamento(stats) { const container = document.getElementById('estatisticas-acompanhamento'); container.innerHTML = `

${stats.total_ordens}

Total de Ordens

${stats.ordens_iniciadas}

Ordens Iniciadas

${stats.ordens_em_andamento}

Em Andamento

${stats.ordens_finalizadas}

Finalizadas

`; } // Limpar filtros function limparFiltrosAcompanhamento() { document.getElementById('filtroEmpresaAcomp').value = ''; document.getElementById('filtroMatriculaAcomp').value = ''; document.getElementById('filtroStatusAcomp').value = ''; buscarOrdensAcompanhamento(); } // Ver detalhes de acompanhamento async function verDetalhesAcompanhamento(idOF) { // Buscar dados da ordem e abrir modal de detalhes try { const response = await apiRequest(`${API_BASE}/registros?idof=${idOF}`); const data = await response.json(); if (data.status === 'success' && data.data.length > 0) { abrirModalAcompanhamento(data.data[0]); } else { mostrarErro('Ordem não encontrada'); } } catch (error) { mostrarErro('Erro ao carregar detalhes: ' + error.message); } } // Funções de mensagem function mostrarSucesso(mensagem) { // Implementar toast ou alert de sucesso alert('✅ ' + mensagem); } function mostrarErro(mensagem) { // Implementar toast ou alert de erro alert('❌ ' + mensagem); } function mostrarInfo(mensagem) { // Implementar toast ou alert de info alert('ℹ️ ' + mensagem); }