Adiciona Fluxo de Resolução (motivo + resolução do atendimento)
- Settings > Fluxo: cadastro de motivos e flags (visualizar/obrigatório para motivo e resolução) - Tela de conversa: dropdown de motivos + campo de resolução abaixo dos dados do titular, exibidos conforme configuração - Finalização valida obrigatoriedade (front e backend) e salva CON_MOTIVO_ID/CON_RESOLUCAO - Estrutura criada de forma idempotente (Postgres/Firebird) em src/resolucaoSetup.js; CRUD de motivos restrito a gerente Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -85,6 +85,28 @@ window.darkModeIsDark=function(){return localStorage.getItem('chatc2_dark_mode')
|
||||
</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 -->
|
||||
@@ -725,6 +747,57 @@ window.salvarConfig = async function() {
|
||||
|
||||
// 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);
|
||||
@@ -850,6 +923,7 @@ carregarMenus();
|
||||
carregarEtiquetas();
|
||||
carregarConexoes();
|
||||
carregarConfig();
|
||||
carregarResolucao();
|
||||
|
||||
})();
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user