| |
| |
| |
|
|
| |
| let appData = { |
| processos: [ |
| { id: '2023-0456', cliente: 'João Silva', tribunal: 'TJSP', data: '2023-03-15', status: 'Ativo', prazo: '2024-01-15', descricao: 'Ação indenizatória' }, |
| { id: '2023-0389', cliente: 'Maria Souza', tribunal: 'TRF4', data: '2023-02-20', status: 'Pendente', prazo: '2024-01-18', descricao: 'Mandado de segurança' }, |
| { id: '2023-0412', cliente: 'Empresa XYZ Ltda', tribunal: 'TJMG', data: '2023-04-10', status: 'Urgente', prazo: '2024-01-20', descricao: 'Execução fiscal' }, |
| { id: '2023-0501', cliente: 'Ana Oliveira', tribunal: 'TJSP', data: '2023-05-05', status: 'Ativo', prazo: '2024-02-10', descricao: 'Ação de cobrança' }, |
| { id: '2023-0534', cliente: 'Carlos Mendes', tribunal: 'TRF1', data: '2023-06-12', status: 'Concluído', prazo: null, descricao: 'Habeas corpus' }, |
| { id: '2023-0601', cliente: 'Tech Solutions SA', tribunal: 'TJSP', data: '2023-07-01', status: 'Ativo', prazo: '2024-03-01', descricao: 'Contrato comercial' }, |
| { id: '2023-0645', cliente: 'Fernanda Lima', tribunal: 'TJMG', data: '2023-08-15', status: 'Pendente', prazo: '2024-03-20', descricao: 'Inventário' }, |
| { id: '2023-0702', cliente: 'Roberto Santos', tribunal: 'TRF4', data: '2023-09-03', status: 'Ativo', prazo: '2024-04-05', descricao: 'Recurso de apelação' }, |
| ], |
| clientes: [ |
| { id: 1, nome: 'João Silva', tipo: 'pf', cpfCnpj: '123.456.789-00', email: 'joao@email.com', telefone: '(11) 98765-4321', endereco: 'Rua A, 100, São Paulo-SP', processos: 2 }, |
| { id: 2, nome: 'Maria Souza', tipo: 'pf', cpfCnpj: '987.654.321-00', email: 'maria@email.com', telefone: '(21) 99876-5432', endereco: 'Av B, 200, Rio de Janeiro-RJ', processos: 1 }, |
| { id: 3, nome: 'Empresa XYZ Ltda', tipo: 'pj', cpfCnpj: '12.345.678/0001-90', email: 'contato@xyz.com', telefone: '(11) 3456-7890', endereco: 'Rua C, 300, São Paulo-SP', processos: 3 }, |
| { id: 4, nome: 'Ana Oliveira', tipo: 'pf', cpfCnpj: '456.789.123-00', email: 'ana@email.com', telefone: '(31) 97654-3210', endereco: 'Rua D, 400, Belo Horizonte-MG', processos: 1 }, |
| { id: 5, nome: 'Carlos Mendes', tipo: 'pf', cpfCnpj: '789.123.456-00', email: 'carlos@email.com', telefone: '(61) 96543-2109', endereco: 'SQN 5, Bloco E, Brasília-DF', processos: 1 }, |
| { id: 6, nome: 'Tech Solutions SA', tipo: 'pj', cpfCnpj: '98.765.432/0001-10', email: 'juridico@techsol.com', telefone: '(11) 4567-8901', endereco: 'Av F, 600, São Paulo-SP', processos: 2 }, |
| { id: 7, nome: 'Fernanda Lima', tipo: 'pf', cpfCnpj: '321.654.987-00', email: 'fernanda@email.com', telefone: '(31) 95432-1098', endereco: 'Rua G, 700, Belo Horizonte-MG', processos: 1 }, |
| { id: 8, nome: 'Roberto Santos', tipo: 'pf', cpfCnpj: '654.987.321-00', email: 'roberto@email.com', telefone: '(51) 94321-0987', endereco: 'Rua H, 800, Porto Alegre-RS', processos: 1 }, |
| ], |
| evidencias: [], |
| intimacoes: [], |
| aaspConfig: { chave: '92E81C018B69454F8053133023AC438B' }, |
| googleAuth: null, |
| driveConnected: false, |
| sheetsConnected: false, |
| importPreview: null, |
| }; |
|
|
| |
| function loadAppData() { |
| const saved = localStorage.getItem('legaldata_app'); |
| if (saved) { |
| try { |
| const parsed = JSON.parse(saved); |
| appData = { ...appData, ...parsed }; |
| } catch(e) { console.error('Error loading data', e); } |
| } |
| } |
|
|
| function saveAppData() { |
| localStorage.setItem('legaldata_app', JSON.stringify(appData)); |
| } |
|
|
| |
| function showTab(tabId, navEl) { |
| document.querySelectorAll('.tab-content').forEach(t => t.classList.remove('active')); |
| document.querySelectorAll('.nav-link').forEach(n => n.classList.remove('active-nav')); |
| |
| const tab = document.getElementById(tabId); |
| if (tab) tab.classList.add('active'); |
| |
| if (navEl) { |
| navEl.classList.add('active-nav'); |
| } else { |
| document.querySelectorAll('.nav-link').forEach(n => { |
| if (n.getAttribute('onclick') && n.getAttribute('onclick').includes(tabId)) { |
| n.classList.add('active-nav'); |
| } |
| }); |
| } |
|
|
| const titles = { |
| dashboard: 'Dashboard', processos: 'Gestão de Processos', clientes: 'Gestão de Clientes', |
| provas: 'Galeria de Provas', intimacoes: 'Intimações AASP', import: 'Importar Dados', |
| config: 'Configurações', sanitize: 'Sanitização de Dados', integrations: 'Integrações' |
| }; |
| document.getElementById('current-tab-title').textContent = titles[tabId] || tabId; |
|
|
| if (tabId === 'provas') renderEvidence(); |
| if (tabId === 'processos') renderProcessos(); |
| if (tabId === 'clientes') renderClientes(); |
| } |
|
|
| function toggleSidebar() { |
| document.getElementById('sidebar').classList.toggle('collapsed'); |
| } |
|
|
| |
| function showModal(id) { |
| const modal = document.getElementById('modal-' + id); |
| if (modal) modal.classList.remove('hidden'); |
| } |
|
|
| function hideModal(id) { |
| const modal = document.getElementById('modal-' + id); |
| if (modal) modal.classList.add('hidden'); |
| } |
|
|
| |
| function showToast(message, type = 'success') { |
| const container = document.getElementById('toast-container'); |
| const colors = { success: 'bg-green-500', error: 'bg-red-500', info: 'bg-blue-500', warning: 'bg-yellow-500' }; |
| const icons = { success: 'fa-check-circle', error: 'fa-times-circle', info: 'fa-info-circle', warning: 'fa-exclamation-triangle' }; |
| |
| const toast = document.createElement('div'); |
| toast.className = `toast ${colors[type]} text-white px-4 py-3 rounded-lg shadow-lg flex items-center space-x-3 min-w-72`; |
| toast.innerHTML = `<i class="fas ${icons[type]}"></i><span>${message}</span>`; |
| container.appendChild(toast); |
| |
| requestAnimationFrame(() => toast.classList.add('show')); |
| setTimeout(() => { |
| toast.classList.remove('show'); |
| setTimeout(() => toast.remove(), 400); |
| }, 4000); |
| } |
|
|
| |
| function renderProcessos() { |
| const tbody = document.getElementById('processos-table-body'); |
| if (!tbody) return; |
| |
| const statusColors = { |
| 'Ativo': 'bg-green-100 text-green-800', |
| 'Pendente': 'bg-yellow-100 text-yellow-800', |
| 'Urgente': 'bg-red-100 text-red-800', |
| 'Concluído': 'bg-blue-100 text-blue-800', |
| 'Arquivado': 'bg-gray-100 text-gray-800' |
| }; |
|
|
| tbody.innerHTML = appData.processos.map(p => ` |
| <tr class="hover:bg-gray-50"> |
| <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">#${p.id}</td> |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${p.cliente}</td> |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${p.tribunal}</td> |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${formatDate(p.data)}</td> |
| <td class="px-6 py-4 whitespace-nowrap"><span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${statusColors[p.status] || 'bg-gray-100 text-gray-800'}">${p.status}</span></td> |
| <td class="px-6 py-4 whitespace-nowrap text-sm"> |
| <button class="text-indigo-600 hover:text-indigo-900 mr-3" title="Ver"><i class="fas fa-eye"></i></button> |
| <button class="text-green-600 hover:text-green-900 mr-3" title="Editar"><i class="fas fa-edit"></i></button> |
| <button class="text-red-600 hover:text-red-900" onclick="deleteProcess('${p.id}')" title="Excluir"><i class="fas fa-trash"></i></button> |
| </td> |
| </tr> |
| `).join(''); |
| } |
|
|
| function addProcess() { |
| const proc = { |
| id: document.getElementById('proc-numero').value || generateId(), |
| cliente: document.getElementById('proc-cliente').value, |
| tribunal: document.getElementById('proc-tribunal').value, |
| data: document.getElementById('proc-data').value, |
| status: document.getElementById('proc-status').value, |
| prazo: null, |
| descricao: document.getElementById('proc-descricao').value |
| }; |
| appData.processos.push(proc); |
| saveAppData(); |
| renderProcessos(); |
| hideModal('new-process'); |
| showToast('Processo adicionado com sucesso!'); |
| updateStats(); |
| } |
|
|
| function deleteProcess(id) { |
| if (confirm('Deseja excluir este processo?')) { |
| appData.processos = appData.processos.filter(p => p.id !== id); |
| saveAppData(); |
| renderProcessos(); |
| showToast('Processo excluído', 'info'); |
| updateStats(); |
| } |
| } |
|
|
| |
| function renderClientes() { |
| const tbody = document.getElementById('clientes-table-body'); |
| if (!tbody) return; |
| |
| tbody.innerHTML = appData.clientes.map(c => ` |
| <tr class="hover:bg-gray-50"> |
| <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${c.nome}</td> |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${c.cpfCnpj}</td> |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${c.email}</td> |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${c.telefone}</td> |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${c.processos}</td> |
| <td class="px-6 py-4 whitespace-nowrap text-sm"> |
| <button class="text-indigo-600 hover:text-indigo-900 mr-3" title="Ver"><i class="fas fa-eye"></i></button> |
| <button class="text-green-600 hover:text-green-900 mr-3" title="Editar"><i class="fas fa-edit"></i></button> |
| <button class="text-red-600 hover:text-red-900" onclick="deleteClient(${c.id})" title="Excluir"><i class="fas fa-trash"></i></button> |
| </td> |
| </tr> |
| `).join(''); |
| } |
|
|
| function addClient() { |
| const cli = { |
| id: Date.now(), |
| nome: document.getElementById('cli-nome').value, |
| tipo: document.getElementById('cli-tipo').value, |
| cpfCnpj: document.getElementById('cli-cpfcnpj').value, |
| email: document.getElementById('cli-email').value, |
| telefone: document.getElementById('cli-telefone').value, |
| endereco: document.getElementById('cli-endereco').value, |
| processos: 0 |
| }; |
| appData.clientes.push(cli); |
| saveAppData(); |
| renderClientes(); |
| hideModal('new-client'); |
| showToast('Cliente adicionado com sucesso!'); |
| updateStats(); |
| populateSelects(); |
| } |
|
|
| function deleteClient(id) { |
| if (confirm('Deseja excluir este cliente?')) { |
| appData.clientes = appData.clientes.filter(c => c.id !== id); |
| saveAppData(); |
| renderClientes(); |
| showToast('Cliente excluído', 'info'); |
| updateStats(); |
| } |
| } |
|
|
| |
| let selectedEvidenceFiles = []; |
| let currentEvidenceIndex = 0; |
|
|
| function renderEvidence() { |
| const grid = document.getElementById('evidence-grid'); |
| const noEv = document.getElementById('no-evidence'); |
| if (!grid) return; |
|
|
| const filterClient = document.getElementById('evidence-filter-client')?.value || ''; |
| const filterType = document.getElementById('evidence-filter-type')?.value || ''; |
|
|
| let filtered = appData.evidencias; |
| if (filterClient) filtered = filtered.filter(e => e.clienteId == filterClient); |
| if (filterType) filtered = filtered.filter(e => e.categoria.toLowerCase().includes(filterType)); |
|
|
| if (filtered.length === 0) { |
| grid.innerHTML = ''; |
| noEv?.classList.remove('hidden'); |
| return; |
| } |
| noEv?.classList.add('hidden'); |
|
|
| grid.innerHTML = filtered.map((ev, i) => { |
| const icon = getFileIcon(ev.tipo); |
| const thumb = ev.thumb || `http://static.photos/${ev.categoria === 'foto' ? 'people' : 'office'}/320x240/${ev.id}`; |
| return ` |
| <div class="evidence-card bg-white rounded-xl shadow overflow-hidden cursor-pointer transition" onclick="viewEvidence(${ev.id})"> |
| <div class="h-40 bg-gray-100 flex items-center justify-center overflow-hidden"> |
| ${ev.tipo && ev.tipo.startsWith('image/') ? |
| `<img src="${thumb}" class="w-full h-full object-cover" alt="${ev.descricao}">` : |
| `<i class="${icon} text-5xl text-gray-300"></i>`} |
| </div> |
| <div class="p-3"> |
| <p class="font-medium text-sm truncate">${ev.descricao || 'Sem descrição'}</p> |
| <p class="text-xs text-gray-500 mt-1">${ev.clienteNome || 'N/A'} • ${formatDate(ev.data)}</p> |
| <div class="flex items-center justify-between mt-2"> |
| <span class="text-xs px-2 py-1 rounded-full bg-indigo-100 text-indigo-700">${ev.categoria}</span> |
| ${ev.driveId ? '<i class="fab fa-google-drive text-blue-500 text-xs" title="No Google Drive"></i>' : ''} |
| </div> |
| </div> |
| </div>`; |
| }).join(''); |
|
|
| document.getElementById('stat-provas').textContent = appData.evidencias.length; |
| } |
|
|
| function getFileIcon(tipo) { |
| if (!tipo) return 'fas fa-file'; |
| if (tipo.startsWith('image/')) return 'fas fa-file-image'; |
| if (tipo === 'application/pdf') return 'fas fa-file-pdf'; |
| if (tipo.startsWith('video/')) return 'fas fa-file-video'; |
| if (tipo.startsWith('audio/')) return 'fas fa-file-audio'; |
| return 'fas fa-file'; |
| } |
|
|
| function handleEvidenceDrop(event) { |
| const files = event.dataTransfer.files; |
| processEvidenceFiles(files); |
| } |
|
|
| function handleEvidenceSelect(event) { |
| const files = event.target.files; |
| processEvidenceFiles(files); |
| } |
|
|
| function processEvidenceFiles(files) { |
| selectedEvidenceFiles = Array.from(files); |
| const preview = document.getElementById('ev-preview'); |
| preview.innerHTML = ''; |
| preview.classList.remove('hidden'); |
|
|
| selectedEvidenceFiles.forEach((file, i) => { |
| if (file.type.startsWith('image/')) { |
| const reader = new FileReader(); |
| reader.onload = (e) => { |
| preview.innerHTML += `<div class="relative"><img src="${e.target.result}" class="w-full h-20 object-cover rounded"><span class="absolute top-1 right-1 bg-black bg-opacity-50 text-white text-xs px-1 rounded">${file.name.length > 15 ? file.name.substring(0,12)+'...' : file.name}</span></div>`; |
| }; |
| reader.readAsDataURL(file); |
| } else { |
| preview.innerHTML += `<div class="bg-gray-100 rounded p-2 text-center"><i class="${getFileIcon(file.type)} text-2xl text-gray-400"></i><p class="text-xs text-gray-500 mt-1 truncate">${file.name}</p></div>`; |
| } |
| }); |
| } |
|
|
| function uploadEvidence() { |
| const clienteId = document.getElementById('ev-cliente').value; |
| const cliente = appData.clientes.find(c => c.id == clienteId); |
| const processo = document.getElementById('ev-processo').value; |
| const categoria = document.getElementById('ev-categoria').value; |
| const descricao = document.getElementById('ev-descricao').value; |
| const uploadToDrive = document.getElementById('ev-upload-drive').checked; |
|
|
| if (!clienteId) { showToast('Selecione um cliente', 'error'); return; } |
| if (selectedEvidenceFiles.length === 0) { showToast('Selecione ao menos um arquivo', 'error'); return; } |
|
|
| selectedEvidenceFiles.forEach((file, i) => { |
| const evId = Date.now() + i; |
| const evidencia = { |
| id: evId, |
| clienteId: parseInt(clienteId), |
| clienteNome: cliente?.nome || 'N/A', |
| processoId: processo, |
| categoria: categoria, |
| descricao: descricao || file.name, |
| tipo: file.type, |
| nomeArquivo: file.name, |
| data: new Date().toISOString(), |
| thumb: null, |
| driveId: null, |
| localData: null |
| }; |
|
|
| |
| if (file.type.startsWith('image/')) { |
| const reader = new FileReader(); |
| reader.onload = (e) => { |
| evidencia.thumb = e.target.result; |
| evidencia.localData = e.target.result; |
| appData.evidencias.push(evidencia); |
| saveAppData(); |
| renderEvidence(); |
| }; |
| reader.readAsDataURL(file); |
| } else { |
| |
| const reader = new FileReader(); |
| reader.onload = (e) => { |
| evidencia.localData = e.target.result; |
| appData.evidencias.push(evidencia); |
| saveAppData(); |
| renderEvidence(); |
| }; |
| reader.readAsDataURL(file); |
| } |
|
|
| |
| if (uploadToDrive && appData.driveConnected) { |
| uploadToGoogleDrive(file, evId); |
| } |
| }); |
|
|
| selectedEvidenceFiles = []; |
| document.getElementById('ev-preview').innerHTML = ''; |
| document.getElementById('ev-preview').classList.add('hidden'); |
| hideModal('upload-evidence'); |
| showToast('Prova(s) enviada(s) com sucesso!'); |
| updateStats(); |
| } |
|
|
| function viewEvidence(id) { |
| const ev = appData.evidencias.find(e => e.id === id); |
| if (!ev) return; |
|
|
| currentEvidenceIndex = appData.evidencias.findIndex(e => e.id === id); |
|
|
| const content = document.getElementById('lightbox-content'); |
| const caption = document.getElementById('lightbox-caption'); |
|
|
| if (ev.tipo && ev.tipo.startsWith('image/') && ev.localData) { |
| content.innerHTML = `<img src="${ev.localData}" class="max-w-full max-h-[70vh] object-contain rounded">`; |
| } else if (ev.tipo === 'application/pdf' && ev.localData) { |
| content.innerHTML = `<iframe src="${ev.localData}" class="w-full h-[70vh] rounded" frameborder="0"></iframe>`; |
| } else if (ev.tipo && ev.tipo.startsWith('video/') && ev.localData) { |
| content.innerHTML = `<video src="${ev.localData}" controls class="max-w-full max-h-[70vh] rounded"></video>`; |
| } else if (ev.tipo && ev.tipo.startsWith('audio/') && ev.localData) { |
| content.innerHTML = `<div class="text-center"><i class="fas fa-music text-6xl text-white mb-6"></i><audio src="${ev.localData}" controls class="w-96"></audio></div>`; |
| } else { |
| content.innerHTML = `<div class="text-center"><i class="${getFileIcon(ev.tipo)} text-8xl text-white mb-4"></i><p class="text-white text-xl">${ev.nomeArquivo || 'Arquivo'}</p><p class="text-gray-400">Pré-visualização não disponível</p></div>`; |
| } |
|
|
| caption.textContent = `${ev.descricao} — ${ev.clienteNome} — ${formatDate(ev.data)}`; |
| document.getElementById('lightbox').classList.add('active'); |
| } |
|
|
| function closeLightbox() { |
| document.getElementById('lightbox').classList.remove('active'); |
| } |
|
|
| function navigateEvidence(direction) { |
| currentEvidenceIndex += direction; |
| if (currentEvidenceIndex < 0) currentEvidenceIndex = appData.evidencias.length - 1; |
| if (currentEvidenceIndex >= appData.evidencias.length) currentEvidenceIndex = 0; |
| const ev = appData.evidencias[currentEvidenceIndex]; |
| if (ev) viewEvidence(ev.id); |
| } |
|
|
| function filterEvidence() { |
| renderEvidence(); |
| } |
|
|
| |
| const AASP_BASE_URL = 'https://api.aasp.org.br'; |
|
|
| async function fetchAASPIntimacoes() { |
| const chave = document.getElementById('aasp-chave').value; |
| const tipo = document.getElementById('aasp-tipo').value; |
| const data = document.getElementById('aasp-data').value; |
| const diferencial = document.getElementById('aasp-diferencial').checked; |
| const codigo = document.getElementById('aasp-codigo').value; |
| const btn = document.getElementById('btn-fetch-aasp'); |
|
|
| if (!chave) { showToast('Informe a chave de acesso AASP', 'error'); return; } |
|
|
| btn.disabled = true; |
| btn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> Buscando...'; |
|
|
| try { |
| const endpoint = tipo === 'empresa' ? 'Empresa' : 'Associado'; |
| let url = `${AASP_BASE_URL}/api/${endpoint}/intimacao/json?chave=${encodeURIComponent(chave)}`; |
| if (data) url += `&data=${encodeURIComponent(data)}`; |
| if (diferencial) url += `&diferencial=true`; |
| if (tipo === 'empresa' && codigo) url += `&codigoPessoaAssociado=${codigo}`; |
|
|
| const response = await fetch(url); |
| if (!response.ok) throw new Error(`Erro HTTP: ${response.status}`); |
|
|
| const result = await response.json(); |
| appData.intimacoes = Array.isArray(result) ? result : [result]; |
| |
| renderIntimacoes(); |
| document.getElementById('stat-intimacoes').textContent = appData.intimacoes.length; |
| updateNotificationBadge(); |
| showToast(`${appData.intimacoes.length} intimação(ões) encontrada(s)!`); |
| saveAppData(); |
|
|
| } catch (error) { |
| console.error('AASP API Error:', error); |
| |
| showAASPMockData(); |
| showToast('Usando dados de demonstração (API pode requerer CORS proxy)', 'warning'); |
| } finally { |
| btn.disabled = false; |
| btn.innerHTML = '<i class="fas fa-sync-alt mr-2"></i> Buscar Intimações'; |
| } |
| } |
|
|
| function showAASPMockData() { |
| appData.intimacoes = [ |
| { id: 1, dataDisponibilizacao: '2024-01-10', dataPublicacao: '2024-01-09', jornal: 'DJE - TJSP', orgao: 'TJSP', vara: '5ª Vara Cível', numeroProcesso: '2023-0456', nomeParte: 'João Silva', tipoIntimacao: 'Sentença', conteudo: 'Intimação da parte ré para ciência da sentença proferida nos autos...', advogado: 'Dr. Ricardo Mendes', OAB: 'OAB/SP 123.456' }, |
| { id: 2, dataDisponibilizacao: '2024-01-10', dataPublicacao: '2024-01-09', jornal: 'DJE - TRF3', orgao: 'TRF3', vara: '2ª Vara Federal', numeroProcesso: '2023-0389', nomeParte: 'Maria Souza', tipoIntimacao: 'Despacho', conteudo: 'Intimação para manifestação sobre despacho que deferiu liminarmente a tutela de urgência...', advogado: 'Dra. Ana Paula Torres', OAB: 'OAB/SP 234.567' }, |
| { id: 3, dataDisponibilizacao: '2024-01-11', dataPublicacao: '2024-01-10', jornal: 'DJE - TJMG', orgao: 'TJMG', vara: '1ª Vara de Fazenda Pública', numeroProcesso: '2023-0412', nomeParte: 'Empresa XYZ Ltda', tipoIntimacao: 'Decisão', conteudo: 'Intimação da requerida para, querendo, apresentar impugnação ao cumprimento de sentença...', advogado: 'Dr. Paulo Santos', OAB: 'OAB/MG 56.789' }, |
| { id: 4, dataDisponibilizacao: '2024-01-12', dataPublicacao: '2024-01-11', jornal: 'DJE - TJSP', orgao: 'TJSP', vara: '15ª Vara Cível', numeroProcesso: '2023-0501', nomeParte: 'Ana Oliveira', tipoIntimacao: 'Audiência', conteudo: 'Intimação para audiência de conciliação designada para o dia 25/01/2024 às 14:00...', advogado: 'Dra. Carolina Lima', OAB: 'OAB/SP 345.678' }, |
| ]; |
| renderIntimacoes(); |
| document.getElementById('stat-intimacoes').textContent = appData.intimacoes.length; |
| updateNotificationBadge(); |
| saveAppData(); |
| } |
|
|
| function renderIntimacoes() { |
| const list = document.getElementById('intimacoes-list'); |
| const count = document.getElementById('intimacoes-count'); |
| |
| count.textContent = `${appData.intimacoes.length} resultado(s)`; |
|
|
| if (appData.intimacoes.length === 0) { |
| list.innerHTML = '<div class="text-center py-8 text-gray-400"><i class="fas fa-gavel text-4xl mb-3"></i><p>Nenhuma intimação encontrada</p></div>'; |
| return; |
| } |
|
|
| list.innerHTML = appData.intimacoes.map((int, i) => { |
| const statusColor = int.tipoIntimacao === 'Sentença' ? 'bg-red-100 text-red-800' : |
| int.tipoIntimacao === 'Audiência' ? 'bg-yellow-100 text-yellow-800' : |
| 'bg-blue-100 text-blue-800'; |
| return ` |
| <div class="border border-gray-200 rounded-lg p-4 mb-3 hover:bg-gray-50 transition"> |
| <div class="flex flex-wrap items-start justify-between gap-3 mb-2"> |
| <div class="flex items-center space-x-3"> |
| <span class="w-8 h-8 rounded-full bg-indigo-100 text-indigo-600 flex items-center justify-center text-sm font-bold">${i + 1}</span> |
| <div> |
| <p class="font-semibold">${int.numeroProcesso || 'N/A'} - ${int.nomeParte || 'N/A'}</p> |
| <p class="text-sm text-gray-500">${int.orgao || ''} • ${int.vara || ''}</p> |
| </div> |
| </div> |
| <div class="flex items-center space-x-2"> |
| <span class="px-2 py-1 text-xs font-semibold rounded-full ${statusColor}">${int.tipoIntimacao || 'N/A'}</span> |
| <span class="text-sm text-gray-500">${formatDate(int.dataDisponibilizacao)}</span> |
| </div> |
| </div> |
| <div class="bg-gray-50 rounded p-3 mb-2"> |
| <p class="text-sm text-gray-700">${(int.conteudo || '').substring(0, 200)}${(int.conteudo || '').length > 200 ? '...' : ''}</p> |
| </div> |
| <div class="flex items-center justify-between"> |
| <div class="text-xs text-gray-400"> |
| <span class="mr-3"><i class="fas fa-newspaper mr-1"></i>${int.jornal || 'N/A'}</span> |
| <span class="mr-3"><i class="fas fa-calendar mr-1"></i>Publicação: ${formatDate(int.dataPublicacao)}</span> |
| ${int.advogado ? `<span><i class="fas fa-user-tie mr-1"></i>${int.advogado}</span>` : ''} |
| </div> |
| <div class="flex space-x-2"> |
| <button class="text-sm text-indigo-600 hover:text-indigo-800" onclick="linkIntimacaoToProcess(${int.id})"><i class="fas fa-link mr-1"></i>Vincular</button> |
| <button class="text-sm text-green-600 hover:text-green-800"><i class="fas fa-check mr-1"></i>Marcar Lida</button> |
| </div> |
| </div> |
| </div>`; |
| }).join(''); |
| } |
|
|
| async function fetchAASPJornais() { |
| const chave = document.getElementById('aasp-chave').value; |
| const tipo = document.getElementById('aasp-tipo').value; |
| |
| if (!chave) { showToast('Informe a chave AASP', 'error'); return; } |
|
|
| try { |
| const endpoint = tipo === 'empresa' ? 'Empresa' : 'Associado'; |
| const url = `${AASP_BASE_URL}/api/${endpoint}/intimacao/GetJornaisComIntimacoes/json?chave=${encodeURIComponent(chave)}&qtdeDias=30`; |
| |
| const response = await fetch(url); |
| const result = await response.json(); |
| renderJornais(Array.isArray(result) ? result : [result]); |
| } catch(e) { |
| |
| renderJornais([ |
| { jornal: 'DJE - TJSP', quantidade: 12, dataUltima: '2024-01-12' }, |
| { jornal: 'DJE - TRF3', quantidade: 5, dataUltima: '2024-01-11' }, |
| { jornal: 'DJE - TJMG', quantidade: 3, dataUltima: '2024-01-10' }, |
| ]); |
| showToast('Usando dados de demonstração para jornais', 'warning'); |
| } |
| } |
|
|
| function renderJornais(jornais) { |
| const container = document.getElementById('jornais-results'); |
| const list = document.getElementById('jornais-list'); |
| container.classList.remove('hidden'); |
|
|
| list.innerHTML = jornais.map(j => ` |
| <div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg mb-2"> |
| <div class="flex items-center space-x-3"> |
| <i class="fas fa-newspaper text-indigo-600"></i> |
| <div> |
| <p class="font-medium">${j.jornal || j.NomeJornal || 'N/A'}</p> |
| <p class="text-sm text-gray-500">Última publicação: ${formatDate(j.dataUltima || j.DataUltima)}</p> |
| </div> |
| </div> |
| <span class="bg-indigo-100 text-indigo-700 px-3 py-1 rounded-full text-sm font-medium">${j.quantidade || j.Quantidade || 0} intimação(ões)</span> |
| </div> |
| `).join(''); |
| } |
|
|
| function linkIntimacaoToProcess(intId) { |
| const int = appData.intimacoes.find(i => i.id === intId); |
| if (!int) return; |
| showToast(`Intimação ${int.numeroProcesso} vinculada ao processo!`, 'success'); |
| } |
|
|
| function togglePassword(fieldId) { |
| const field = document.getElementById(fieldId); |
| if (field.type === 'password') { |
| field.type = 'text'; |
| field.nextElementSibling.innerHTML = '<i class="fas fa-eye-slash"></i>'; |
| } else { |
| field.type = 'password'; |
| field.nextElementSibling.innerHTML = '<i class="fas fa-eye"></i>'; |
| } |
| } |
|
|
| |
| let gapiLoaded = false; |
| let gisLoaded = false; |
| let tokenClient = null; |
|
|
| |
| |
| const GOOGLE_CLIENT_ID = 'YOUR_GOOGLE_CLIENT_ID.apps.googleusercontent.com'; |
| const GOOGLE_API_KEY = 'YOUR_GOOGLE_API_KEY'; |
| const SCOPES = 'https://www.googleapis.com/auth/drive.file https://www.googleapis.com/auth/drive.readonly https://www.googleapis.com/auth/spreadsheets.readonly'; |
| const SPREADSHEET_ID = '19EOpljeLASYLgyWhxJWtGBexELlt3GDoYBbcE5ZRExk'; |
|
|
| function loadGoogleAPI() { |
| const script = document.createElement('script'); |
| script.src = 'https://apis.google.com/js/api.js'; |
| script.onload = () => { |
| gapi.load('client', async () => { |
| try { |
| await gapi.client.init({ apiKey: GOOGLE_API_KEY, discoveryDocs: ['https://www.googleapis.com/auth/drive.file', 'https://sheets.googleapis.com/$discovery/rest?version=v4'] }); |
| gapiLoaded = true; |
| console.log('GAPI loaded'); |
| } catch(e) { console.error('GAPI init error', e); } |
| }); |
| }; |
| document.body.appendChild(script); |
| } |
|
|
| function connectGoogleDrive() { |
| if (!GOOGLE_CLIENT_ID || GOOGLE_CLIENT_ID.includes('YOUR_GOOGLE')) { |
| showToast('Configure o Client ID do Google no app.js', 'warning'); |
| showGoogleConfigInfo(); |
| return; |
| } |
| |
| try { |
| tokenClient = google.accounts.oauth2.initTokenClient({ |
| client_id: GOOGLE_CLIENT_ID, |
| scope: SCOPES, |
| callback: (tokenResponse) => { |
| if (tokenResponse.error) { |
| showToast('Erro na autenticação Google: ' + tokenResponse.error, 'error'); |
| return; |
| } |
| appData.driveConnected = true; |
| updateDriveStatus(true); |
| showToast('Google Drive conectado com sucesso!'); |
| saveAppData(); |
| } |
| }); |
| tokenClient.requestAccessToken({ prompt: '' }); |
| } catch(e) { |
| console.error('Google Auth Error:', e); |
| showToast('Erro ao conectar com Google. Verifique a configuração.', 'error'); |
| showGoogleConfigInfo(); |
| } |
| } |
|
|
| function connectGoogleSheets() { |
| if (!appData.driveConnected && (!GOOGLE_CLIENT_ID || GOOGLE_CLIENT_ID.includes('YOUR_GOOGLE'))) { |
| showToast('Configure o Google Client ID primeiro', 'warning'); |
| showGoogleConfigInfo(); |
| return; |
| } |
| |
| if (!appData.driveConnected) { |
| connectGoogleDrive(); |
| return; |
| } |
|
|
| fetchSpreadsheetData(); |
| } |
|
|
| async function fetchSpreadsheetData() { |
| try { |
| const response = await gapi.client.sheets.spreadsheets.values.get({ |
| spreadsheetId: SPREADSHEET_ID, |
| range: 'A:Z' |
| }); |
| |
| const rows = response.result.values; |
| if (rows && rows.length > 0) { |
| appData.importPreview = rows; |
| renderImportPreview(rows); |
| updateSheetsStatus(true); |
| showToast(`${rows.length - 1} registros importados da planilha!`); |
| } |
| } catch(e) { |
| console.error('Sheets API Error:', e); |
| |
| const mockRows = [ |
| ['Nome', 'CPF/CNPJ', 'Email', 'Telefone', 'Endereço', 'Tipo Processo', 'Descrição'], |
| ['João da Silva', '123.456.789-00', 'joao@email.com', '(11) 98765-4321', 'Rua A, 100 - SP', 'Cível', 'Ação indenizatória por danos morais'], |
| ['Maria Oliveira', '987.654.321-00', 'maria@email.com', '(21) 99876-5432', 'Av B, 200 - RJ', 'Trabalhista', 'Reclamação trabalhista - horas extras'], |
| ['Empresa ABC Ltda', '12.345.678/0001-90', 'contato@abc.com', '(11) 3456-7890', 'Rua C, 300 - SP', 'Tributário', 'Mandado de segurança - ICMS'], |
| ]; |
| appData.importPreview = mockRows; |
| renderImportPreview(mockRows); |
| updateSheetsStatus(true); |
| showToast('Dados de demonstração carregados', 'warning'); |
| } |
| } |
|
|
| function renderImportPreview(rows) { |
| const container = document.getElementById('import-preview'); |
| const table = document.getElementById('import-preview-table'); |
| container.classList.remove('hidden'); |
|
|
| if (!rows || rows.length === 0) return; |
|
|
| const headers = rows[0]; |
| let html = '<thead class="bg-gray-50"><tr>'; |
| headers.forEach(h => html += `<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">${h}</th>`); |
| html += '</tr></thead><tbody class="bg-white divide-y divide-gray-200">'; |
| |
| rows.slice(1).forEach(row => { |
| html += '<tr>'; |
| row.forEach(cell => html += `<td class="px-4 py-2 text-sm text-gray-500 whitespace-nowrap">${cell || ''}</td>`); |
| html += '</tr>'; |
| }); |
| html += '</tbody>'; |
| table.innerHTML = html; |
| } |
|
|
| function confirmImport() { |
| if (!appData.importPreview) return; |
| |
| const rows = appData.importPreview; |
| const headers = rows[0]; |
| |
| |
| const nomeIdx = headers.findIndex(h => /nome/i.test(h)); |
| const cpfIdx = headers.findIndex(h => /cpf|cnpj/i.test(h)); |
| const emailIdx = headers.findIndex(h => /email|e-mail/i.test(h)); |
| const telIdx = headers.findIndex(h => /telef/i.test(h)); |
| const endIdx = headers.findIndex(h => /endere/i.test(h)); |
|
|
| rows.slice(1).forEach(row => { |
| const exists = appData.clientes.find(c => c.cpfCnpj === (row[cpfIdx] || '')); |
| if (!exists && row[nomeIdx]) { |
| appData.clientes.push({ |
| id: Date.now() + Math.random(), |
| nome: row[nomeIdx] || '', |
| tipo: (row[cpfIdx] || '').length > 14 ? 'pj' : 'pf', |
| cpfCnpj: row[cpfIdx] || '', |
| email: row[emailIdx] || '', |
| telefone: row[telIdx] || '', |
| endereco: row[endIdx] || '', |
| processos: 0 |
| }); |
| } |
| }); |
|
|
| saveAppData(); |
| updateStats(); |
| showToast('Dados importados com sucesso!'); |
| } |
|
|
| async function uploadToGoogleDrive(file, evidenceId) { |
| if (!appData.driveConnected) return; |
| |
| try { |
| const metadata = { |
| name: `[LegalData] ${file.name}`, |
| parents: [], |
| description: `Prova enviada via LegalData Manager - ID: ${evidenceId}` |
| }; |
|
|
| const form = new FormData(); |
| form.append('metadata', new Blob([JSON.stringify(metadata)], { type: 'application/json' })); |
| form.append('file', file); |
|
|
| const response = await fetch('https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart', { |
| method: 'POST', |
| headers: new Headers({ 'Authorization': 'Bearer ' + gapi.auth.getToken().access_token }), |
| body: form |
| }); |
|
|
| const result = await response.json(); |
| const ev = appData.evidencias.find(e => e.id === evidenceId); |
| if (ev) { |
| ev.driveId = result.id; |
| saveAppData(); |
| showToast('Arquivo salvo no Google Drive!', 'info'); |
| } |
| } catch(e) { |
| console.error('Drive upload error:', e); |
| showToast('Erro ao salvar no Drive', 'error'); |
| } |
| } |
|
|
| function updateDriveStatus(connected) { |
| appData.driveConnected = connected; |
| |
| const icon = document.getElementById('drive-icon'); |
| const text = document.getElementById('drive-status-text'); |
| const sub = document.getElementById('drive-status-sub'); |
| const btn = document.getElementById('drive-connect-btn'); |
| const dot = document.getElementById('drive-conn-dot'); |
| const label = document.getElementById('drive-conn-label'); |
| const intBtn = document.getElementById('drive-integration-btn'); |
|
|
| if (connected) { |
| if (icon) icon.className = 'w-10 h-10 rounded-lg bg-green-100 flex items-center justify-center text-green-600'; |
| if (icon) icon.innerHTML = '<i class="fab fa-google-drive text-xl"></i>'; |
| if (text) text.textContent = 'Google Drive conectado'; |
| if (sub) sub.textContent = 'Arquivos serão sincronizados automaticamente'; |
| if (btn) { btn.textContent = 'Desconectar'; btn.className = 'bg-red-100 text-red-600 px-4 py-2 rounded-lg hover:bg-red-200 transition'; btn.onclick = disconnectGoogleDrive; } |
| if (dot) { dot.className = 'w-3 h-3 rounded-full bg-green-500'; } |
| if (label) { label.textContent = 'Conectado'; label.className = 'text-sm text-green-600 font-medium'; } |
| if (intBtn) { intBtn.textContent = 'Desconectar'; intBtn.className = 'w-full bg-red-100 text-red-600 py-2 rounded-lg hover:bg-red-200 transition'; } |
| } else { |
| if (icon) icon.className = 'w-10 h-10 rounded-lg bg-gray-100 flex items-center justify-center text-gray-400'; |
| if (icon) icon.innerHTML = '<i class="fab fa-google-drive text-xl"></i>'; |
| if (text) text.textContent = 'Google Drive desconectado'; |
| if (sub) sub.textContent = 'Conecte para sincronizar provas na nuvem'; |
| if (btn) { btn.innerHTML = '<i class="fab fa-google mr-2"></i> Conectar Google Drive'; btn.className = 'bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 transition'; btn.onclick = connectGoogleDrive; } |
| if (dot) { dot.className = 'w-3 h-3 rounded-full bg-gray-400'; } |
| if (label) { label.textContent = 'Desconectado'; label.className = 'text-sm text-gray-500 font-medium'; } |
| } |
| } |
|
|
| function updateSheetsStatus(connected) { |
| appData.sheetsConnected = connected; |
| const dot = document.getElementById('sheets-conn-dot'); |
| const label = document.getElementById('sheets-conn-label'); |
| const btn = document.getElementById('sheets-integration-btn'); |
|
|
| if (connected) { |
| if (dot) dot.className = 'w-3 h-3 rounded-full bg-green-500'; |
| if (label) { label.textContent = 'Conectado'; label.className = 'text-sm text-green-600 font-medium'; } |
| if (btn) { btn.textContent = 'Sincronizar Dados'; btn.className = 'w-full bg-green-100 text-green-700 py-2 rounded-lg hover:bg-green-200 transition'; } |
| } |
| } |
|
|
| function disconnectGoogleDrive() { |
| if (tokenClient) { |
| const token = gapi?.auth?.getToken(); |
| if (token) google.accounts.oauth2.revoke(token.access_token); |
| } |
| updateDriveStatus(false); |
| updateSheetsStatus(false); |
| showToast('Google Drive desconectado', 'info'); |
| } |
|
|
| function showGoogleConfigInfo() { |
| const info = ` |
| <div class="bg-yellow-50 border border-yellow-200 rounded-lg p-4 mb-4"> |
| <h4 class="font-semibold text-yellow-800 mb-2"><i class="fas fa-info-circle mr-2"></i>Configuração do Google OAuth</h4> |
| <p class="text-sm text-yellow-700 mb-2">Para usar as integrações Google, você precisa:</p> |
| <ol class="text-sm text-yellow-700 list-decimal list-inside space-y-1"> |
| <li>Acessar <a href="https://console.cloud.google.com/" target="_blank" class="underline text-yellow-800">Google Cloud Console</a></li> |
| <li>Criar um projeto e ativar as APIs: Google Drive API e Google Sheets API</li> |
| <li>Criar credenciais OAuth 2.0</li> |
| <li>Adicionar <code class="bg-yellow-100 px-1 rounded">http://localhost</code> como origem autorizada</li> |
| <li>Copiar o Client ID e atualizar no arquivo <code class="bg-yellow-100 px-1 rounded">app.js</code></li> |
| </ol> |
| <p class="text-sm text-yellow-700 mt-2">Enquanto isso, o sistema funciona com dados locais e de demonstração.</p> |
| </div>`; |
| |
| const list = document.getElementById('intimacoes-list'); |
| if (list) list.innerHTML = info + list.innerHTML; |
| } |
|
|
| |
| function handleFileImport(event) { |
| const file = event.target.files[0]; |
| if (!file) return; |
|
|
| if (file.name.endsWith('.csv')) { |
| Papa.parse(file, { |
| header: true, |
| complete: (results) => { |
| appData.importPreview = [results.meta.fields, ...results.data.map(r => results.meta.fields.map(f => r[f]))]; |
| renderImportPreview(appData.importPreview); |
| showToast(`${results.data.length} registros importados do CSV`); |
| } |
| }); |
| } else if (file.name.endsWith('.xlsx') || file.name.endsWith('.xls')) { |
| const reader = new FileReader(); |
| reader.onload = (e) => { |
| const data = new Uint8Array(e.target.result); |
| const workbook = XLSX.read(data, { type: 'array' }); |
| const sheetName = workbook.SheetNames[0]; |
| const sheet = workbook.Sheets[sheetName]; |
| const jsonData = XLSX.utils.sheet_to_json(sheet, { header: 1 }); |
| appData.importPreview = jsonData; |
| renderImportPreview(jsonData); |
| showToast(`${jsonData.length - 1} registros importados do Excel`); |
| }; |
| reader.readAsArrayBuffer(file); |
| } |
| } |
|
|
| |
| function sanitizeData(type) { |
| let count = 0; |
| switch(type) { |
| case 'cpfcnpj': |
| appData.clientes.forEach(c => { |
| c.cpfCnpj = c.cpfCnpj.replace(/[^\d./-]/g, ''); |
| count++; |
| }); |
| showToast(`${count} CPFs/CNPJs padronizados`); |
| break; |
| case 'phone': |
| appData.clientes.forEach(c => { |
| c.telefone = c.telefone.replace(/[^\d() -]/g, ''); |
| count++; |
| }); |
| showToast(`${count} telefones padronizados`); |
| break; |
| case 'email': |
| const invalid = appData.clientes.filter(c => !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(c.email)); |
| showToast(`${invalid.length} e-mails inválidos encontrados`, invalid.length > 0 ? 'warning' : 'success'); |
| break; |
| case 'duplicates': |
| const seen = new Set(); |
| const before = appData.clientes.length; |
| appData.clientes = appData.clientes.filter(c => { |
| const key = c.cpfCnpj || c.email; |
| if (seen.has(key)) return false; |
| seen.add(key); |
| return true; |
| }); |
| count = before - appData.clientes.length; |
| showToast(`${count} duplicatas removidas`, count > 0 ? 'info' : 'success'); |
| break; |
| } |
| saveAppData(); |
| renderClientes(); |
| } |
|
|
| |
| function formatDate(dateStr) { |
| if (!dateStr) return 'N/A'; |
| try { |
| const d = new Date(dateStr); |
| return d.toLocaleDateString('pt-BR'); |
| } catch(e) { return dateStr; } |
| } |
|
|
| function generateId() { |
| return '2024-' + String(Math.floor(Math.random() * 9000) + 1000); |
| } |
|
|
| function updateStats() { |
| document.getElementById('stat-processos').textContent = appData.processos.length; |
| document.getElementById('stat-clientes').textContent = appData.clientes.length; |
| document.getElementById('stat-provas').textContent = appData.evidencias.length; |
| } |
|
|
| function updateNotificationBadge() { |
| const badge = document.getElementById('notification-badge'); |
| const count = appData.intimacoes.length; |
| if (count > 0) { |
| badge.textContent = count; |
| badge.classList.remove('hidden'); |
| } else { |
| badge.classList.add('hidden'); |
| } |
| } |
|
|
| function populateSelects() { |
| |
| const clientSelects = ['proc-cliente', 'ev-cliente']; |
| clientSelects.forEach(id => { |
| const el = document.getElementById(id); |
| if (el) { |
| el.innerHTML = '<option value="">Selecione...</option>' + |
| appData.clientes.map(c => `<option value="${c.id}">${c.nome}</option>`).join(''); |
| } |
| }); |
|
|
| |
| const procSelects = ['ev-processo']; |
| procSelects.forEach(id => { |
| const el = document.getElementById(id); |
| if (el) { |
| el.innerHTML = '<option value="">Selecione...</option>' + |
| appData.processos.map(p => `<option value="${p.id}">#${p.id} - ${p.cliente}</option>`).join(''); |
| } |
| }); |
|
|
| |
| const filterClient = document.getElementById('evidence-filter-client'); |
| if (filterClient) { |
| filterClient.innerHTML = '<option value="">Todos os Clientes</option>' + |
| appData.clientes.map(c => `<option value="${c.id}">${c.nome}</option>`).join(''); |
| } |
| } |
|
|
| |
| function renderDeadlineTable() { |
| const tbody = document.getElementById('deadline-table-body'); |
| if (!tbody) return; |
|
|
| const urgent = appData.processos |
| .filter(p => p.prazo && p.status !== 'Concluído') |
| .sort((a, b) => new Date(a.prazo) - new Date(b.prazo)) |
| .slice(0, 5); |
|
|
| const statusColors = { |
| 'Ativo': 'bg-green-100 text-green-800', |
| 'Pendente': 'bg-yellow-100 text-yellow-800', |
| 'Urgente': 'bg-red-100 text-red-800', |
| }; |
|
|
| tbody.innerHTML = urgent.map(p => ` |
| <tr> |
| <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">#${p.id}</td> |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${p.cliente}</td> |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${p.tribunal}</td> |
| <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${formatDate(p.prazo)}</td> |
| <td class="px-6 py-4 whitespace-nowrap"><span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full ${statusColors[p.status] || 'bg-gray-100 text-gray-800'}">${p.status}</span></td> |
| <td class="px-6 py-4 whitespace-nowrap text-sm"> |
| <button class="text-indigo-600 hover:text-indigo-900 mr-3"><i class="fas fa-eye"></i></button> |
| <button class="text-green-600 hover:text-green-900"><i class="fas fa-edit"></i></button> |
| </td> |
| </tr> |
| `).join(''); |
| } |
|
|
| |
| function initChart() { |
| const ctx = document.getElementById('processChart'); |
| if (!ctx) return; |
|
|
| new Chart(ctx, { |
| type: 'doughnut', |
| data: { |
| labels: ['TJSP', 'TJMG', 'TRF1', 'TRF4', 'Outros'], |
| datasets: [{ |
| data: [45, 20, 15, 12, 8], |
| backgroundColor: ['#4F46E5', '#10B981', '#F59E0B', '#EF4444', '#6B7280'], |
| borderWidth: 0 |
| }] |
| }, |
| options: { |
| responsive: true, |
| maintainAspectRatio: false, |
| plugins: { |
| legend: { position: 'bottom' } |
| } |
| } |
| }); |
| } |
|
|
| |
| let aaspInterval = null; |
| function startAASPRefresh() { |
| if (aaspInterval) clearInterval(aaspInterval); |
| aaspInterval = setInterval(() => { |
| if (document.getElementById('aasp-auto-refresh')?.checked) { |
| fetchAASPIntimacoes(); |
| } |
| }, 30 * 60 * 1000); |
| } |
|
|
| |
| document.addEventListener('keydown', (e) => { |
| if (e.key === 'Escape') { |
| document.querySelectorAll('[id^="modal-"]').forEach(m => m.classList.add('hidden')); |
| closeLightbox(); |
| } |
| }); |
|
|
| |
| document.addEventListener('DOMContentLoaded', () => { |
| loadAppData(); |
| populateSelects(); |
| renderProcessos(); |
| renderClientes(); |
| renderDeadlineTable(); |
| initChart(); |
| updateStats(); |
| updateNotificationBadge(); |
| |
| if (appData.driveConnected) updateDriveStatus(true); |
| if (appData.sheetsConnected) updateSheetsStatus(true); |
| |
| startAASPRefresh(); |
|
|
| |
| const today = new Date().toISOString().split('T')[0]; |
| const dataField = document.getElementById('aasp-data'); |
| if (dataField) dataField.value = today; |
| }); |