atualizacoes
This commit is contained in:
+143
-38
@@ -26,8 +26,17 @@ body { background:var(--surface-3); display:flex; min-height:100vh; }
|
||||
.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:var(--danger-text); }
|
||||
.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); }
|
||||
@@ -51,7 +60,7 @@ body { background:var(--surface-3); display:flex; min-height:100vh; }
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/css/dark-mode.css">
|
||||
<script>if(localStorage.getItem("chatc2_dark_mode")==="true")document.documentElement.classList.add("dark-mode-pending")</script>
|
||||
<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">
|
||||
@@ -169,12 +178,34 @@ body { background:var(--surface-3); display:flex; min-height:100vh; }
|
||||
|
||||
<!-- Modal Equipe -->
|
||||
<div class="modal-overlay" id="modalEquipe">
|
||||
<div class="modal" style="max-width:400px">
|
||||
<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><input type="number" id="equipeOrdem" value="0" min="0" style="width:80px"><span style="font-size:12px;color:var(--text-faint);margin-left:8px">(menor = aparece primeiro)</span></div>
|
||||
<div class="form-group"><label>Membros</label><div id="equipeMembros"></div></div>
|
||||
<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>
|
||||
@@ -185,7 +216,7 @@ body { background:var(--surface-3); display:flex; min-height:100vh; }
|
||||
|
||||
<!-- Modal Etiqueta -->
|
||||
<div class="modal-overlay" id="modalEtiqueta">
|
||||
<div class="modal" style="max-width:400px">
|
||||
<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>
|
||||
@@ -200,7 +231,7 @@ body { background:var(--surface-3); display:flex; min-height:100vh; }
|
||||
|
||||
<!-- Modal Menu -->
|
||||
<div class="modal-overlay" id="modalMenu">
|
||||
<div class="modal" style="max-width:500px">
|
||||
<div class="modal-box" style="max-width:520px">
|
||||
<h3 id="modalMenuTitle">Novo Submenu</h3>
|
||||
<input type="hidden" id="editMenuId">
|
||||
<input type="hidden" id="editMenuEquipeId">
|
||||
@@ -241,7 +272,7 @@ body { background:var(--surface-3); display:flex; min-height:100vh; }
|
||||
|
||||
<!-- Modal Conexão -->
|
||||
<div class="modal-overlay" id="modalConexao">
|
||||
<div class="modal" style="max-width:500px">
|
||||
<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>
|
||||
@@ -311,6 +342,41 @@ window.ativarAba = function(aba, btn) {
|
||||
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);
|
||||
@@ -322,9 +388,10 @@ async function carregarEquipes() {
|
||||
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,"\\'") + '\')" style="background:var(--surface-3);margin-right:4px">✏️</button>' +
|
||||
'<button class="btn btn-sm btn-danger" onclick="excluirEquipe(' + eq.id + ')">🗑️</button></td></tr>';
|
||||
'<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>';
|
||||
}
|
||||
|
||||
@@ -332,16 +399,22 @@ 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 = function(id, ordem, nome) {
|
||||
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');
|
||||
};
|
||||
@@ -364,27 +437,41 @@ async function carregarUsuariosCheckbox(equipeId) {
|
||||
}).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 }) });
|
||||
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 }) });
|
||||
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) {
|
||||
if (!confirm('Excluir esta equipe?')) return;
|
||||
var r = await api('/teams/' + id, { method: 'DELETE' });
|
||||
if (r.success) 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 =====
|
||||
@@ -649,9 +736,10 @@ window.salvarMenu = async function() {
|
||||
};
|
||||
|
||||
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();
|
||||
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 =====
|
||||
@@ -666,7 +754,7 @@ async function carregarEtiquetas() {
|
||||
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 + ')">🗑️</button></td></tr>';
|
||||
'<button class="btn btn-sm btn-danger" onclick="excluirEtiqueta(' + l.id + ',\'' + l.nome.replace(/'/g,"\\'") + '\')">🗑️</button></td></tr>';
|
||||
}).join('') + '</tbody></table>';
|
||||
}
|
||||
|
||||
@@ -701,10 +789,11 @@ window.salvarEtiqueta = async function() {
|
||||
}
|
||||
};
|
||||
|
||||
window.excluirEtiqueta = async function(id) {
|
||||
if (!confirm('Excluir esta etiqueta?')) return;
|
||||
var r = await api('/labels/' + id, { method: 'DELETE' });
|
||||
if (r.success) 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 =====
|
||||
@@ -784,7 +873,7 @@ async function carregarResolucao() {
|
||||
? 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 + ')">🗑️</button></div>';
|
||||
'<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>';
|
||||
}
|
||||
@@ -806,10 +895,11 @@ window.adicionarMotivo = async function() {
|
||||
if (r.success) { inp.value = ''; carregarResolucao(); } else mostrarFeedbackResolucao(r.error || 'Erro ao adicionar motivo', 'erro');
|
||||
};
|
||||
|
||||
window.removerMotivo = async function(id) {
|
||||
if (!confirm('Remover este motivo?')) return;
|
||||
var r = await api('/motivos/' + id, { method: 'DELETE' });
|
||||
if (r.success) carregarResolucao(); else mostrarFeedbackResolucao(r.error || 'Erro ao remover', '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) {
|
||||
@@ -899,13 +989,11 @@ window.editarConexao = async function(id) {
|
||||
|
||||
// ===== 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 {
|
||||
mostrarFeedbackModal('conexaoFeedback', 'Erro: ' + r.error, 'erro');
|
||||
}
|
||||
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() {
|
||||
@@ -969,6 +1057,23 @@ 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>
|
||||
|
||||
Reference in New Issue
Block a user