// Sistema PELL - Controle de Produção (Modo Somente Leitura) /* const API_BASE = 'http://localhost:3000/api'; */ // O host da API será o mesmo do endereço que você acessa no navegador const API_BASE = `${window.location.protocol}//${window.location.hostname}:3000/api`; // Função utilitária para fazer requisições com autenticação async function apiRequest(url, options = {}) { const token = localStorage.getItem('authToken'); const defaultOptions = { headers: { 'Content-Type': 'application/json', ...(token && { 'Authorization': `Bearer ${token}` }) } }; const finalOptions = { ...defaultOptions, ...options, headers: { ...defaultOptions.headers, ...options.headers } }; console.log('🚀 API Request:', url, 'Token:', token ? 'EXISTS' : 'MISSING'); const response = await fetch(url, finalOptions); if (response.status === 401) { console.log('❌ 401 Unauthorized - redirecting to login'); window.location.href = '/login.html'; throw new Error('Não autorizado'); } return response; } // Estado da aplicação let paginaAtual = ''; // Função para carregar páginas async function carregarPagina(pagina) { const conteudo = document.getElementById('conteudo-principal'); // Atualizar navegação ativa document.querySelectorAll('.nav-link').forEach(link => { link.classList.remove('active'); }); event?.target.classList.add('active'); paginaAtual = pagina; try { switch (pagina) { case 'dashboard': await carregarDashboard(conteudo); break; case 'ordens': await carregarOrdens(conteudo); break; case 'acompanhamento': await carregarAcompanhamento(conteudo); break; case 'relatorios': await carregarRelatorios(conteudo); break; case 'whatsapp': await carregarWhatsApp(conteudo); break; case 'clientes': await carregarClientes(conteudo); break; case 'materiais': await carregarMateriais(conteudo); break; default: conteudo.innerHTML = '
Página não encontrada
'; } } catch (error) { console.error('Erro ao carregar página:', error); conteudo.innerHTML = `
Erro ao carregar ${pagina}: ${error.message}
`; } } // Dashboard async function carregarDashboard(container) { container.innerHTML = `

Dashboard - Sistema PELL

Carregando...
Ordens por Empresa
Últimas Ordens
`; try { const response = await apiRequest(`${API_BASE}/dashboard`); const data = await response.json(); if (data.status === 'success') { exibirEstatisticasDashboard(data.data.estatisticas); exibirGraficoEmpresas(data.data.ordens_por_empresa); exibirUltimasOrdens(data.data.ultimas_ordens); } else { throw new Error(data.message); } } catch (error) { document.getElementById('dashboard-stats').innerHTML = `
Erro ao carregar dashboard: ${error.message}
`; } } // Exibir estatísticas do dashboard function exibirEstatisticasDashboard(stats) { const statsContainer = document.getElementById('dashboard-stats'); statsContainer.innerHTML = `

${stats.total_ordens}

Total de Ordens

${stats.ordens_iniciadas}

Iniciadas

${stats.em_testes}

Em Testes

${stats.expedidas}

Expedidas
`; } // Gráfico de ordens por empresa function exibirGraficoEmpresas(dados) { const ctx = document.getElementById('graficoEmpresas').getContext('2d'); new Chart(ctx, { type: 'doughnut', data: { labels: dados.map(item => item.Empresa || 'Sem empresa'), datasets: [{ data: dados.map(item => item.total), backgroundColor: [ '#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF', '#FF9F40', '#FF6384', '#C9CBCF', '#4BC0C0', '#FF6384' ] }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'bottom' } } } }); } // Últimas ordens function exibirUltimasOrdens(ordens) { const container = document.getElementById('ultimas-ordens'); if (ordens.length === 0) { container.innerHTML = '

Nenhuma ordem encontrada

'; return; } container.innerHTML = ordens.map(ordem => `
OF #${ordem.idOF}
${ordem.Empresa || 'Sem empresa'} | ${ordem.Matricula || 'Sem máquina'}
${formatarData(ordem.DataPedido)}
Prazo: ${formatarData(ordem.PrazoEntrega)}
`).join(''); } // Ordens de Fabricação async function carregarOrdens(container) { container.innerHTML = `

