1088 lines
57 KiB
HTML
1088 lines
57 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:var(--surface-3); 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 var(--surface-3); }
|
||
.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:var(--text-muted); font-weight:500; }
|
||
.tabs button:hover { background:var(--surface-2); color:var(--text-secondary); }
|
||
.tabs button.active { border-bottom-color:var(--primary); color:var(--primary); 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:var(--text-secondary); margin-bottom:5px; }
|
||
.form-group input, .form-group select, .form-group textarea { width:100%; padding:10px 14px; border:2px solid var(--border); border-radius:8px; font-size:14px; outline:none; background:var(--surface-2); color:var(--text-primary); transition:all .15s; font-family:inherit; }
|
||
.form-group input:focus, .form-group select:focus, .form-group textarea:focus { border-color:var(--primary); 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:var(--primary); color:#fff; }
|
||
.btn-primary:hover { background:var(--primary-dark); }
|
||
.btn-secondary {
|
||
display: inline-flex; align-items: center; gap: 6px;
|
||
padding: 10px 20px; border: 1px solid var(--border);
|
||
border-radius: 8px; font-size: 14px; font-weight: 600;
|
||
cursor: pointer; transition: all .15s;
|
||
background: var(--surface); color: var(--text-secondary);
|
||
}
|
||
.btn-secondary:hover { background: var(--surface-2); border-color: #d1d5db; }
|
||
.btn-danger { background:var(--danger); color:#fff; }
|
||
.btn-danger:hover { background:#dc2626; }
|
||
.btn-danger:disabled { opacity:0.5; cursor:not-allowed; background:var(--danger); }
|
||
.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:var(--success-bg); color:var(--success-text); }
|
||
.badge-danger { background:var(--danger-bg); color:var(--danger-text); }
|
||
.user-info { display:flex; align-items:center; gap:14px; }
|
||
.user-name { font-size:14px; font-weight:500; color:var(--text-secondary); }
|
||
.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:var(--success-bg); color:var(--success-text); }
|
||
|
||
.feedback-msg {
|
||
padding: 8px 14px; border-radius: 6px; font-size: 13px;
|
||
margin-bottom: 8px; display: none;
|
||
}
|
||
.feedback-msg.sucesso { background: var(--success-bg); color: var(--success-text); display: block; }
|
||
.feedback-msg.erro { background: var(--danger-bg); color: var(--danger-text); display: block; }
|
||
|
||
/* 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(){var m=localStorage.getItem("chatc2_dark_mode_manual");var d=m!==null?m==="true":window.matchMedia("(prefers-color-scheme: dark)").matches;if(d)document.documentElement.className="dark"})()</script>
|
||
</head>
|
||
<body>
|
||
<aside class="sidebar" role="navigation" aria-label="Navegação principal">
|
||
<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" aria-label="Alternar modo escuro">🌙 Escuro</button>
|
||
<a onclick="logout()" aria-label="Sair do sistema"><span class="icon">🚪</span> Sair</a></div>
|
||
</aside>
|
||
<main class="main" id="main-content">
|
||
<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:var(--text-muted);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:var(--text-faint)">Carregando...</p></div>
|
||
</div>
|
||
|
||
<div class="card" id="cardResolucao">
|
||
<h3 style="margin:0 0 8px">🧩 Fluxo de Resolução</h3>
|
||
<p style="color:var(--text-muted);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:var(--text-faint);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>
|
||
|
||
<div id="resolucaoFeedback" class="feedback-msg"></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:var(--text-faint)">Carregando...</p></div>
|
||
</div>
|
||
<div class="card">
|
||
<h3>Usuários da Empresa</h3>
|
||
<div id="usuariosList"><p style="color:var(--text-faint)">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:var(--text-faint)">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:var(--text-faint)">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:var(--text-faint)">Carregando...</p></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modal Equipe -->
|
||
<div class="modal-overlay" id="modalEquipe">
|
||
<div class="modal-box" style="max-width:480px">
|
||
<h3 id="modalEquipeTitle">Nova Equipe</h3>
|
||
<input type="hidden" id="editEquipeId">
|
||
<div class="form-group">
|
||
<label for="equipeNome">Nome da Equipe</label>
|
||
<input type="text" id="equipeNome" placeholder="Ex: Atendimento">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="equipeOrdem">Ordem</label>
|
||
<div style="display:flex;align-items:center;gap:8px">
|
||
<input type="number" id="equipeOrdem" value="0" min="0" style="width:80px">
|
||
<span style="font-size:12px;color:var(--text-faint)">Menor = aparece primeiro</span>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="equipeMensagem">Mensagem automática</label>
|
||
<textarea id="equipeMensagem" rows="2" placeholder="Mensagem enviada quando o cliente escolhe esta equipe..."></textarea>
|
||
<span style="font-size:11px;color:var(--text-faint);margin-top:4px;display:block">Opcional. Se preenchida, será enviada ao cliente após escolher esta opção.</span>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="equipeEtiqueta">Etiqueta automática</label>
|
||
<select id="equipeEtiqueta"><option value="">Nenhuma</option></select>
|
||
<span style="font-size:11px;color:var(--text-faint);margin-top:4px;display:block">Opcional. Etiqueta adicionada automaticamente à conversa.</span>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Membros</label>
|
||
<div id="equipeMembros"></div>
|
||
</div>
|
||
<div id="equipeFeedback" class="feedback-msg"></div>
|
||
<div class="modal-footer">
|
||
<button class="btn-secondary" onclick="fecharModal('modalEquipe')">Cancelar</button>
|
||
<button class="btn-primary" onclick="salvarEquipe()">Salvar</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modal Etiqueta -->
|
||
<div class="modal-overlay" id="modalEtiqueta">
|
||
<div class="modal-box" style="max-width:400px">
|
||
<h3 id="modalEtiquetaTitle">Nova Etiqueta</h3>
|
||
<input type="hidden" id="editEtiquetaId">
|
||
<div class="form-group"><label for="etiquetaNome">Nome</label><input type="text" id="etiquetaNome" placeholder="Ex: Cliente VIP"></div>
|
||
<div class="form-group"><label for="etiquetaCor">Cor</label><input type="color" id="etiquetaCor" value="#667eea"></div>
|
||
<div id="etiquetaFeedback" class="feedback-msg"></div>
|
||
<div class="modal-footer">
|
||
<button class="btn-secondary" onclick="fecharModal('modalEtiqueta')">Cancelar</button>
|
||
<button class="btn-primary" onclick="salvarEtiqueta()">Salvar</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modal Menu -->
|
||
<div class="modal-overlay" id="modalMenu">
|
||
<div class="modal-box" style="max-width:520px">
|
||
<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 for="menuEquipe">Equipe</label><select id="menuEquipe"><option value="">Selecione...</option></select></div>
|
||
<div class="form-group"><label for="menuTitulo">Título</label><input type="text" id="menuTitulo" placeholder="Ex: Alteração Cadastral"></div>
|
||
<div class="form-group"><label for="menuTipo">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 for="menuTexto">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 for="menuAcaoRota">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 for="menuAcaoPrompt">Pergunta ao cliente (se precisar de dados)</label>
|
||
<textarea id="menuAcaoPrompt" rows="2" placeholder="Ex: Informe seu novo e-mail:"></textarea></div>
|
||
</div>
|
||
<div class="form-group"><label for="menuOrdem">Ordem</label><input type="number" id="menuOrdem" value="0" min="0" style="width:80px"></div>
|
||
<div class="form-group"><label for="menuPai">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 var(--border);border-radius:8px;min-height:36px"></div></div>
|
||
<div id="menuFeedback" class="feedback-msg"></div>
|
||
<div class="modal-footer">
|
||
<button class="btn-secondary" onclick="fecharModal('modalMenu')">Cancelar</button>
|
||
<button class="btn-primary" onclick="salvarMenu()">Salvar</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Modal Conexão -->
|
||
<div class="modal-overlay" id="modalConexao">
|
||
<div class="modal-box" style="max-width:520px">
|
||
<h3 id="modalConexaoTitle">Nova Conexão WhatsApp</h3>
|
||
<input type="hidden" id="editConexaoId">
|
||
<div class="form-group"><label for="conNome">Nome da Instância</label><input type="text" id="conNome" placeholder="Ex: WhatsApp Comercial"></div>
|
||
<div class="form-group"><label for="conUrl">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 for="conApiKey">API Key</label><input type="text" id="conApiKey" placeholder="API Key"></div>
|
||
<div class="form-group"><label for="conInstance">Nome da Instância (Evolution)</label><input type="text" id="conInstance" placeholder="Ex: empresa1-wpp"></div>
|
||
<div id="conexaoFeedback" class="feedback-msg"></div>
|
||
<div class="modal-footer">
|
||
<button class="btn-secondary" onclick="fecharModal('modalConexao')">Cancelar</button>
|
||
<button class="btn-primary" onclick="salvarConexao()" id="btnSalvarConexao">Conectar</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
(function(){
|
||
'use strict';
|
||
|
||
// Fechar modais com Esc
|
||
document.addEventListener('keydown', function(e) {
|
||
if (e.key === 'Escape') {
|
||
document.querySelectorAll('.modal-overlay.show, .modal.show').forEach(function(m) {
|
||
m.classList.remove('show');
|
||
});
|
||
}
|
||
});
|
||
|
||
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');
|
||
};
|
||
|
||
// ===== MODAL DE CONFIRMAÇÃO =====
|
||
let _confirmarCallback = null;
|
||
|
||
window.mostrarConfirmacao = function(titulo, mensagem, nomeConfirmar, callback) {
|
||
document.getElementById('confirmarTitulo').textContent = titulo;
|
||
document.getElementById('confirmarMensagem').textContent = mensagem;
|
||
document.getElementById('confirmarInput').value = '';
|
||
document.getElementById('confirmarInput').placeholder = 'Digite: ' + nomeConfirmar;
|
||
document.getElementById('btnConfirmarExclusao').disabled = true;
|
||
_confirmarCallback = callback;
|
||
_initConfirmModal();
|
||
document.getElementById('modalConfirmar').classList.add('show');
|
||
document.getElementById('confirmarInput').focus();
|
||
};
|
||
|
||
// Event listeners do modal de confirmação (inicializados após DOM pronto)
|
||
function _initConfirmModal() {
|
||
var inp = document.getElementById('confirmarInput');
|
||
if (!inp || inp._confirmInit) return;
|
||
inp._confirmInit = true;
|
||
inp.addEventListener('input', function() {
|
||
var esperado = this.placeholder.replace('Digite: ', '');
|
||
document.getElementById('btnConfirmarExclusao').disabled = this.value.trim() !== esperado;
|
||
});
|
||
inp.addEventListener('keydown', function(e) {
|
||
if (e.key === 'Enter' && !document.getElementById('btnConfirmarExclusao').disabled) {
|
||
document.getElementById('btnConfirmarExclusao').click();
|
||
}
|
||
});
|
||
document.getElementById('btnConfirmarExclusao').addEventListener('click', function() {
|
||
if (_confirmarCallback) { _confirmarCallback(); _confirmarCallback = null; }
|
||
fecharModal('modalConfirmar');
|
||
});
|
||
}
|
||
|
||
// ===== 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:var(--text-faint)">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(', ') || '-';
|
||
var mensagemEsc = (eq.mensagem || '').replace(/\\/g,'\\\\').replace(/'/g,"\\'");
|
||
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,"\\'") + '\',\'' + mensagemEsc + '\',' + (eq.etiquetaId || 'null') + ')" style="background:var(--surface-3);margin-right:4px">✏️</button>' +
|
||
'<button class="btn btn-sm btn-danger" onclick="excluirEquipe(' + eq.id + ',\'' + eq.nome.replace(/'/g,"\\'") + '\')">🗑️</button></td></tr>';
|
||
}).join('') + '</tbody></table>';
|
||
}
|
||
|
||
window.mostrarModalEquipe = function() {
|
||
document.getElementById('editEquipeId').value = '';
|
||
document.getElementById('equipeOrdem').value = 0;
|
||
document.getElementById('equipeNome').value = '';
|
||
document.getElementById('equipeMensagem').value = '';
|
||
document.getElementById('equipeEtiqueta').value = '';
|
||
document.getElementById('modalEquipeTitle').textContent = 'Nova Equipe';
|
||
carregarUsuariosCheckbox();
|
||
carregarEtiquetasDropdown();
|
||
document.getElementById('modalEquipe').classList.add('show');
|
||
};
|
||
|
||
window.editarEquipe = async function(id, ordem, nome, mensagem, etiquetaId) {
|
||
document.getElementById('editEquipeId').value = id;
|
||
document.getElementById('equipeOrdem').value = ordem;
|
||
document.getElementById('equipeNome').value = nome;
|
||
document.getElementById('equipeMensagem').value = mensagem || '';
|
||
document.getElementById('equipeEtiqueta').value = etiquetaId || '';
|
||
document.getElementById('modalEquipeTitle').textContent = 'Editar Equipe';
|
||
await carregarEtiquetasDropdown();
|
||
carregarUsuariosCheckbox(id);
|
||
document.getElementById('modalEquipe').classList.add('show');
|
||
};
|
||
|
||
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:var(--text-faint)">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('');
|
||
}
|
||
|
||
async function carregarEtiquetasDropdown() {
|
||
var sel = document.getElementById('equipeEtiqueta');
|
||
var data = await api('/labels?empresaId=' + empresaId);
|
||
sel.innerHTML = '<option value="">Nenhuma</option>';
|
||
if (data.success && data.data) {
|
||
data.data.forEach(function(l) {
|
||
sel.innerHTML += '<option value="' + l.id + '">' + l.nome + '</option>';
|
||
});
|
||
}
|
||
}
|
||
|
||
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); });
|
||
var mensagem = document.getElementById('equipeMensagem').value.trim();
|
||
var etiquetaId = document.getElementById('equipeEtiqueta').value || null;
|
||
|
||
if (!nome) { mostrarFeedbackModal('equipeFeedback', 'Informe o nome da equipe', 'erro'); return; }
|
||
|
||
if (id) {
|
||
var r = await api('/teams/' + id, { method: 'PUT', body: JSON.stringify({ nome: nome, ordem: ordem, membros: membros, mensagem: mensagem, etiquetaId: etiquetaId }) });
|
||
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, mensagem: mensagem, etiquetaId: etiquetaId }) });
|
||
if (r.success) { fecharModal('modalEquipe'); carregarEquipes(); }
|
||
}
|
||
};
|
||
|
||
window.excluirEquipe = async function(id, nome) {
|
||
mostrarConfirmacao('Excluir Equipe', 'Esta ação não pode ser desfeita. Todos os submenus vinculados serão perdidos.', nome || 'equipe', async function() {
|
||
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:var(--text-faint)">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:var(--text-faint)">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 var(--border);border-radius:8px;overflow:hidden">';
|
||
html += '<div style="background:var(--surface-2);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:var(--text-faint);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:var(--text-faint);font-size:11px">(' + m.tipo + ')</span></span>';
|
||
html += '<button class="btn btn-sm" onclick="mostrarModalMenu(' + m.equipeId + ',' + m.id + ')" style="background:var(--surface-3);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').classList.add('show');
|
||
};
|
||
|
||
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:var(--text-faint);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:var(--surface-3);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) { mostrarFeedbackModal('menuFeedback', 'Informe o título', 'erro'); return; }
|
||
if (!equipeId) { mostrarFeedbackModal('menuFeedback', 'Selecione a equipe', 'erro'); return; }
|
||
|
||
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 mostrarFeedbackModal('menuFeedback', 'Erro: ' + (r.error || 'desconhecido'), 'erro');
|
||
} else {
|
||
var r = await api('/menus', { method: 'POST', body: JSON.stringify(body) });
|
||
if (r.success) { fecharModal('modalMenu'); carregarMenus(); }
|
||
else mostrarFeedbackModal('menuFeedback', 'Erro: ' + (r.error || 'desconhecido'), 'erro');
|
||
}
|
||
};
|
||
|
||
window.excluirMenu = async function(id, titulo) {
|
||
mostrarConfirmacao('Excluir Submenu', 'O submenu "' + titulo + '" e todos os seus sub-itens serão removidos.', titulo, async function() {
|
||
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:var(--text-faint)">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:var(--surface-3);margin-right:4px">✏️</button>' +
|
||
'<button class="btn btn-sm btn-danger" onclick="excluirEtiqueta(' + l.id + ',\'' + l.nome.replace(/'/g,"\\'") + '\')">🗑️</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').classList.add('show');
|
||
};
|
||
|
||
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').classList.add('show');
|
||
};
|
||
|
||
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) { mostrarFeedbackModal('etiquetaFeedback', 'Informe o nome', 'erro'); return; }
|
||
|
||
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, nome) {
|
||
mostrarConfirmacao('Excluir Etiqueta', 'A etiqueta será removida permanentemente.', nome, async function() {
|
||
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:var(--surface-2);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="cfgResolucaoSalvarMSC" ' + (cfg.resolucaoSalvarMSC === 'S' ? 'checked' : '') + '> <label for="cfgResolucaoSalvarMSC">💾 Salvar resolução de atendimento na tabela MENSAGENS_CLIENTES (como aviso)</label></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>' +
|
||
'<div id="configFeedback" class="feedback-msg"></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,
|
||
resolucaoSalvarMSC: document.getElementById('cfgResolucaoSalvarMSC').checked ? 'S' : 'N',
|
||
};
|
||
|
||
var r = await api('/company/config', { method: 'POST', body: JSON.stringify(data) });
|
||
if (r.success) mostrarFeedbackModal('configFeedback', 'Configurações salvas com sucesso!', '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 var(--border);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 + ',\'' + escc(m.descricao).replace(/'/g,"\\'") + '\')">🗑️</button></div>';
|
||
}).join('')
|
||
: '<p style="color:var(--text-faint);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 mostrarFeedbackResolucao(r.error || 'Erro ao adicionar motivo', 'erro');
|
||
};
|
||
|
||
window.removerMotivo = async function(id, descricao) {
|
||
mostrarConfirmacao('Remover Motivo', 'O motivo será removido permanentemente.', descricao, async function() {
|
||
var r = await api('/motivos/' + id, { method: 'DELETE' });
|
||
if (r.success) carregarResolucao(); else mostrarFeedbackResolucao(r.error || 'Erro ao remover', 'erro');
|
||
});
|
||
};
|
||
|
||
function mostrarFeedbackResolucao(msg, tipo) {
|
||
var fb = document.getElementById('resolucaoFeedback');
|
||
if (!fb) return;
|
||
fb.textContent = msg;
|
||
fb.className = 'feedback-msg ' + tipo;
|
||
setTimeout(function() { fb.className = 'feedback-msg'; }, 4000);
|
||
}
|
||
|
||
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) mostrarFeedbackModal('resolucaoFeedback', 'Fluxo de Resolução salvo!', 'sucesso'); else mostrarFeedbackModal('resolucaoFeedback', r.error || 'Erro ao salvar', 'erro');
|
||
};
|
||
|
||
// ===== 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:var(--text-faint)">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:var(--surface-3);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:var(--surface-3)">📱 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').classList.add('show');
|
||
};
|
||
|
||
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:var(--text-muted)">Abra o WhatsApp no celular e escaneie</p></body></html>');
|
||
} else {
|
||
mostrarFeedbackModal('conexaoFeedback', 'Erro ao gerar QR Code', 'erro');
|
||
}
|
||
};
|
||
|
||
// ===== EDITAR CONEXÃO =====
|
||
window.editarConexao = async function(id) {
|
||
// Busca dados atuais da API
|
||
var data = await api('/evolution/instances?empresaId=' + empresaId);
|
||
if (!data.success) { mostrarFeedbackModal('conexaoFeedback', 'Erro ao carregar dados', 'erro'); return; }
|
||
var ins = data.data.find(function(i) { return i.id === id; });
|
||
if (!ins) { mostrarFeedbackModal('conexaoFeedback', 'Instância não encontrada', 'erro'); return; }
|
||
|
||
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').classList.add('show');
|
||
};
|
||
|
||
// ===== EXCLUIR CONEXÃO =====
|
||
window.excluirConexao = async function(id, nome) {
|
||
mostrarConfirmacao('Excluir Conexao', 'A conexao WhatsApp "' + nome + '" sera removida.', nome, async function() {
|
||
var r = await api('/evolution/instances/' + id, { method: 'DELETE' });
|
||
if (r.success) carregarConexoes();
|
||
else mostrarFeedbackModal('conexaoFeedback', 'Erro: ' + r.error, 'erro');
|
||
});
|
||
};
|
||
|
||
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)
|
||
mostrarFeedbackModal('conexaoFeedback', 'Preencha todos os campos', 'erro'); return;
|
||
|
||
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 {
|
||
mostrarFeedbackModal('conexaoFeedback', 'Erro: ' + r.error, 'erro');
|
||
}
|
||
};
|
||
|
||
// ===== MODAIS =====
|
||
window.fecharModal = function(id) { document.getElementById(id).classList.remove('show'); };
|
||
|
||
function mostrarFeedbackModal(elId, msg, tipo) {
|
||
var fb = document.getElementById(elId);
|
||
if (!fb) return;
|
||
fb.textContent = msg;
|
||
fb.className = 'feedback-msg ' + tipo;
|
||
setTimeout(function() { fb.className = 'feedback-msg'; }, 4000);
|
||
}
|
||
|
||
// Fechar modal ao clicar fora
|
||
document.querySelectorAll('.modal-overlay').forEach(function(el) {
|
||
el.addEventListener('click', function(e) { if (e.target === this) this.classList.remove('show'); });
|
||
});
|
||
|
||
// ===== INICIAR =====
|
||
carregarEquipes();
|
||
carregarUsuarios();
|
||
carregarMenus();
|
||
carregarEtiquetas();
|
||
carregarConexoes();
|
||
carregarConfig();
|
||
carregarResolucao();
|
||
|
||
})();
|
||
</script>
|
||
<!-- Modal Confirmação de Exclusão -->
|
||
<div class="modal-overlay" id="modalConfirmar">
|
||
<div class="modal-box" style="max-width:420px">
|
||
<h3 id="confirmarTitulo">Confirmar exclusão</h3>
|
||
<p id="confirmarMensagem" style="font-size:14px;color:var(--text-secondary);margin-bottom:14px;line-height:1.5"></p>
|
||
<div class="form-group">
|
||
<label for="confirmarInput" style="font-size:13px;font-weight:600;color:var(--text-secondary);margin-bottom:5px">Digite o nome para confirmar:</label>
|
||
<input type="text" id="confirmarInput" placeholder="Digite exatamente o nome..." style="width:100%;padding:10px 14px;border:2px solid var(--border);border-radius:8px;font-size:14px;outline:none;background:var(--surface-2);color:var(--text-primary);transition:all .15s" onfocus="this.style.borderColor='var(--primary)';this.style.background='var(--surface)'" onblur="this.style.borderColor='var(--border)';this.style.background='var(--surface-2)'">
|
||
</div>
|
||
<div id="confirmarFeedback" class="feedback-msg"></div>
|
||
<div class="modal-footer">
|
||
<button class="btn-secondary" onclick="fecharModal('modalConfirmar')">Cancelar</button>
|
||
<button class="btn-danger" id="btnConfirmarExclusao" disabled>Excluir</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="/js/dark-mode.js"></script>
|
||
<!-- impeccable-live-start -->
|
||
<script src="http://localhost:8400/live.js"></script>
|
||
<!-- impeccable-live-end -->
|
||
|
||
<!-- Bottom Tab Bar (mobile) -->
|
||
<script src="/js/tabbar.js"></script>
|
||
</body>
|
||
</html>
|