d9e195d924
- Foto do cliente atualizada automaticamente ao abrir a conversa (remove botão manual) - Exibe CLI_FOTO na tela de Dados do Cliente; matrícula com conversão robusta - Envio de boleto na conversa (checkbox em Configurações > Empresa): lista títulos em aberto e envia texto com linha digitável + PIX ao cliente - Novo Dashboard (gerente): conversas (abertas/não atendidas/não atribuídas/pendentes), atendentes disponíveis/desconectados e heatmap de tráfego - Presença de atendentes em memória + ping periódico do chat/dashboard Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
941 lines
50 KiB
HTML
941 lines
50 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="pt-BR">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Configurações - Chatc2</title>
|
||
<link rel="stylesheet" href="/css/main.css">
|
||
<style>
|
||
body { background:#f3f4f6; display:flex; min-height:100vh; }
|
||
.sidebar-nav .admin-only { display:none; }
|
||
.main { flex:1; display:flex; flex-direction:column; min-width:0; }
|
||
.container { flex:1; padding:24px; overflow-y:auto; }
|
||
.tabs { display:flex; margin-bottom:24px; background:#fff; border-radius:12px; overflow:hidden; box-shadow:0 1px 3px rgba(0,0,0,0.08); border:1px solid #f3f4f6; }
|
||
.tabs button { flex:1; padding:13px 16px; border:none; background:#fff; font-size:14px; cursor:pointer; border-bottom:2px solid transparent; transition:all .15s; color:#6b7280; font-weight:500; }
|
||
.tabs button:hover { background:#f9fafb; color:#374151; }
|
||
.tabs button.active { border-bottom-color:#667eea; color:#667eea; font-weight:700; background:#fafbff; }
|
||
.tab-content { display:none; }
|
||
.tab-content.active { display:block; }
|
||
.form-group { margin-bottom:16px; }
|
||
.form-group label { display:block; font-size:13px; font-weight:600; color:#374151; margin-bottom:5px; }
|
||
.form-group input, .form-group select, .form-group textarea { width:100%; padding:10px 14px; border:2px solid #e5e7eb; border-radius:8px; font-size:14px; outline:none; background:#f9fafb; color:#111827; transition:all .15s; font-family:inherit; }
|
||
.form-group input:focus, .form-group select:focus, .form-group textarea:focus { border-color:#667eea; background:#fff; box-shadow:0 0 0 3px rgba(102,126,234,0.1); }
|
||
.form-group textarea { min-height:80px; resize:vertical; }
|
||
.form-group .toggle { display:flex; align-items:center; gap:8px; }
|
||
.form-group .toggle input { width:auto; }
|
||
.btn { display:inline-flex; align-items:center; gap:6px; padding:10px 20px; border:none; border-radius:8px; font-size:14px; font-weight:600; cursor:pointer; transition:all .15s; }
|
||
.btn-primary { background:#667eea; color:#fff; }
|
||
.btn-primary:hover { background:#5a67d8; }
|
||
.btn-danger { background:#ef4444; color:#fff; }
|
||
.btn-danger:hover { background:#dc2626; }
|
||
.btn-sm { padding:6px 12px; font-size:12px; border-radius:6px; }
|
||
.badge { display:inline-block; padding:2px 9px; border-radius:10px; font-size:11px; font-weight:600; }
|
||
.badge-success { background:#d1fae5; color:#065f46; }
|
||
.badge-danger { background:#fef2f2; color:#991b1b; }
|
||
.user-info { display:flex; align-items:center; gap:14px; }
|
||
.user-name { font-size:14px; font-weight:500; color:#374151; }
|
||
.status-badge { display:inline-flex; align-items:center; gap:5px; padding:4px 12px; border-radius:20px; font-size:12px; font-weight:600; }
|
||
.status-badge.online { background:#d1fae5; color:#065f46; }
|
||
|
||
/* Responsivo: abas rolam horizontalmente no celular */
|
||
@media (max-width: 768px) {
|
||
.tabs { overflow-x: auto; -webkit-overflow-scrolling: touch; }
|
||
.tabs button { flex: 0 0 auto; white-space: nowrap; padding: 12px 14px; font-size: 13px; }
|
||
}
|
||
</style>
|
||
<link rel="stylesheet" href="/css/dark-mode.css">
|
||
<script>function darkModeToggle(){var e=document.body;if(!e)return;var a=localStorage.getItem('chatc2_dark_mode')!=='true';e.classList.toggle('dark-mode',a);localStorage.setItem('chatc2_dark_mode',a?'true':'false');document.querySelectorAll('.dark-mode-toggle').forEach(function(b){b.innerHTML=a?'☀️ Claro':'🌙 Escuro'});}
|
||
window.darkModeApply=function(a){var e=document.body;if(!e)return;e.classList.toggle('dark-mode',a);localStorage.setItem('chatc2_dark_mode',a?'true':'false');document.querySelectorAll('.dark-mode-toggle').forEach(function(b){b.innerHTML=a?'☀️ Claro':'🌙 Escuro'});};
|
||
window.darkModeIsDark=function(){return localStorage.getItem('chatc2_dark_mode')==='true';};</script>
|
||
</head>
|
||
<body>
|
||
<aside class="sidebar">
|
||
<div class="sidebar-brand">
|
||
<div class="logo">C2</div>
|
||
<div><h2>Chatc2</h2><span id="sidebarAlias">-</span></div>
|
||
</div>
|
||
<nav class="sidebar-nav">
|
||
<div class="nav-label">Principal</div>
|
||
<a href="#" id="navDashboard"><span class="icon">📊</span> Dashboard</a>
|
||
<a href="#" id="navClientsSide"><span class="icon">👥</span> Clientes</a>
|
||
<a href="#" id="navChat"><span class="icon">💬</span> Conversas</a>
|
||
<div class="nav-label admin-only" id="adminLabelSet">Administrador</div>
|
||
<a href="#" class="active admin-only" id="navConfig"><span class="icon">⚙️</span> Configurações</a>
|
||
<a href="#" id="navRoutesSet" class="admin-only"><span class="icon">📡</span> Rotas</a>
|
||
</nav>
|
||
<div class="sidebar-footer">
|
||
<button class="dark-mode-toggle" onclick="darkModeToggle()" style="width:100%;margin-bottom:8px;padding:8px">🌙 Escuro</button>
|
||
<a onclick="logout()"><span class="icon">🚪</span> Sair</a></div>
|
||
</aside>
|
||
<div class="main">
|
||
<div class="topbar"><span class="topbar-title">⚙️ Configurações</span></div>
|
||
<div class="container">
|
||
<div class="tabs">
|
||
<button class="active" onclick="ativarAba('equipe',this)">👥 Equipe</button>
|
||
<button onclick="ativarAba('fluxo',this)">📋 Fluxo</button>
|
||
<button onclick="ativarAba('empresa',this)">🏢 Empresa</button>
|
||
<button onclick="ativarAba('etiquetas',this)">🏷️ Etiquetas</button>
|
||
<button onclick="ativarAba('conexao',this)">📱 Conexão</button>
|
||
</div>
|
||
|
||
<!-- Aba Fluxo -->
|
||
<div class="tab-content" id="tabFluxo">
|
||
<div class="card">
|
||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
|
||
<h3 style="margin:0">📋 Fluxo de Atendimento</h3>
|
||
</div>
|
||
<p style="color:#6b7280;font-size:13px;margin-bottom:16px">
|
||
Configure os submenus que aparecem quando o cliente seleciona uma equipe.
|
||
As opções iniciais são sempre as <strong>Equipes</strong> cadastradas,
|
||
com a opção de <strong>Segunda via de Boleto</strong> no final.
|
||
</p>
|
||
<div id="menusList"><p style="color:#9ca3af">Carregando...</p></div>
|
||
</div>
|
||
|
||
<div class="card" id="cardResolucao">
|
||
<h3 style="margin:0 0 8px">🧩 Fluxo de Resolução</h3>
|
||
<p style="color:#6b7280;font-size:13px;margin-bottom:16px">
|
||
Defina os motivos de atendimento e como o atendente registra a resolução ao finalizar a conversa.
|
||
</p>
|
||
|
||
<h4 style="margin:8px 0">Motivo do Atendimento</h4>
|
||
<div style="display:flex;gap:8px;margin-bottom:8px">
|
||
<input type="text" id="novoMotivo" placeholder="Cadastrar novo motivo..." style="flex:1;padding:8px;border:2px solid #e5e7eb;border-radius:8px;font-size:13px" onkeydown="if(event.key==='Enter')adicionarMotivo()">
|
||
<button class="btn btn-primary btn-sm" onclick="adicionarMotivo()">+ Adicionar</button>
|
||
</div>
|
||
<div id="motivosList" style="margin-bottom:12px"><p style="color:#9ca3af;font-size:13px">Carregando...</p></div>
|
||
<div class="form-group"><div class="toggle"><input type="checkbox" id="flgMotivoVis"> <label for="flgMotivoVis">Visualizar Motivo na tela de conversa</label></div></div>
|
||
<div class="form-group"><div class="toggle"><input type="checkbox" id="flgMotivoObr"> <label for="flgMotivoObr">Obrigatório preencher (só finaliza com motivo)</label></div></div>
|
||
|
||
<h4 style="margin:16px 0 8px">Resolução do Atendimento</h4>
|
||
<div class="form-group"><div class="toggle"><input type="checkbox" id="flgResolVis"> <label for="flgResolVis">Visualizar Resolução na tela de conversa</label></div></div>
|
||
<div class="form-group"><div class="toggle"><input type="checkbox" id="flgResolObr"> <label for="flgResolObr">Obrigatório preencher (só finaliza com resolução)</label></div></div>
|
||
|
||
<button class="btn btn-primary" onclick="salvarResolucao()">💾 Salvar Fluxo de Resolução</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Aba Equipe -->
|
||
<div class="tab-content active" id="tabEquipe">
|
||
<div class="card">
|
||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
|
||
<h3 style="margin:0">Equipes</h3>
|
||
<button class="btn btn-primary btn-sm" onclick="mostrarModalEquipe()">+ Nova Equipe</button>
|
||
</div>
|
||
<div id="equipesList"><p style="color:#9ca3af">Carregando...</p></div>
|
||
</div>
|
||
<div class="card">
|
||
<h3>Usuários da Empresa</h3>
|
||
<div id="usuariosList"><p style="color:#9ca3af">Carregando...</p></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Aba Empresa -->
|
||
<div class="tab-content" id="tabEmpresa">
|
||
<div class="card">
|
||
<h3>Configurações da Empresa</h3>
|
||
<div id="configForm"><p style="color:#9ca3af">Carregando...</p></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Aba Etiquetas -->
|
||
<div class="tab-content" id="tabEtiquetas">
|
||
<div class="card">
|
||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
|
||
<h3 style="margin:0">Etiquetas</h3>
|
||
<button class="btn btn-primary btn-sm" onclick="mostrarModalEtiqueta()">+ Nova Etiqueta</button>
|
||
</div>
|
||
<div id="etiquetasList"><p style="color:#9ca3af">Carregando...</p></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Aba Conexão -->
|
||
<div class="tab-content" id="tabConexao">
|
||
<div class="card">
|
||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px">
|
||
<h3 style="margin:0">📱 Conexões WhatsApp</h3>
|
||
<button class="btn btn-primary btn-sm" onclick="mostrarModalConexao()">+ Nova Conexão</button>
|
||
</div>
|
||
<div id="conexoesList"><p style="color:#9ca3af">Carregando...</p></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modal Equipe -->
|
||
<div class="modal-overlay" id="modalEquipe" style="display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);align-items:center;justify-content:center;z-index:1000">
|
||
<div style="background:#fff;border-radius:12px;padding:24px;width:90%;max-width:400px">
|
||
<h3 id="modalEquipeTitle">Nova Equipe</h3>
|
||
<input type="hidden" id="editEquipeId">
|
||
<div class="form-group"><label>Nome da Equipe</label><input type="text" id="equipeNome" placeholder="Ex: Atendimento"></div>
|
||
<div class="form-group"><label>Ordem</label><input type="number" id="equipeOrdem" value="0" min="0" style="width:80px"><span style="font-size:12px;color:#9ca3af;margin-left:8px">(menor = aparece primeiro)</span></div>
|
||
<div class="form-group"><label>Membros</label><div id="equipeMembros"></div></div>
|
||
<div style="display:flex;gap:8px;justify-content:flex-end">
|
||
<button class="btn" onclick="fecharModal('modalEquipe')" style="background:#f3f4f6">Cancelar</button>
|
||
<button class="btn btn-primary" onclick="salvarEquipe()">Salvar</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modal Etiqueta -->
|
||
<div class="modal-overlay" id="modalEtiqueta" style="display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);align-items:center;justify-content:center;z-index:1000">
|
||
<div style="background:#fff;border-radius:12px;padding:24px;width:90%;max-width:400px">
|
||
<h3 id="modalEtiquetaTitle">Nova Etiqueta</h3>
|
||
<input type="hidden" id="editEtiquetaId">
|
||
<div class="form-group"><label>Nome</label><input type="text" id="etiquetaNome" placeholder="Ex: Cliente VIP"></div>
|
||
<div class="form-group"><label>Cor</label><input type="color" id="etiquetaCor" value="#667eea"></div>
|
||
<div style="display:flex;gap:8px;justify-content:flex-end">
|
||
<button class="btn" onclick="fecharModal('modalEtiqueta')" style="background:#f3f4f6">Cancelar</button>
|
||
<button class="btn btn-primary" onclick="salvarEtiqueta()">Salvar</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modal Menu -->
|
||
<div class="modal-overlay" id="modalMenu" style="display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);align-items:center;justify-content:center;z-index:1000">
|
||
<div style="background:#fff;border-radius:12px;padding:24px;width:90%;max-width:500px">
|
||
<h3 id="modalMenuTitle">Novo Submenu</h3>
|
||
<input type="hidden" id="editMenuId">
|
||
<input type="hidden" id="editMenuEquipeId">
|
||
<input type="hidden" id="editMenuPaiId">
|
||
<div class="form-group" id="menuEquipeGroup"><label>Equipe</label><select id="menuEquipe"><option value="">Selecione...</option></select></div>
|
||
<div class="form-group"><label>Título</label><input type="text" id="menuTitulo" placeholder="Ex: Alteração Cadastral"></div>
|
||
<div class="form-group">
|
||
<label>Tipo</label>
|
||
<select id="menuTipo" onchange="mudarTipoMenu()">
|
||
<option value="M">📂 Submenu (mostra mais opções)</option>
|
||
<option value="T">💬 Texto (envia mensagem fixa)</option>
|
||
<option value="R">⚙️ Ação (executa alteração via API)</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group" id="menuTextoGroup" style="display:none"><label>Texto a ser enviado</label><textarea id="menuTexto" rows="3" placeholder="Digite a mensagem..."></textarea></div>
|
||
<div class="form-group" id="menuRotaGroup" style="display:none">
|
||
<label>Ação (Rota)</label>
|
||
<select id="menuAcaoRota">
|
||
<option value="">Selecione uma ação...</option>
|
||
<option value="listar_carnes">📄 Listar carnês / Boleto</option>
|
||
<option value="alterar_email">📧 Alterar E-mail</option>
|
||
<option value="alterar_celular">📱 Alterar Celular</option>
|
||
<option value="alterar_endereco">🏠 Alterar Endereço</option>
|
||
<option value="info_cliente">ℹ️ Mostrar dados do cliente</option>
|
||
</select>
|
||
<div style="margin-top:8px"><label>Pergunta ao cliente (se precisar de dados)</label>
|
||
<textarea id="menuAcaoPrompt" rows="2" placeholder="Ex: Informe seu novo e-mail:" style="width:100%;padding:10px;border:2px solid #e5e7eb;border-radius:8px;font-size:13px;resize:vertical"></textarea></div>
|
||
</div>
|
||
<div class="form-group"><label>Ordem</label><input type="number" id="menuOrdem" value="0" min="0" style="width:80px"></div>
|
||
<div class="form-group"><label>Subordinado a (opcional)</label><select id="menuPai"><option value="">Nenhum (raiz da equipe)</option></select></div>
|
||
<div class="form-group"><label>Etiquetas (adicionar ao selecionar)</label><div id="menuEtiquetasContainer" style="display:flex;flex-wrap:wrap;gap:6px;padding:6px;border:1px solid #e5e7eb;border-radius:8px;min-height:36px"></div></div>
|
||
<div style="display:flex;gap:8px;justify-content:flex-end;margin-top:12px">
|
||
<button class="btn" onclick="fecharModal('modalMenu')" style="background:#f3f4f6">Cancelar</button>
|
||
<button class="btn btn-primary" onclick="salvarMenu()">Salvar</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modal Conexão -->
|
||
<div class="modal-overlay" id="modalConexao" style="display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);align-items:center;justify-content:center;z-index:1000">
|
||
<div style="background:#fff;border-radius:12px;padding:24px;width:90%;max-width:500px">
|
||
<h3 id="modalConexaoTitle">Nova Conexão WhatsApp</h3>
|
||
<input type="hidden" id="editConexaoId">
|
||
<div class="form-group"><label>Nome da Instância</label><input type="text" id="conNome" placeholder="Ex: WhatsApp Comercial"></div>
|
||
<div class="form-group"><label>URL Evolution API</label><input type="text" id="conUrl" value="https://evoatende.c2sistemas.com.br" placeholder="https://evoatende.c2sistemas.com.br"></div>
|
||
<div class="form-group"><label>API Key</label><input type="text" id="conApiKey" placeholder="API Key"></div>
|
||
<div class="form-group"><label>Nome da Instância (Evolution)</label><input type="text" id="conInstance" placeholder="Ex: empresa1-wpp"></div>
|
||
<div style="display:flex;gap:8px;justify-content:flex-end">
|
||
<button class="btn" onclick="fecharModal('modalConexao')" style="background:#f3f4f6">Cancelar</button>
|
||
<button class="btn btn-primary" onclick="salvarConexao()" id="btnSalvarConexao">Conectar</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
(function(){
|
||
'use strict';
|
||
const token = localStorage.getItem('chatc2_token');
|
||
const pathParts = window.location.pathname.split('/');
|
||
const alias = pathParts[2] || localStorage.getItem('chatc2_alias') || 'lajedo';
|
||
localStorage.setItem('chatc2_alias', alias);
|
||
const user = JSON.parse(localStorage.getItem('chatc2_user') || '{}');
|
||
const empresaId = user.empresas?.[0] || 1;
|
||
|
||
if (!token) { window.location.href = '/app/' + alias + '/login'; return; }
|
||
|
||
document.getElementById('sidebarAlias').textContent = alias;
|
||
document.getElementById("navDashboard").onclick = function(e) { e.preventDefault(); window.location.href = "/app/" + alias + "/dashboard"; };
|
||
document.getElementById("navChat").onclick = function(e) { e.preventDefault(); window.location.href = "/app/" + alias + "/company/" + empresaId + "/conversation/0"; };
|
||
document.getElementById("navConfig").onclick = function(e) { e.preventDefault(); window.location.href = "/app/" + alias + "/settings"; };
|
||
var navClientsSide = document.getElementById("navClientsSide");
|
||
if (navClientsSide) navClientsSide.onclick = function(e) { e.preventDefault(); window.location.href = "/app/" + alias + "/clients"; };
|
||
var navRoutesSet = document.getElementById("navRoutesSet");
|
||
if (navRoutesSet) navRoutesSet.onclick = function(e) { e.preventDefault(); window.location.href = "/app/" + alias + "/routes"; };
|
||
var tc = user.tipoChat || "A";
|
||
if (tc === "G") {
|
||
var admins = document.querySelectorAll(".admin-only");
|
||
for (var i = 0; i < admins.length; i++) admins[i].style.display = "";
|
||
}
|
||
|
||
window.logout = function() {
|
||
['chatc2_token','chatc2_alias','chatc2_user'].forEach(function(k) { localStorage.removeItem(k); });
|
||
window.location.href = '/app/' + alias + '/login';
|
||
};
|
||
|
||
function api(path, opts) {
|
||
return fetch('/api/' + alias + path, Object.assign({
|
||
headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token }
|
||
}, opts)).then(function(r) { return r.json(); });
|
||
}
|
||
|
||
// ===== ABAS =====
|
||
window.ativarAba = function(aba, btn) {
|
||
document.querySelectorAll('.tabs button').forEach(function(b) { b.classList.remove('active'); });
|
||
document.querySelectorAll('.tab-content').forEach(function(t) { t.classList.remove('active'); });
|
||
btn.classList.add('active');
|
||
document.getElementById('tab' + aba.charAt(0).toUpperCase() + aba.slice(1)).classList.add('active');
|
||
};
|
||
|
||
// ===== EQUIPES =====
|
||
async function carregarEquipes() {
|
||
var data = await api('/teams?empresaId=' + empresaId);
|
||
var div = document.getElementById('equipesList');
|
||
if (!data.success || !data.data || data.data.length === 0) {
|
||
div.innerHTML = '<p style="color:#9ca3af">Nenhuma equipe cadastrada</p>';
|
||
return;
|
||
}
|
||
div.innerHTML = '<table><thead><tr><th>Ordem</th><th>Nome</th><th>Membros</th><th>Ações</th></tr></thead><tbody>' +
|
||
data.data.map(function(eq) {
|
||
var membros = (eq.membros || []).map(function(m) { return m.nome; }).join(', ') || '-';
|
||
return '<tr><td>' + (eq.ordem || 0) + '</td><td><strong>' + eq.nome + '</strong></td><td>' + membros + '</td><td>' +
|
||
'<button class="btn btn-sm" onclick="editarEquipe(' + eq.id + ',' + (eq.ordem || 0) + ',\'' + eq.nome.replace(/'/g,"\\'") + '\')" style="background:#f3f4f6;margin-right:4px">✏️</button>' +
|
||
'<button class="btn btn-sm btn-danger" onclick="excluirEquipe(' + eq.id + ')">🗑️</button></td></tr>';
|
||
}).join('') + '</tbody></table>';
|
||
}
|
||
|
||
window.mostrarModalEquipe = function() {
|
||
document.getElementById('editEquipeId').value = '';
|
||
document.getElementById('equipeOrdem').value = 0;
|
||
document.getElementById('equipeNome').value = '';
|
||
document.getElementById('modalEquipeTitle').textContent = 'Nova Equipe';
|
||
carregarUsuariosCheckbox();
|
||
document.getElementById('modalEquipe').style.display = 'flex';
|
||
};
|
||
|
||
window.editarEquipe = function(id, ordem, nome) {
|
||
document.getElementById('editEquipeId').value = id;
|
||
document.getElementById('equipeOrdem').value = ordem;
|
||
document.getElementById('equipeNome').value = nome;
|
||
document.getElementById('modalEquipeTitle').textContent = 'Editar Equipe';
|
||
carregarUsuariosCheckbox(id);
|
||
document.getElementById('modalEquipe').style.display = 'flex';
|
||
};
|
||
|
||
async function carregarUsuariosCheckbox(equipeId) {
|
||
var div = document.getElementById('equipeMembros');
|
||
var data = await api('/company/users?empresaId=' + empresaId);
|
||
if (!data.success) { div.innerHTML = '<p style="color:#9ca3af">Erro ao carregar</p>'; return; }
|
||
|
||
var membrosAtuais = [];
|
||
if (equipeId) {
|
||
var eqData = await api('/teams?empresaId=' + empresaId);
|
||
var eq = (eqData.data || []).find(function(e) { return e.id === equipeId; });
|
||
if (eq) membrosAtuais = (eq.membros || []).map(function(m) { return m.id; });
|
||
}
|
||
|
||
div.innerHTML = (data.data || []).map(function(u) {
|
||
var checked = membrosAtuais.includes(u.id) ? 'checked' : '';
|
||
return '<label style="display:flex;align-items:center;gap:8px;padding:6px 0;font-size:13px"><input type="checkbox" value="' + u.id + '" ' + checked + '> ' + u.nome + ' (' + u.login + ')</label>';
|
||
}).join('');
|
||
}
|
||
|
||
window.salvarEquipe = async function() {
|
||
var id = document.getElementById('editEquipeId').value;
|
||
var nome = document.getElementById('equipeNome').value.trim();
|
||
var ordem = parseInt(document.getElementById('equipeOrdem').value) || 0;
|
||
var membros = Array.from(document.querySelectorAll('#equipeMembros input:checked')).map(function(cb) { return parseInt(cb.value); });
|
||
|
||
if (!nome) return alert('Informe o nome da equipe');
|
||
|
||
if (id) {
|
||
var r = await api('/teams/' + id, { method: 'PUT', body: JSON.stringify({ nome: nome, ordem: ordem, membros: membros }) });
|
||
if (r.success) { fecharModal('modalEquipe'); carregarEquipes(); }
|
||
} else {
|
||
var r = await api('/teams', { method: 'POST', body: JSON.stringify({ nome: nome, ordem: ordem, membros: membros, empresaId: empresaId }) });
|
||
if (r.success) { fecharModal('modalEquipe'); carregarEquipes(); }
|
||
}
|
||
};
|
||
|
||
window.excluirEquipe = async function(id) {
|
||
if (!confirm('Excluir esta equipe?')) return;
|
||
var r = await api('/teams/' + id, { method: 'DELETE' });
|
||
if (r.success) carregarEquipes();
|
||
};
|
||
|
||
// ===== USUÁRIOS =====
|
||
async function carregarUsuarios() {
|
||
var data = await api('/company/users?empresaId=' + empresaId);
|
||
var div = document.getElementById('usuariosList');
|
||
if (!data.success || !data.data || data.data.length === 0) {
|
||
div.innerHTML = '<p style="color:#9ca3af">Nenhum usuário encontrado</p>';
|
||
return;
|
||
}
|
||
div.innerHTML = '<table><thead><tr><th>Nome</th><th>Login</th><th>Tipo Chat</th></tr></thead><tbody>' +
|
||
data.data.map(function(u) {
|
||
var tipo = u.tipoChat === 'A' ? '<span class="badge badge-success">Atendente</span>' : u.tipoChat === 'G' ? '<span class="badge badge-success">Gerente</span>' : '<span class="badge badge-danger">Bloqueado</span>';
|
||
return '<tr><td>' + u.nome + '</td><td>' + u.login + '</td><td>' + tipo + '</td></tr>';
|
||
}).join('') + '</tbody></table>';
|
||
}
|
||
|
||
// ===== FLUXO DE ATENDIMENTO (MENUS) =====
|
||
async function carregarMenus() {
|
||
var [eqData, menuData] = await Promise.all([
|
||
api('/teams?empresaId=' + empresaId),
|
||
api('/menus?empresaId=' + empresaId)
|
||
]);
|
||
var div = document.getElementById('menusList');
|
||
|
||
if (!eqData.success || !eqData.data || eqData.data.length === 0) {
|
||
div.innerHTML = '<p style="color:#9ca3af">Crie equipes primeiro para configurar os submenus.</p>';
|
||
return;
|
||
}
|
||
|
||
var menusAgrupados = menuData.success ? menuData.data : [];
|
||
|
||
var html = '';
|
||
eqData.data.forEach(function(eq) {
|
||
var menusEq = menusAgrupados.find(function(g) { return g.equipeId === eq.id; });
|
||
var temMenus = menusEq && menusEq.menus && menusEq.menus.length > 0;
|
||
|
||
html += '<div style="margin-bottom:16px;border:1px solid #e5e7eb;border-radius:8px;overflow:hidden">';
|
||
html += '<div style="background:#f9fafb;padding:10px 14px;font-weight:600;font-size:14px;border-bottom:1px solid #e5e7eb;display:flex;align-items:center;justify-content:space-between">';
|
||
html += '<span>👥 ' + eq.nome + '</span>';
|
||
html += '<button class="btn btn-sm" onclick="mostrarModalMenu(' + eq.id + ')" style="background:#e0e7ff">+ Submenu</button>';
|
||
html += '</div>';
|
||
|
||
if (temMenus) {
|
||
html += '<div style="padding:4px 0">' + montarArvoreHtml(menusEq.menus, 0) + '</div>';
|
||
} else {
|
||
html += '<p style="padding:12px 14px;color:#9ca3af;font-size:13px;margin:0">Nenhum submenu configurado.</p>';
|
||
}
|
||
html += '</div>';
|
||
});
|
||
|
||
div.innerHTML = html;
|
||
}
|
||
|
||
function montarArvoreHtml(menus, nivel) {
|
||
if (!menus || menus.length === 0) return '';
|
||
var html = '<div style="padding-left:' + (nivel * 20 + 8) + 'px">';
|
||
menus.forEach(function(m) {
|
||
var tipoIcon = m.tipo === 'M' ? '📂' : m.tipo === 'T' ? '💬' : m.tipo === 'R' ? '⚙️' : '❓';
|
||
html += '<div style="display:flex;align-items:center;padding:6px 10px;border-bottom:1px solid #f3f4f6">';
|
||
html += '<span style="flex:1;font-size:13px">' + tipoIcon + ' ' + m.titulo + ' <span style="color:#9ca3af;font-size:11px">(' + m.tipo + ')</span></span>';
|
||
html += '<button class="btn btn-sm" onclick="mostrarModalMenu(' + m.equipeId + ',' + m.id + ')" style="background:#f3f4f6;margin-right:4px;padding:4px 8px;font-size:11px">✏️</button>';
|
||
html += '<button class="btn btn-sm" onclick="excluirMenu(' + m.id + ',\'' + m.titulo.replace(/'/g,"\\'") + '\')" style="background:#fef2f2;color:#991b1b;padding:4px 8px;font-size:11px">🗑️</button>';
|
||
html += '<button class="btn btn-sm" onclick="mostrarModalMenu(' + m.equipeId + ',null,' + m.id + ')" style="margin-left:4px;padding:4px 8px;font-size:11px">➕ Sub</button>';
|
||
html += '</div>';
|
||
if (m.filhos && m.filhos.length > 0) {
|
||
html += montarArvoreHtml(m.filhos, nivel + 1);
|
||
}
|
||
});
|
||
html += '</div>';
|
||
return html;
|
||
}
|
||
|
||
window.mostrarModalMenu = async function(equipeId, editMenuId, parentMenuId) {
|
||
// Carrega equipes para o select
|
||
var eqData = await api('/teams?empresaId=' + empresaId);
|
||
var selectEq = document.getElementById('menuEquipe');
|
||
selectEq.innerHTML = '<option value="">Selecione...</option>';
|
||
(eqData.data || []).forEach(function(eq) {
|
||
var opt = document.createElement('option');
|
||
opt.value = eq.id;
|
||
opt.textContent = eq.nome;
|
||
if (eq.id === equipeId) opt.selected = true;
|
||
selectEq.appendChild(opt);
|
||
});
|
||
|
||
document.getElementById('editMenuId').value = editMenuId || '';
|
||
document.getElementById('editMenuEquipeId').value = equipeId || '';
|
||
document.getElementById('editMenuPaiId').value = parentMenuId || '';
|
||
document.getElementById('menuTitulo').value = '';
|
||
document.getElementById('menuTipo').value = 'M';
|
||
document.getElementById('menuTexto').value = '';
|
||
document.getElementById('menuOrdem').value = 0;
|
||
document.getElementById('menuAcaoRota').value = '';
|
||
document.getElementById('menuAcaoPrompt').value = '';
|
||
document.getElementById('menuTextoGroup').style.display = 'none';
|
||
document.getElementById('menuRotaGroup').style.display = 'none';
|
||
document.getElementById('menuEquipeGroup').style.display = parentMenuId ? 'none' : 'block';
|
||
|
||
// Carrega menus pai disponíveis
|
||
var selectPai = document.getElementById('menuPai');
|
||
selectPai.innerHTML = '<option value="">Nenhum (raiz da equipe)</option>';
|
||
if (!parentMenuId) {
|
||
var flatData = await api('/menus/flat?empresaId=' + empresaId + '&equipeId=' + equipeId);
|
||
if (flatData.success && flatData.data) {
|
||
flatData.data.forEach(function(m) {
|
||
if (m.id !== editMenuId) {
|
||
var opt = document.createElement('option');
|
||
opt.value = m.id;
|
||
opt.textContent = m.titulo;
|
||
selectPai.appendChild(opt);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
// Carrega etiquetas disponiveis como checkboxes
|
||
var etiquetasData = await api('/labels?empresaId=' + empresaId);
|
||
var etiquetasSelecionadas = editMenuId ? await buscarEtiquetasDoMenu(editMenuId) : [];
|
||
if (!parentMenuId) etiquetasSelecionadas = etiquetasSelecionadas || [];
|
||
renderEtiquetasCheckbox(etiquetasData, etiquetasSelecionadas);
|
||
|
||
if (editMenuId) {
|
||
// Modo edição: busca dados
|
||
document.getElementById('modalMenuTitle').textContent = 'Editar Submenu';
|
||
|
||
// Como a API retorna agrupado, precisamos buscar os dados de outra forma
|
||
// Vamos usar uma chamada direta
|
||
var allData = await api('/menus?empresaId=' + empresaId);
|
||
if (allData.success) {
|
||
var found = null;
|
||
allData.data.forEach(function(g) {
|
||
function buscar(m, id) {
|
||
if (m.id === id) return m;
|
||
if (m.filhos) {
|
||
for (var f of m.filhos) {
|
||
var r = buscar(f, id);
|
||
if (r) return r;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
(g.menus || []).forEach(function(m) {
|
||
var r = buscar(m, editMenuId);
|
||
if (r) found = r;
|
||
});
|
||
});
|
||
|
||
if (found) {
|
||
document.getElementById('menuTitulo').value = found.titulo || '';
|
||
document.getElementById('menuTipo').value = found.tipo || 'M';
|
||
document.getElementById('menuTexto').value = found.texto || '';
|
||
document.getElementById('menuOrdem').value = found.ordem || 0;
|
||
document.getElementById('menuAcaoRota').value = found.acaoRota || '';
|
||
document.getElementById('menuAcaoPrompt').value = found.acaoPrompt || '';
|
||
|
||
if (found.paiId) {
|
||
selectPai.value = found.paiId;
|
||
}
|
||
|
||
if (found.tipo === 'T') {
|
||
document.getElementById('menuTextoGroup').style.display = 'block';
|
||
document.getElementById('menuRotaGroup').style.display = 'none';
|
||
} else if (found.tipo === 'R') {
|
||
document.getElementById('menuTextoGroup').style.display = 'none';
|
||
document.getElementById('menuRotaGroup').style.display = 'block';
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
document.getElementById('modalMenuTitle').textContent = 'Novo Submenu';
|
||
|
||
// Se tem um pai, marca no select
|
||
if (parentMenuId) {
|
||
selectPai.value = parentMenuId;
|
||
}
|
||
}
|
||
|
||
document.getElementById('modalMenu').style.display = 'flex';
|
||
};
|
||
|
||
window.mudarTipoMenu = function() {
|
||
var tipo = document.getElementById('menuTipo').value;
|
||
document.getElementById('menuTextoGroup').style.display = tipo === 'T' ? 'block' : 'none';
|
||
document.getElementById('menuRotaGroup').style.display = tipo === 'R' ? 'block' : 'none';
|
||
};
|
||
|
||
// Busca etiquetas configuradas em um menu (percorre a arvore da API)
|
||
async function buscarEtiquetasDoMenu(menuId) {
|
||
var allData = await api('/menus?empresaId=' + empresaId);
|
||
console.log('[Menu] buscarEtiquetasDoMenu - menuId:', menuId, '| allData:', JSON.stringify(allData).substring(0, 300));
|
||
var ids = [];
|
||
function percorrer(lista) {
|
||
(lista || []).forEach(function(m) {
|
||
if (m.id === menuId) {
|
||
if (m.etiquetaIds) ids = m.etiquetaIds.split(',').map(function(x){return parseInt(x.trim());}).filter(function(x){return !isNaN(x);});
|
||
}
|
||
if (m.filhos) percorrer(m.filhos);
|
||
});
|
||
}
|
||
allData.data.forEach(function(g) { percorrer(g.menus); });
|
||
return ids;
|
||
}
|
||
|
||
// Renderiza checkboxes de etiquetas no modal
|
||
function renderEtiquetasCheckbox(data, selecionadas) {
|
||
var container = document.getElementById('menuEtiquetasContainer');
|
||
if (!data.success || !data.data || data.data.length === 0) {
|
||
container.innerHTML = '<span style="color:#9ca3af;font-size:12px">Nenhuma etiqueta cadastrada</span>';
|
||
return;
|
||
}
|
||
container.innerHTML = data.data.map(function(e) {
|
||
var checked = selecionadas.includes(e.id) ? 'checked' : '';
|
||
return '<label style="display:flex;align-items:center;gap:4px;padding:4px 8px;background:#f3f4f6;border-radius:6px;font-size:12px;cursor:pointer">' +
|
||
'<input type="checkbox" value="' + e.id + '" ' + checked + ' style="accent-color:#667eea"> ' +
|
||
'<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:' + (e.cor || '#667eea') + '"></span> ' +
|
||
e.nome +
|
||
'</label>';
|
||
}).join('');
|
||
}
|
||
|
||
window.salvarMenu = async function() {
|
||
var editId = document.getElementById('editMenuId').value;
|
||
var equipeId = document.getElementById('editMenuEquipeId').value || document.getElementById('menuEquipe').value;
|
||
var paiId = document.getElementById('editMenuPaiId').value || document.getElementById('menuPai').value;
|
||
var titulo = document.getElementById('menuTitulo').value.trim();
|
||
var tipo = document.getElementById('menuTipo').value;
|
||
var texto = document.getElementById('menuTexto').value;
|
||
var ordem = parseInt(document.getElementById('menuOrdem').value) || 0;
|
||
var acaoRota = document.getElementById('menuAcaoRota').value;
|
||
var acaoPrompt = document.getElementById('menuAcaoPrompt').value;
|
||
// Etiquetas selecionadas
|
||
var etiquetaIds = Array.from(document.querySelectorAll('#menuEtiquetasContainer input[type="checkbox"]:checked')).map(function(cb) { return parseInt(cb.value); }).filter(function(v) { return !isNaN(v); }).join(',');
|
||
|
||
if (!titulo) return alert('Informe o título');
|
||
if (!equipeId) return alert('Selecione a equipe');
|
||
|
||
var body = {
|
||
empresaId: empresaId,
|
||
equipeId: parseInt(equipeId),
|
||
titulo: titulo,
|
||
tipo: tipo,
|
||
texto: tipo === 'T' ? texto : null,
|
||
ordem: ordem,
|
||
acaoRota: tipo === 'R' ? acaoRota : null,
|
||
acaoPrompt: tipo === 'R' ? acaoPrompt : null,
|
||
menuPaiId: paiId ? parseInt(paiId) : null,
|
||
etiquetaIds: etiquetaIds || null,
|
||
};
|
||
|
||
console.log('[Menu] Salvando body:', JSON.stringify(body));
|
||
if (editId) {
|
||
var r = await api('/menus/' + editId, { method: 'PUT', body: JSON.stringify(body) });
|
||
console.log('[Menu] Resposta save:', JSON.stringify(r));
|
||
if (r.success) { fecharModal('modalMenu'); carregarMenus(); }
|
||
else alert('Erro: ' + (r.error || 'desconhecido'));
|
||
} else {
|
||
var r = await api('/menus', { method: 'POST', body: JSON.stringify(body) });
|
||
if (r.success) { fecharModal('modalMenu'); carregarMenus(); }
|
||
else alert('Erro: ' + (r.error || 'desconhecido'));
|
||
}
|
||
};
|
||
|
||
window.excluirMenu = async function(id, titulo) {
|
||
if (!confirm('Excluir o submenu "' + titulo + '" e todos os seus sub-itens?')) return;
|
||
var r = await api('/menus/' + id, { method: 'DELETE' });
|
||
if (r.success) carregarMenus();
|
||
};
|
||
|
||
// ===== ETIQUETAS =====
|
||
async function carregarEtiquetas() {
|
||
var data = await api('/labels?empresaId=' + empresaId);
|
||
var div = document.getElementById('etiquetasList');
|
||
if (!data.success || !data.data || data.data.length === 0) {
|
||
div.innerHTML = '<p style="color:#9ca3af">Nenhuma etiqueta cadastrada</p>';
|
||
return;
|
||
}
|
||
div.innerHTML = '<table><thead><tr><th>Nome</th><th>Cor</th><th>Ações</th></tr></thead><tbody>' +
|
||
data.data.map(function(l) {
|
||
return '<tr><td><strong>' + l.nome + '</strong></td><td><span class="tag" style="background:' + l.cor + '">' + l.cor + '</span></td><td>' +
|
||
'<button class="btn btn-sm" onclick="editarEtiqueta(' + l.id + ',\'' + l.nome.replace(/'/g,"\\'") + '\',\'' + l.cor + '\')" style="background:#f3f4f6;margin-right:4px">✏️</button>' +
|
||
'<button class="btn btn-sm btn-danger" onclick="excluirEtiqueta(' + l.id + ')">🗑️</button></td></tr>';
|
||
}).join('') + '</tbody></table>';
|
||
}
|
||
|
||
window.mostrarModalEtiqueta = function() {
|
||
document.getElementById('editEtiquetaId').value = '';
|
||
document.getElementById('etiquetaNome').value = '';
|
||
document.getElementById('etiquetaCor').value = '#667eea';
|
||
document.getElementById('modalEtiquetaTitle').textContent = 'Nova Etiqueta';
|
||
document.getElementById('modalEtiqueta').style.display = 'flex';
|
||
};
|
||
|
||
window.editarEtiqueta = function(id, nome, cor) {
|
||
document.getElementById('editEtiquetaId').value = id;
|
||
document.getElementById('etiquetaNome').value = nome;
|
||
document.getElementById('etiquetaCor').value = cor;
|
||
document.getElementById('modalEtiquetaTitle').textContent = 'Editar Etiqueta';
|
||
document.getElementById('modalEtiqueta').style.display = 'flex';
|
||
};
|
||
|
||
window.salvarEtiqueta = async function() {
|
||
var id = document.getElementById('editEtiquetaId').value;
|
||
var nome = document.getElementById('etiquetaNome').value.trim();
|
||
var cor = document.getElementById('etiquetaCor').value;
|
||
if (!nome) return alert('Informe o nome');
|
||
|
||
if (id) {
|
||
var r = await api('/labels/' + id, { method: 'PUT', body: JSON.stringify({ nome: nome, cor: cor }) });
|
||
if (r.success) { fecharModal('modalEtiqueta'); carregarEtiquetas(); }
|
||
} else {
|
||
var r = await api('/labels', { method: 'POST', body: JSON.stringify({ nome: nome, cor: cor }) });
|
||
if (r.success) { fecharModal('modalEtiqueta'); carregarEtiquetas(); }
|
||
}
|
||
};
|
||
|
||
window.excluirEtiqueta = async function(id) {
|
||
if (!confirm('Excluir esta etiqueta?')) return;
|
||
var r = await api('/labels/' + id, { method: 'DELETE' });
|
||
if (r.success) carregarEtiquetas();
|
||
};
|
||
|
||
// ===== CONFIGURAÇÕES EMPRESA =====
|
||
async function carregarConfig() {
|
||
var data = await api('/company/config?empresaId=' + empresaId);
|
||
var div = document.getElementById('configForm');
|
||
if (!data.success) { div.innerHTML = '<p style="color:#ef4444">Erro ao carregar</p>'; return; }
|
||
|
||
var cfg = data.data;
|
||
div.innerHTML =
|
||
'<div class="form-group"><label>Instância Padrão</label><select id="cfgInstancia"><option value="">Nenhuma</option></select></div>' +
|
||
'<div class="form-group"><div class="toggle"><input type="checkbox" id="cfgFoto" ' + (cfg.fotoCelular === 'S' ? 'checked' : '') + '> <label for="cfgFoto">Atualizar foto do cliente conforme WhatsApp</label></div></div>' +
|
||
'<div class="form-group"><div class="toggle"><input type="checkbox" id="cfgSaudacao" ' + (cfg.saudacaoAtiva === 'S' ? 'checked' : '') + '> <label for="cfgSaudacao">Ativar saudação automática</label></div></div>' +
|
||
'<div class="form-group"><label>Mensagem de Saudação</label><textarea id="cfgSaudacaoMsg">' + (cfg.saudacaoMensagem || '') + '</textarea></div>' +
|
||
'<div class="form-group"><div class="toggle"><input type="checkbox" id="cfgNomeUser" ' + (cfg.enviarNomeUsuario === 'S' ? 'checked' : '') + '> <label for="cfgNomeUser">Mostrar nome do usuário nas mensagens ("Nome: Mensagem")</label></div></div>' +
|
||
'<div class="form-group"><div class="toggle"><input type="checkbox" id="cfgEnviarBoleto" ' + (cfg.enviarBoleto === 'S' ? 'checked' : '') + '> <label for="cfgEnviarBoleto">💳 Permitir enviar boleto na conversa (botão "Enviar boleto")</label></div></div>' +
|
||
'<div class="form-group"><div class="toggle"><input type="checkbox" id="cfgTriagem" ' + (cfg.triagemAtiva === 'S' ? 'checked' : '') + '> <label for="cfgTriagem">📋 Ativar fluxo de triagem (menu de opções)</label></div></div>' +
|
||
'<div class="form-group" id="triagemConfig" style="display:' + (cfg.triagemAtiva === 'S' ? 'block' : 'none') + ';padding:12px;background:#f9fafb;border-radius:8px;margin-bottom:12px">' +
|
||
'<div class="form-group"><label>Mensagem de boas-vindas (use {EMPRESA} para o nome)</label><textarea id="cfgTriagemWelcome" rows="2" style="width:100%;padding:10px;border:2px solid #e5e7eb;border-radius:8px;font-size:13px;resize:vertical">' + (cfg.triagemMsgWelcome || '') + '</textarea></div>' +
|
||
'<div class="form-group"><label>Mensagem após escolha</label><textarea id="cfgTriagemAfter" rows="2" style="width:100%;padding:10px;border:2px solid #e5e7eb;border-radius:8px;font-size:13px;resize:vertical">' + (cfg.triagemMsgAfter || '') + '</textarea></div>' +
|
||
'<div class="form-group"><label>Número da opção "Segunda via de Boleto"</label><input type="text" id="cfgTriagemBoletoNum" value="' + (cfg.triagemBoletoNumero || '0') + '" style="width:100%;padding:10px;border:2px solid #e5e7eb;border-radius:8px;font-size:14px"></div>' +
|
||
'</div>' +
|
||
'<div class="form-group"><div class="toggle"><input type="checkbox" id="cfgCsat" ' + (cfg.csatAtivo === 'S' ? 'checked' : '') + '> <label for="cfgCsat">Ativar CSAT (Pesquisa de satisfação)</label></div></div>' +
|
||
'<div class="form-group"><label>Mensagem CSAT</label><textarea id="cfgCsatMsg">' + (cfg.csatMensagem || '') + '</textarea></div>' +
|
||
'<button class="btn btn-primary" onclick="salvarConfig()">💾 Salvar Configurações</button>';
|
||
|
||
// Evento para toggle da triagem
|
||
document.getElementById('cfgTriagem').addEventListener('change', function() {
|
||
document.getElementById('triagemConfig').style.display = this.checked ? 'block' : 'none';
|
||
});
|
||
|
||
// Carrega instâncias no select
|
||
var instData = await api('/evolution/instances?empresaId=' + empresaId);
|
||
if (instData.success && instData.data) {
|
||
var select = document.getElementById('cfgInstancia');
|
||
instData.data.forEach(function(ins) {
|
||
var opt = document.createElement('option');
|
||
opt.value = ins.id;
|
||
opt.textContent = ins.nome + ' (' + ins.instanceName + ')';
|
||
if (ins.id === cfg.instanciaPadraoId) opt.selected = true;
|
||
select.appendChild(opt);
|
||
});
|
||
}
|
||
}
|
||
|
||
window.salvarConfig = async function() {
|
||
var data = {
|
||
empresaId: empresaId,
|
||
instanciaPadraoId: parseInt(document.getElementById('cfgInstancia').value) || null,
|
||
fotoCelular: document.getElementById('cfgFoto').checked ? 'S' : 'N',
|
||
saudacaoAtiva: document.getElementById('cfgSaudacao').checked ? 'S' : 'N',
|
||
saudacaoMensagem: document.getElementById('cfgSaudacaoMsg').value,
|
||
enviarNomeUsuario: document.getElementById('cfgNomeUser').checked ? 'S' : 'N',
|
||
enviarBoleto: document.getElementById('cfgEnviarBoleto').checked ? 'S' : 'N',
|
||
triagemAtiva: document.getElementById('cfgTriagem').checked ? 'S' : 'N',
|
||
triagemMsgWelcome: document.getElementById('cfgTriagemWelcome').value,
|
||
triagemMsgAfter: document.getElementById('cfgTriagemAfter').value,
|
||
triagemBoletoNumero: document.getElementById('cfgTriagemBoletoNum').value,
|
||
csatAtivo: document.getElementById('cfgCsat').checked ? 'S' : 'N',
|
||
csatMensagem: document.getElementById('cfgCsatMsg').value,
|
||
};
|
||
|
||
var r = await api('/company/config', { method: 'POST', body: JSON.stringify(data) });
|
||
if (r.success) alert('Configurações salvas com sucesso!');
|
||
};
|
||
|
||
// O addEventListener do cfgTriagem é adicionado dentro do carregarConfig() após criar o HTML
|
||
|
||
// ===== FLUXO DE RESOLUÇÃO =====
|
||
function escc(s){ return String(s == null ? '' : s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); }
|
||
|
||
async function carregarResolucao() {
|
||
var md = await api('/motivos?empresaId=' + empresaId);
|
||
var div = document.getElementById('motivosList');
|
||
if (div && md.success) {
|
||
div.innerHTML = (md.data && md.data.length)
|
||
? md.data.map(function(m) {
|
||
return '<div style="display:flex;justify-content:space-between;align-items:center;padding:6px 10px;border:1px solid #eee;border-radius:6px;margin-bottom:4px">' +
|
||
'<span style="font-size:13px">' + escc(m.descricao) + '</span>' +
|
||
'<button class="btn btn-sm" style="color:#dc2626;background:none;border:none;cursor:pointer" onclick="removerMotivo(' + m.id + ')">🗑️</button></div>';
|
||
}).join('')
|
||
: '<p style="color:#9ca3af;font-size:13px">Nenhum motivo cadastrado.</p>';
|
||
}
|
||
var cd = await api('/company/config?empresaId=' + empresaId);
|
||
if (cd.success) {
|
||
var s = function(id, v) { var el = document.getElementById(id); if (el) el.checked = v === 'S'; };
|
||
s('flgMotivoVis', cd.data.motivoVisualizar);
|
||
s('flgMotivoObr', cd.data.motivoObrigatorio);
|
||
s('flgResolVis', cd.data.resolucaoVisualizar);
|
||
s('flgResolObr', cd.data.resolucaoObrigatorio);
|
||
}
|
||
}
|
||
|
||
window.adicionarMotivo = async function() {
|
||
var inp = document.getElementById('novoMotivo');
|
||
var d = (inp.value || '').trim();
|
||
if (!d) return;
|
||
var r = await api('/motivos', { method: 'POST', body: JSON.stringify({ descricao: d, empresaId: empresaId }) });
|
||
if (r.success) { inp.value = ''; carregarResolucao(); } else alert(r.error || 'Erro ao adicionar motivo');
|
||
};
|
||
|
||
window.removerMotivo = async function(id) {
|
||
if (!confirm('Remover este motivo?')) return;
|
||
var r = await api('/motivos/' + id, { method: 'DELETE' });
|
||
if (r.success) carregarResolucao(); else alert(r.error || 'Erro ao remover');
|
||
};
|
||
|
||
window.salvarResolucao = async function() {
|
||
var body = {
|
||
empresaId: empresaId,
|
||
motivoVisualizar: document.getElementById('flgMotivoVis').checked ? 'S' : 'N',
|
||
motivoObrigatorio: document.getElementById('flgMotivoObr').checked ? 'S' : 'N',
|
||
resolucaoVisualizar: document.getElementById('flgResolVis').checked ? 'S' : 'N',
|
||
resolucaoObrigatorio: document.getElementById('flgResolObr').checked ? 'S' : 'N',
|
||
};
|
||
var r = await api('/company/resolucao-config', { method: 'POST', body: JSON.stringify(body) });
|
||
if (r.success) alert('Fluxo de Resolução salvo!'); else alert(r.error || 'Erro ao salvar');
|
||
};
|
||
|
||
// ===== CONEXÕES =====
|
||
async function carregarConexoes() {
|
||
var data = await api('/evolution/instances?empresaId=' + empresaId);
|
||
var div = document.getElementById('conexoesList');
|
||
if (!data.success || !data.data || data.data.length === 0) {
|
||
div.innerHTML = '<p style="color:#9ca3af">Nenhuma conexão cadastrada</p>';
|
||
return;
|
||
}
|
||
div.innerHTML = '<table><thead><tr><th>Nome</th><th>Instância</th><th>URL</th><th>Status</th><th>Ações</th></tr></thead><tbody>' +
|
||
data.data.map(function(ins) {
|
||
var status = ins.status === 'A' ? '<span class="badge badge-success">✅ Conectado</span>' :
|
||
ins.status === 'C' ? '<span class="badge badge-success">🟡 Conectando</span>' :
|
||
ins.status === 'D' ? '<span class="badge badge-danger">⛔ Desconectado</span>' : '<span class="badge badge-danger">❌ ' + ins.status + '</span>';
|
||
var nomeEsc = (ins.nome || '').replace(/'/g, "\\'");
|
||
return '<tr><td><strong>' + ins.nome + '</strong></td><td>' + ins.instanceName + '</td><td style="font-size:11px;max-width:150px;overflow:hidden;text-overflow:ellipsis">' + ins.url + '</td><td>' + status + '</td><td>' +
|
||
'<button class="btn btn-sm" onclick="editarConexao(' + ins.id + ')" style="background:#f3f4f6;margin-right:4px">✏️</button>' +
|
||
'<button class="btn btn-sm" onclick="excluirConexao(' + ins.id + ',\'' + nomeEsc + '\')" style="background:#fef2f2;color:#991b1b;margin-right:4px">🗑️</button>' +
|
||
'<button class="btn btn-sm" onclick="gerarQRCode(' + ins.id + ')" style="background:#f3f4f6">📱 QR Code</button></td></tr>';
|
||
}).join('') + '</tbody></table>';
|
||
}
|
||
|
||
window.mostrarModalConexao = function() {
|
||
document.getElementById('editConexaoId').value = '';
|
||
document.getElementById('conNome').value = '';
|
||
document.getElementById('conUrl').value = 'https://evoatende.c2sistemas.com.br';
|
||
document.getElementById('conApiKey').value = '';
|
||
document.getElementById('conInstance').value = '';
|
||
document.getElementById('modalConexaoTitle').textContent = 'Nova Conexão WhatsApp';
|
||
document.getElementById('btnSalvarConexao').textContent = 'Conectar';
|
||
document.getElementById('modalConexao').style.display = 'flex';
|
||
};
|
||
|
||
window.gerarQRCode = async function(id) {
|
||
var r = await api('/evolution/qrcode/' + id, { method: 'POST' });
|
||
if (r.success && r.data && (r.data.qrcode || r.data.base64)) {
|
||
var qr = r.data.qrcode || r.data.base64;
|
||
var imgSrc = qr.startsWith('data:') ? qr : 'data:image/png;base64,' + qr;
|
||
var w = window.open('', '_blank', 'width=400,height=500');
|
||
w.document.write('<html><head><title>QR Code</title></head><body style="display:flex;flex-direction:column;align-items:center;justify-content:center;height:100vh;font-family:sans-serif">' +
|
||
'<h2 style="margin-bottom:20px">Escaneie o QR Code</h2>' +
|
||
'<img src="' + imgSrc + '" style="max-width:300px">' +
|
||
'<p style="margin-top:20px;color:#6b7280">Abra o WhatsApp no celular e escaneie</p></body></html>');
|
||
} else {
|
||
alert('Erro ao gerar QR Code: ' + JSON.stringify(r.data));
|
||
}
|
||
};
|
||
|
||
// ===== EDITAR CONEXÃO =====
|
||
window.editarConexao = async function(id) {
|
||
// Busca dados atuais da API
|
||
var data = await api('/evolution/instances?empresaId=' + empresaId);
|
||
if (!data.success) return alert('Erro ao carregar dados');
|
||
var ins = data.data.find(function(i) { return i.id === id; });
|
||
if (!ins) return alert('Instância não encontrada');
|
||
|
||
document.getElementById('editConexaoId').value = id;
|
||
document.getElementById('conNome').value = ins.nome;
|
||
document.getElementById('conUrl').value = ins.url;
|
||
document.getElementById('conApiKey').value = ins.apiKey;
|
||
document.getElementById('conInstance').value = ins.instanceName;
|
||
document.getElementById('modalConexaoTitle').textContent = 'Editar Conexão WhatsApp';
|
||
document.getElementById('btnSalvarConexao').textContent = 'Salvar';
|
||
document.getElementById('modalConexao').style.display = 'flex';
|
||
};
|
||
|
||
// ===== EXCLUIR CONEXÃO =====
|
||
window.excluirConexao = async function(id, nome) {
|
||
if (!confirm('Excluir a conexão "' + nome + '"?')) return;
|
||
var r = await api('/evolution/instances/' + id, { method: 'DELETE' });
|
||
if (r.success) {
|
||
carregarConexoes();
|
||
} else {
|
||
alert('Erro: ' + r.error);
|
||
}
|
||
};
|
||
|
||
window.salvarConexao = async function() {
|
||
var editId = document.getElementById('editConexaoId').value;
|
||
var data = {
|
||
INS_NOME: document.getElementById('conNome').value.trim(),
|
||
INS_URL: document.getElementById('conUrl').value.trim(),
|
||
INS_API_KEY: document.getElementById('conApiKey').value.trim(),
|
||
INS_INSTANCE_NAME: document.getElementById('conInstance').value.trim(),
|
||
};
|
||
|
||
if (!data.INS_NOME || !data.INS_URL || !data.INS_API_KEY || !data.INS_INSTANCE_NAME)
|
||
return alert('Preencha todos os campos');
|
||
|
||
var r;
|
||
if (editId) {
|
||
// Atualizar
|
||
r = await api('/evolution/instances/' + editId, { method: 'PUT', body: JSON.stringify(data) });
|
||
} else {
|
||
// Criar nova
|
||
data.INS_EMPRESA_ID = empresaId;
|
||
r = await api('/evolution/connect', { method: 'POST', body: JSON.stringify(data) });
|
||
}
|
||
|
||
if (r.success) {
|
||
fecharModal('modalConexao');
|
||
document.getElementById('editConexaoId').value = '';
|
||
document.getElementById('modalConexaoTitle').textContent = 'Nova Conexão WhatsApp';
|
||
document.getElementById('btnSalvarConexao').textContent = 'Conectar';
|
||
carregarConexoes();
|
||
if (!editId && r.data && r.data.id) gerarQRCode(r.data.id);
|
||
} else {
|
||
alert('Erro: ' + r.error);
|
||
}
|
||
};
|
||
|
||
// ===== MODAIS =====
|
||
window.fecharModal = function(id) { document.getElementById(id).style.display = 'none'; };
|
||
|
||
// Fechar modal ao clicar fora
|
||
document.querySelectorAll('.modal-overlay').forEach(function(el) {
|
||
el.addEventListener('click', function(e) { if (e.target === this) this.style.display = 'none'; });
|
||
});
|
||
|
||
// ===== INICIAR =====
|
||
carregarEquipes();
|
||
carregarUsuarios();
|
||
carregarMenus();
|
||
carregarEtiquetas();
|
||
carregarConexoes();
|
||
carregarConfig();
|
||
carregarResolucao();
|
||
|
||
})();
|
||
</script>
|
||
<script src="/js/dark-mode.js"></script>
|
||
</body>
|
||
</html>
|