Ordens de Fabricação

Carregando...
`; await buscarOrdens(); } async function buscarOrdens() { const tabelaContainer = document.getElementById('tabela-ordens'); try { const empresa = document.getElementById('filtroEmpresa')?.value || ''; const matricula = document.getElementById('filtroMatricula')?.value || ''; const params = new URLSearchParams(); if (empresa) params.append('empresa', empresa); if (matricula) params.append('matricula', matricula); const response = await apiRequest(`${API_BASE}/registros?${params}`); const data = await response.json(); if (data.status === 'success') { exibirTabelaOrdens(data.data, tabelaContainer); } else { throw new Error(data.message); } } catch (error) { tabelaContainer.innerHTML = `
Erro ao buscar ordens: ${error.message}
`; } } function exibirTabelaOrdens(ordens, container) { if (ordens.length === 0) { container.innerHTML = '
Nenhuma ordem encontrada com os filtros aplicados
'; return; } container.innerHTML = `
${ordens.map(ordem => ` `).join('')}
Comessa Cliente Código Máquina Nome Comercial Data do Pedido Prazo de Entrega Progresso Ações
${ordem.idOF} ${ordem.Empresa || '-'} ${ordem.Matricula || '-'} ${ordem.NomeComercial || '-'} ${formatarData(ordem.DataPedido)} ${formatarData(ordem.PrazoEntrega)}
${gerarWorkflowMini(ordem)}
Total: ${ordens.length} ordem(ns) encontrada(s)
`; } // Workflow mini para a tabela function gerarWorkflowMini(ordem) { const etapas = [ ordem.OrdemFabricacao, ordem.AprovacaoLayout, ordem.LiberacaoListasMecanica, ordem.LiberacaoListasEletrica, ordem.Separacao, ordem.PreMontagem, ordem.PreMontagemEletrica, ordem.PreMontagemMecanica, ordem.PreMontagemPainel, ordem.EletricaMontagem, ordem.Testes, ordem.FAT, ordem.PreparacaoExpedicao ]; let html = ''; etapas.forEach((etapa, index) => { let classe = 'pendente'; if (etapa === 1) { classe = 'concluida'; } else if (index > 0 && etapas[index - 1] === 1 && etapa !== 1) { classe = 'em-andamento'; } html += `
`; }); return html; } // Funções auxiliares para ordens function obterStatusOrdem(ordem) { if (ordem.Expedicao === 1) return 'Expedida'; if (ordem.Testes === 1) return 'Em Testes'; if (ordem.OrdemFabricacao === 1) return 'Iniciada'; return 'Pendente'; } function isPrazoVencido(prazoEntrega) { if (!prazoEntrega) return false; const hoje = new Date(); const prazo = new Date(prazoEntrega); return prazo < hoje; } function limparFiltrosOrdens() { document.getElementById('filtroEmpresa').value = ''; document.getElementById('filtroMatricula').value = ''; buscarOrdens(); } async function verDetalhesOrdem(idOF) { const modal = new bootstrap.Modal(document.getElementById('modalDetalhes')); const modalTitle = document.querySelector('#modalDetalhes .modal-title'); const modalBody = document.getElementById('modal-body-content'); modalTitle.textContent = 'Detalhes da Ordem de Fabricação'; modalBody.innerHTML = `
Carregando...
`; modal.show(); try { const response = await apiRequest(`${API_BASE}/registros?idof=${idOF}`); const data = await response.json(); if (data.status === 'success' && data.data.length > 0) { const ordem = data.data[0]; modalBody.innerHTML = `
Informações Gerais
Comessa:${ordem.idOF}
Matrícula:${ordem.Matricula || '-'}
Cliente:${ordem.Empresa || '-'}
Nome Comercial:${ordem.NomeComercial || '-'}
Data do Pedido:${formatarData(ordem.DataPedido)}
Prazo de Entrega:${formatarData(ordem.PrazoEntrega)}
Responsáveis
${ordem.ResponsavelOrdemFabricacao ? `
OF: ${ordem.ResponsavelOrdemFabricacao}
` : ''} ${ordem.ResponsavelAprovacaoLayout ? `
Layout: ${ordem.ResponsavelAprovacaoLayout}
` : ''} ${ordem.ResponsavelLiberacaoListasMecanica ? `
Lista Mecânica: ${ordem.ResponsavelLiberacaoListasMecanica}
` : ''} ${ordem.ResponsavelLiberacaoListasEletrica ? `
Lista Elétrica: ${ordem.ResponsavelLiberacaoListasEletrica}
` : ''} ${ordem.ResponsavelSeparacao ? `
Separação: ${ordem.ResponsavelSeparacao}
` : ''} ${ordem.ResponsavelPreMontagem ? `
Pré-Montagem: ${ordem.ResponsavelPreMontagem}
` : ''}
Workflow de Produção
${gerarWorkflowVisual(ordem)}
`; } else { modalBody.innerHTML = '
Ordem não encontrada
'; } } catch (error) { modalBody.innerHTML = `
Erro ao carregar detalhes: ${error.message}
`; } } // Gerar workflow visual igual ao da imagem function gerarWorkflowVisual(ordem) { const etapas = [ { key: 'OrdemFabricacao', label: 'OF', valor: ordem.OrdemFabricacao }, { key: 'AprovacaoLayout', label: 'Layout', valor: ordem.AprovacaoLayout }, { key: 'LiberacaoListasMecanica', label: 'Lista Mecânica', valor: ordem.LiberacaoListasMecanica }, { key: 'LiberacaoListasEletrica', label: 'Lista Elétrica', valor: ordem.LiberacaoListasEletrica }, { key: 'Separacao', label: 'Separação', valor: ordem.Separacao }, { key: 'PreMontagemEletrica', label: 'Pré-Montagem
Elétrica', valor: ordem.PreMontagemEletrica, sublabel: true }, { key: 'PreMontagemMecanica', label: 'Pré-Montagem
Mecânica', valor: ordem.PreMontagemMecanica, sublabel: true }, { key: 'PreMontagemPainel', label: 'Painel Elétrico', valor: ordem.PreMontagemPainel }, { key: 'EletricaMontagem', label: 'Cabeamento', valor: ordem.EletricaMontagem }, { key: 'Testes', label: 'Testes', valor: ordem.Testes }, { key: 'FAT', label: 'FAT', valor: ordem.FAT }, { key: 'PreparacaoExpedicao', label: 'Preparação Expedição', valor: ordem.PreparacaoExpedicao } ]; let html = `
Comessa: ${ordem.idOF} | Matricula: ${ordem.Matricula}
`; etapas.forEach((etapa, index) => { const concluida = etapa.valor === 1; const emAndamento = index > 0 && etapas[index - 1].valor === 1 && !concluida; let statusClass = ''; let statusColor = ''; if (concluida) { statusClass = 'concluida'; statusColor = '#28a745'; // Verde } else if (emAndamento) { statusClass = 'em-andamento'; statusColor = '#ffc107'; // Amarelo } else { statusClass = 'pendente'; statusColor = '#6c757d'; // Cinza } html += `
${etapa.sublabel ? etapa.label : `${etapa.label}`}
`; }); html += '
'; // Adicionar estilos CSS para o workflow html += ` `; return html; } // Relatórios async function carregarRelatorios(container) { container.innerHTML = `

Relatórios do Sistema PELL

Ordens por Período

Relatório de ordens de fabricação filtradas por período e empresa.

Ordens por Empresa

Relatório consolidado de ordens agrupadas por empresa/cliente.




Status do Workflow

Relatório do status das etapas do workflow de produção.



Comessas

Relatório detalhado de comessas do sistema.



Cartão de Ponto por Comessa
Em Desenvolvimento: O relatório de cartão de ponto está sendo preparado com as particularidades específicas do sistema.

Este relatório mostrará dados detalhados de ponto dos funcionários por comessa, incluindo horas trabalhadas, períodos e totalizações.

`; } // Funções para gerar relatórios async function gerarRelatorioOrdensPeriodo() { const dataInicio = document.getElementById('dataInicio').value; const dataFim = document.getElementById('dataFim').value; const empresa = document.getElementById('empresaFiltro').value; const container = document.getElementById('resultado-relatorio'); container.innerHTML = `
Relatório: Ordens por Período
Gerando relatório...
`; try { const params = new URLSearchParams(); if (dataInicio) params.append('data_inicio', dataInicio); if (dataFim) params.append('data_fim', dataFim); if (empresa) params.append('empresa', empresa); const response = await apiRequest(`${API_BASE}/relatorios/ordens-periodo?${params}`); const data = await response.json(); if (data.status === 'success') { exibirRelatorioOrdensPeriodo(data, container); } else { throw new Error(data.message); } } catch (error) { container.innerHTML = `
Erro ao gerar relatório: ${error.message}
`; } } async function gerarRelatorioOrdensEmpresa() { const empresa = document.getElementById('empresaRelatorio').value; const container = document.getElementById('resultado-relatorio'); container.innerHTML = `
Relatório: Ordens por Empresa
Gerando relatório...
`; try { const params = new URLSearchParams(); if (empresa) params.append('empresa', empresa); const response = await apiRequest(`${API_BASE}/relatorios/ordens-empresa?${params}`); const data = await response.json(); if (data.status === 'success') { exibirRelatorioOrdensEmpresa(data, container); } else { throw new Error(data.message); } } catch (error) { container.innerHTML = `
Erro ao gerar relatório: ${error.message}
`; } } async function gerarRelatorioWorkflow() { const periodo = document.getElementById('periodoWorkflow').value; const container = document.getElementById('resultado-relatorio'); container.innerHTML = `
Relatório: Status do Workflow
Gerando relatório...
`; try { const params = new URLSearchParams(); if (periodo) params.append('periodo', periodo); const response = await apiRequest(`${API_BASE}/relatorios/workflow-status?${params}`); const data = await response.json(); if (data.status === 'success') { exibirRelatorioWorkflow(data, container); } else { throw new Error(data.message); } } catch (error) { container.innerHTML = `
Erro ao gerar relatório: ${error.message}
`; } } async function gerarRelatorioComessas() { const codigo = document.getElementById('codigoComessa').value; const container = document.getElementById('resultado-relatorio'); container.innerHTML = `
Relatório: Comessas
Gerando relatório...
`; try { const params = new URLSearchParams(); if (codigo) params.append('codigo_comessa', codigo); const response = await apiRequest(`${API_BASE}/relatorios/comessas?${params}`); const data = await response.json(); if (data.status === 'success') { exibirRelatorioComessas(data, container); } else { throw new Error(data.message); } } catch (error) { container.innerHTML = `
Erro ao gerar relatório: ${error.message}
`; } } // Materiais (placeholder) async function carregarMateriais(container) { container.innerHTML = `

Materiais

Módulo de materiais em desenvolvimento. Esta seção permitirá visualizar o estoque e informações dos materiais.
`; } // Relatórios async function carregarRelatorios(container) { container.innerHTML = `

Relatórios do Sistema PELL

Sistema em Modo Somente Leitura: Este sistema está conectado ao banco de dados de produção para visualização apenas.

Relatórios de Cartão de Ponto

Por Comessa

Filtrar por número da comessa

Por Nome

Filtrar por nome do funcionário

Por Nome e Data

Filtrar por funcionário e período

Por Data

Filtrar por período

Por Comessa e Data

Filtrar por comessa e período

Por Comessa e Funcionário

Filtrar por comessa e funcionário

Outros Relatórios

Cartão de Ponto

Relatório de horas por comessa

Lista de Comessas

Todas as comessas disponíveis

Funcionários

Lista de funcionários cadastrados

Estatísticas

Estatísticas gerais do sistema

Selecione um relatório acima para visualizar os dados.
`; } // Mostrar relatório de cartão de ponto async function mostrarRelatorioCartaoPonto() { const container = document.getElementById('conteudo-relatorio'); container.innerHTML = `
Relatório de Cartão de Ponto por Comessa

Selecione uma matrícula e clique em "Gerar Relatório"
`; // Carregar lista de comessas await carregarComessasSelect(); } // Carregar comessas no select async function carregarComessasSelect() { try { const response = await apiRequest(`${API_BASE}/relatorios/comessas`); const data = await response.json(); const select = document.getElementById('matriculaRelatorio'); if (data.status === 'success') { select.innerHTML = ''; data.data.forEach(comessa => { select.innerHTML += ``; }); } else { select.innerHTML = ''; } } catch (error) { document.getElementById('matriculaRelatorio').innerHTML = ''; } } // Gerar relatório de cartão de ponto async function gerarRelatorioCartaoPonto() { const matricula = document.getElementById('matriculaRelatorio').value; const dataInicio = document.getElementById('dataInicio').value; const dataFim = document.getElementById('dataFim').value; const container = document.getElementById('resultado-relatorio'); if (!matricula) { mostrarErro('Selecione uma matrícula para gerar o relatório'); return; } container.innerHTML = `
Gerando relatório...

Gerando relatório...

`; try { const params = new URLSearchParams(); if (dataInicio) params.append('dataInicio', dataInicio); if (dataFim) params.append('dataFim', dataFim); const response = await apiRequest(`${API_BASE}/relatorios/cartao-ponto/${matricula}?${params}`); const data = await response.json(); if (data.status === 'success') { exibirRelatorioCartaoPonto(data.dados); } else { throw new Error(data.message); } } catch (error) { container.innerHTML = `
Erro ao gerar relatório: ${error.message}
`; } } // Exibir relatório de cartão de ponto function exibirRelatorioCartaoPonto(dados) { const container = document.getElementById('resultado-relatorio'); if (dados.registros.length === 0) { container.innerHTML = `
Nenhum registro encontrado para a matrícula ${dados.matricula} no período de ${formatarData(dados.periodo.inicio)} a ${formatarData(dados.periodo.fim)}
`; return; } container.innerHTML = `
Comessa: ${dados.matricula}
Período: ${formatarData(dados.periodo.inicio)} a ${formatarData(dados.periodo.fim)}
Total: ${dados.totais.total_horas_formatado}
${dados.registros.map(registro => ` `).join('')}
Nome Data Matrícula Serviço Início Fim Especificar Total Minutos Total Horas
${registro.Nome || '-'} ${formatarData(registro.Data)} ${registro.Matricula} ${registro.Servico || '-'} ${registro.Inicio || '-'} ${registro.Fim || '-'} ${registro.Especificar || '-'} ${registro.total_minutos || 0} ${registro.total_horas || '-'}
TOTAL: ${dados.totais.total_minutos} ${dados.totais.total_horas_formatado}
`; } // Lista de comessas async function mostrarListaComessas() { const container = document.getElementById('conteudo-relatorio'); container.innerHTML = `
Lista de Comessas
Carregando...
`; try { const response = await apiRequest(`${API_BASE}/relatorios/comessas`); const data = await response.json(); if (data.status === 'success') { container.innerHTML = `
Lista de Comessas (${data.total})
${data.data.map(comessa => ` `).join('')}
Matrícula Total de Registros Primeira Data Última Data Ações
${comessa.Matricula} ${comessa.total_registros} ${formatarData(comessa.primeira_data)} ${formatarData(comessa.ultima_data)}
`; } else { throw new Error(data.message); } } catch (error) { container.innerHTML = `
Erro ao carregar comessas: ${error.message}
`; } } // Função para mostrar relatório por comessa async function mostrarRelatorioPorComessa() { const container = document.getElementById('conteudo-relatorio'); container.innerHTML = `
Relatório por Comessa
`; } async function gerarRelatorioPorComessa(event) { event.preventDefault(); const comessa = document.getElementById('comessa').value; const container = document.getElementById('resultado-relatorio'); try { container.innerHTML = '
'; const response = await apiRequest(`${API_BASE}/relatorios/por-comessa?comessa=${comessa}`); const data = await response.json(); if (data.status === 'success') { exibirRelatorioGenerico(data, container); } else { throw new Error(data.message); } } catch (error) { container.innerHTML = `
Erro: ${error.message}
`; } } // Função para mostrar relatório por nome async function mostrarRelatorioPorNome() { const container = document.getElementById('conteudo-relatorio'); container.innerHTML = `
Relatório por Nome
`; } async function gerarRelatorioPorNome(event) { event.preventDefault(); const nome = document.getElementById('nome').value; const container = document.getElementById('resultado-relatorio'); try { container.innerHTML = '
'; const response = await apiRequest(`${API_BASE}/relatorios/por-nome?nome=${encodeURIComponent(nome)}`); const data = await response.json(); if (data.status === 'success') { exibirRelatorioGenerico(data, container); } else { throw new Error(data.message); } } catch (error) { container.innerHTML = `
Erro: ${error.message}
`; } } // Função para mostrar relatório por nome e data async function mostrarRelatorioPorNomeData() { const hoje = new Date().toISOString().split('T')[0]; const semanaAtras = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]; const container = document.getElementById('conteudo-relatorio'); container.innerHTML = `
Relatório por Nome e Data
`; } async function gerarRelatorioPorNomeData(event) { event.preventDefault(); const nome = document.getElementById('nomeData').value; const dataInicio = document.getElementById('dataInicio').value; const dataFim = document.getElementById('dataFim').value; const container = document.getElementById('resultado-relatorio'); try { container.innerHTML = '
'; const params = new URLSearchParams({ nome: nome, dataInicio: dataInicio, dataFim: dataFim }); const response = await fetch(`${API_BASE}/relatorios/por-nome-data?${params}`); const data = await response.json(); if (data.status === 'success') { exibirRelatorioGenerico(data, container); } else { throw new Error(data.message); } } catch (error) { container.innerHTML = `
Erro: ${error.message}
`; } } // Função para mostrar relatório por data async function mostrarRelatorioPorData() { const hoje = new Date().toISOString().split('T')[0]; const semanaAtras = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]; const container = document.getElementById('conteudo-relatorio'); container.innerHTML = `
Relatório por Data
`; } async function gerarRelatorioPorData(event) { event.preventDefault(); const dataInicio = document.getElementById('dataInicioData').value; const dataFim = document.getElementById('dataFimData').value; const container = document.getElementById('resultado-relatorio'); try { container.innerHTML = '
'; const params = new URLSearchParams({ dataInicio: dataInicio, dataFim: dataFim }); const response = await fetch(`${API_BASE}/relatorios/por-data?${params}`); const data = await response.json(); if (data.status === 'success') { exibirRelatorioGenerico(data, container); } else { throw new Error(data.message); } } catch (error) { container.innerHTML = `
Erro: ${error.message}
`; } } // Função para mostrar relatório por comessa e data async function mostrarRelatorioPorComessaData() { const hoje = new Date().toISOString().split('T')[0]; const semanaAtras = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]; const container = document.getElementById('conteudo-relatorio'); container.innerHTML = `
Relatório por Comessa e Data
`; } async function gerarRelatorioPorComessaData(event) { event.preventDefault(); const comessa = document.getElementById('comessaData').value; const dataInicio = document.getElementById('dataInicioComessaData').value; const dataFim = document.getElementById('dataFimComessaData').value; const container = document.getElementById('resultado-relatorio'); try { container.innerHTML = '
'; const params = new URLSearchParams({ comessa: comessa, dataInicio: dataInicio, dataFim: dataFim }); const response = await fetch(`${API_BASE}/relatorios/por-comessa-data?${params}`); const data = await response.json(); if (data.status === 'success') { exibirRelatorioGenerico(data, container); } else { throw new Error(data.message); } } catch (error) { container.innerHTML = `
Erro: ${error.message}
`; } } // Função para mostrar relatório por comessa e funcionário async function mostrarRelatorioPorComessaFuncionario() { const container = document.getElementById('conteudo-relatorio'); container.innerHTML = `
Relatório por Comessa e Funcionário
`; } async function gerarRelatorioPorComessaFuncionario(event) { event.preventDefault(); const comessa = document.getElementById('comessaFunc').value; const nome = document.getElementById('nomeFunc').value; const container = document.getElementById('resultado-relatorio'); try { container.innerHTML = '
'; const params = new URLSearchParams({ comessa: comessa, nome: nome }); const response = await fetch(`${API_BASE}/relatorios/por-comessa-funcionario?${params}`); const data = await response.json(); if (data.status === 'success') { exibirRelatorioGenerico(data, container); } else { throw new Error(data.message); } } catch (error) { container.innerHTML = `
Erro: ${error.message}
`; } } // Função genérica para exibir relatórios function exibirRelatorioGenerico(data, container) { if (!data.registros || data.registros.length === 0) { container.innerHTML = `
Nenhum registro encontrado para os filtros informados.
`; return; } let totalMinutos = 0; data.registros.forEach(registro => { if (registro.total_minutos) { totalMinutos += registro.total_minutos; } }); const totalHoras = Math.floor(totalMinutos / 60); const totalMinutosRestantes = totalMinutos % 60; const totalFormatado = `${totalHoras}:${totalMinutosRestantes.toString().padStart(2, '0')}`; container.innerHTML = `
${data.relatorio}
${data.total} registros
Total de Horas Trabalhadas: ${totalFormatado}
${data.registros.map(registro => ` `).join('')}
Nome Data Matrícula Serviço Início Fim Horas
${registro.Nome || '-'} ${new Date(registro.Data).toLocaleDateString('pt-BR')} ${registro.Matricula || '-'} ${registro.Servico || '-'} ${registro.Inicio || '-'} ${registro.Fim || '-'} ${registro.total_horas || '0:00'}
`; } // Funcionários placeholder async function mostrarRelatorioFuncionarios() { const container = document.getElementById('conteudo-relatorio'); container.innerHTML = `
Relatório de Funcionários
Relatório de funcionários em desenvolvimento.
`; } // Estatísticas placeholder async function mostrarEstatisticas() { const container = document.getElementById('conteudo-relatorio'); container.innerHTML = `
Estatísticas Gerais
Estatísticas gerais em desenvolvimento.
`; } // Gerar relatório rápido function gerarRelatorioRapido(matricula) { // Mudar para aba de cartão de ponto e preencher automaticamente mostrarRelatorioCartaoPonto().then(() => { document.getElementById('matriculaRelatorio').value = matricula; gerarRelatorioCartaoPonto(); }); } // Funções de exportação e impressão (placeholder) function exportarRelatorio(matricula) { mostrarSucesso('Funcionalidade de exportação em desenvolvimento'); } function imprimirRelatorio() { window.print(); } // Utilitários function formatarData(data) { if (!data) return '-'; try { return new Date(data).toLocaleDateString('pt-BR'); } catch (error) { return '-'; } } function mostrarErro(mensagem) { const alert = document.createElement('div'); alert.className = 'alert alert-danger alert-dismissible fade show'; alert.innerHTML = ` ${mensagem} `; document.body.insertBefore(alert, document.body.firstChild); setTimeout(() => { alert.remove(); }, 5000); } function mostrarSucesso(mensagem) { const alert = document.createElement('div'); alert.className = 'alert alert-success alert-dismissible fade show'; alert.innerHTML = ` ${mensagem} `; document.body.insertBefore(alert, document.body.firstChild); setTimeout(() => { alert.remove(); }, 3000); } // WhatsApp - Sistema de Notificações async function carregarWhatsApp(container) { container.innerHTML = `

Sistema de Notificações WhatsApp

Sistema para envio automático de notificações sobre mudanças no workflow de produção.
Status da Conexão
Verificando...
Contatos Cadastrados
-
Estatísticas
-

Ações do Sistema

Inicializar WhatsApp
Teste de Mensagem
Teste Workflow
Logs de Envio
Selecione uma ação acima para começar.
`; // Carregar status inicial await verificarStatusWhatsApp(); await carregarEstatisticas(); } async function verificarStatusWhatsApp() { try { const response = await apiRequest(`${API_BASE}/whatsapp/status`); const data = await response.json(); const statusDiv = document.getElementById('status-whatsapp'); if (data.whatsapp.conectado) { statusDiv.innerHTML = '✅ Conectado'; } else if (data.whatsapp.inicializando) { statusDiv.innerHTML = '🔄 Inicializando...'; } else { statusDiv.innerHTML = '❌ Desconectado'; } } catch (error) { document.getElementById('status-whatsapp').innerHTML = '❌ Erro'; } } async function carregarEstatisticas() { try { const response = await apiRequest(`${API_BASE}/whatsapp/estatisticas`); const data = await response.json(); if (data.status === 'success') { const stats = data.estatisticas; document.getElementById('total-contatos').innerHTML = `${stats.contatos_ativos}/${stats.total_contatos}`; document.getElementById('estatisticas-whatsapp').innerHTML = `Hoje: ${stats.enviados_hoje} ✅ ${stats.erros_hoje} ❌`; } } catch (error) { console.error('Erro ao carregar estatísticas:', error); } } async function inicializarWhatsApp() { try { const response = await apiRequest(`${API_BASE}/whatsapp/inicializar`, { method: 'POST', headers: { 'Content-Type': 'application/json' } }); const data = await response.json(); alert(data.message); if (data.status === 'success') { document.getElementById('conteudo-whatsapp').innerHTML = `
QR Code para Conexão

Verifique o console do servidor para ver o QR Code e escaneie com seu WhatsApp.

Importante: O QR Code aparece no terminal onde o servidor está rodando.

`; } setTimeout(verificarStatusWhatsApp, 2000); } catch (error) { alert('Erro ao inicializar WhatsApp: ' + error.message); } } async function mostrarTesteMessage() { document.getElementById('conteudo-whatsapp').innerHTML = `
Teste de Mensagem
`; } async function enviarMensagemTeste(event) { event.preventDefault(); const telefone = document.getElementById('telefone-teste').value; const mensagem = document.getElementById('mensagem-teste').value; const container = document.getElementById('resultado-teste'); try { container.innerHTML = '
'; const response = await apiRequest(`${API_BASE}/whatsapp/teste`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ telefone, mensagem }) }); const data = await response.json(); container.innerHTML = `
${data.message}
`; } catch (error) { container.innerHTML = `
Erro: ${error.message}
`; } } async function testarNotificacaoWorkflow() { try { const response = await apiRequest(`${API_BASE}/whatsapp/teste-workflow`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({}) }); const data = await response.json(); alert(data.message); if (data.status === 'success') { setTimeout(carregarEstatisticas, 2000); } } catch (error) { alert('Erro ao testar notificação: ' + error.message); } } async function listarContatos() { try { const response = await fetch(`${API_BASE}/whatsapp/contatos`); const data = await response.json(); if (data.status === 'success') { let html = `
Contatos Cadastrados (${data.total})
`; data.contatos.forEach(contato => { const statusBadge = contato.ativo ? 'success' : 'danger'; const statusText = contato.ativo ? 'Ativo' : 'Inativo'; const toggleText = contato.ativo ? 'Desativar' : 'Ativar'; const toggleIcon = contato.ativo ? 'pause' : 'play'; const toggleClass = contato.ativo ? 'warning' : 'success'; html += ` `; }); if (data.contatos.length === 0) { html += ` `; } html += `
Nome Telefone Tipo Status Cadastro Ações
${contato.nome} ${contato.telefone} ${contato.tipo_notificacao} ${statusText} ${new Date(contato.data_cadastro).toLocaleDateString('pt-BR')}

Nenhum contato cadastrado
`; document.getElementById('conteudo-whatsapp').innerHTML = html; } } catch (error) { document.getElementById('conteudo-whatsapp').innerHTML = `
Erro: ${error.message}
`; } } async function mostrarLogs() { try { const response = await fetch(`${API_BASE}/whatsapp/logs?limite=20`); const data = await response.json(); if (data.status === 'success') { let html = `
Logs de Envio (últimos 20)
`; data.logs.forEach(log => { html += ` `; }); html += `
Data/Hora Telefone Mensagem Status
${new Date(log.data_envio).toLocaleString('pt-BR')} ${log.telefone} ${log.mensagem.substring(0, 50)}... ${log.status}
`; document.getElementById('conteudo-whatsapp').innerHTML = html; } } catch (error) { document.getElementById('conteudo-whatsapp').innerHTML = `
Erro: ${error.message}
`; } }