Carry over pre-existing WABA outreach automation WIP

This work already existed uncommitted in the main working tree (not
authored by this branch) and is required as a runtime dependency for the
campaign outreach port (zpro-client, templates, outreach routes/UI). Copied
in as-is, untouched, so this feature branch has a working baseline; the
original uncommitted state in the main checkout is left exactly as it was.
This commit is contained in:
Gustavo
2026-08-01 10:12:25 -03:00
parent 0894ab68b3
commit 4f736562f3
33 changed files with 3537 additions and 342 deletions
+135 -10
View File
@@ -5,12 +5,12 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GTI Máquina Comercial</title>
<link rel="stylesheet" href="/css/app.css">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🎯</text></svg>">
<link rel="icon" href="/img/logo-gti.png">
</head>
<body>
<header class="topbar">
<div class="brand">
<span class="brand-mark">GTI</span>
<img class="brand-mark" src="/img/logo-gti.png" alt="GTI">
<span class="brand-name">Máquina Comercial</span>
</div>
<nav class="tabs" role="tablist">
@@ -206,7 +206,7 @@
<table id="tabela-leads">
<thead>
<tr>
<th>Empresa</th><th>WhatsApp</th><th>Cidade</th><th>Nicho</th>
<th class="acao-col">Ação</th><th>Empresa</th><th>WhatsApp</th><th>Cidade</th><th>Nicho</th>
<th>Prioridade</th><th class="num">Geral</th>
<th>Classificação</th><th>Produto</th><th>Exportado</th>
</tr>
@@ -283,9 +283,131 @@
<!-- Modal de configurações -->
<dialog id="modal-settings">
<form method="dialog" class="modal-body">
<h2>Configurações</h2>
<div class="field">
<label>Padrões Z-PRO (usados nas exportações)</label>
<div class="settings-header">
<div>
<h2>Configurações</h2>
<p class="muted">Ajustes de envio, credenciais Z-PRO e preferências comerciais.</p>
</div>
<span class="chip" id="outreach-status"></span>
</div>
<section class="settings-card settings-principal">
<div>
<label class="settings-title">Envio WhatsApp</label>
<p class="muted">O limite vale para envios manuais e automáticos feitos hoje.</p>
</div>
<div class="settings-controls">
<label class="toggle"><input type="checkbox" id="outreach-ativo"> Automação ativa</label>
<label>Limite por dia <input type="number" id="outreach-limite" min="1"></label>
</div>
</section>
<details class="settings-section" open>
<summary>Enviar mensagem manual</summary>
<p class="muted">Cria ou reutiliza um ticket no painel Z-PRO e respeita o limite diário.</p>
<div class="manual-send-card">
<label class="full">Número do WhatsApp
<input type="text" id="manual-numero" placeholder="5511999999999" inputmode="numeric">
</label>
<div class="manual-channel full" aria-label="Canal de envio manual">
<label class="radio"><input type="radio" name="manual-canal" id="manual-canal-naooficial" value="nao_oficial" checked> Não-oficial (texto livre)</label>
<label class="radio"><input type="radio" name="manual-canal" id="manual-canal-oficial" value="oficial"> Oficial (Meta, template aprovado)</label>
</div>
<label class="full" id="manual-mensagem-wrap">Mensagem
<textarea id="manual-mensagem" rows="2" placeholder="Digite a mensagem de texto livre..."></textarea>
</label>
<div id="manual-oficial-campos" class="hidden full">
<label class="full">Escolher modelo salvo
<select id="manual-template-biblioteca">
<option value="">Selecione um template...</option>
</select>
</label>
<div class="row full">
<button class="btn-ghost btn-sm" id="btn-testar-template-biblioteca" type="button">Testar modelo selecionado</button>
<span class="muted">Usa o número informado acima e variáveis de exemplo.</span>
</div>
<label>Template aprovado
<input type="text" id="manual-template-nome" placeholder="ex.: confirma_suporte">
</label>
<label>Idioma
<input type="text" id="manual-template-idioma" value="pt_BR">
</label>
<label>Rota Z-PRO
<select id="manual-template-rota">
<option value="template">Template padrão</option>
<option value="templateBody">Utility/Body</option>
<option value="templateMarketingBody">Marketing/Body</option>
</select>
</label>
<div class="template-vars full">
<label>Variáveis do template</label>
<p class="muted">Preencha na mesma ordem do template: {{1}}, {{2}}, {{3}}...</p>
<div class="variable-helper">
<select id="manual-variable-picker">
<option value="">Inserir variável da Máquina Comercial...</option>
</select>
<span class="muted">Clique em um campo abaixo e escolha uma variável.</span>
</div>
<div class="template-vars-grid">
<label class="template-var-field">Variável {{1}} <input type="text" class="manual-template-var" id="manual-template-var1" data-var-index="1" placeholder="Ex.: Gustavo"></label>
<label class="template-var-field">Variável {{2}} <input type="text" class="manual-template-var" data-var-index="2" placeholder="Ex.: Suporte GLPI #123"></label>
<label class="template-var-field">Variável {{3}} <input type="text" class="manual-template-var" data-var-index="3"></label>
<label class="template-var-field">Variável {{4}} <input type="text" class="manual-template-var" data-var-index="4"></label>
<label class="template-var-field">Variável {{5}} <input type="text" class="manual-template-var" data-var-index="5"></label>
</div>
<div class="template-preview" id="manual-template-preview">Selecione um template para ver a pré-visualização.</div>
</div>
</div>
<div class="manual-actions full">
<span class="muted" id="manual-status"></span>
<button class="btn btn-primary" id="btn-enviar-manual" type="button">Enviar mensagem</button>
</div>
<button class="btn-ghost btn-sm" id="btn-toggle-outreach-log" type="button">Ver log de envios</button>
<div id="outreach-ultimos" class="lista hidden full"></div>
</div>
</details>
<details class="settings-section">
<summary>Templates automáticos</summary>
<p class="muted">Mensagens usadas quando a automação estiver ativada. Uma por produto recomendado.</p>
<div class="template-sync-inline">
<span class="muted" id="waba-template-library-status">Carregando biblioteca de templates...</span>
<button class="btn-ghost btn-sm" id="btn-sync-gchat-templates-inline" type="button">Atualizar lista do GChat</button>
</div>
<div id="outreach-templates" class="lista"></div>
<div class="row space-between">
<span></span>
<button class="btn-ghost" id="btn-salvar-outreach" type="button">Salvar templates</button>
</div>
</details>
<details class="settings-section">
<summary>Credenciais Z-PRO</summary>
<p class="muted">Use os dados de Admin &gt; API do Z-PRO. Pode colar a Base URL com ou sem <code>https://</code>.</p>
<div class="row">
<label>Base URL <input type="text" id="cfg-zpro-baseurl" placeholder="seu-dominio-zpro.com.br"></label>
<label>API ID <input type="text" id="cfg-zpro-apiid"></label>
</div>
<div class="row">
<label>Token <input type="password" id="cfg-zpro-token" autocomplete="off"></label>
<label>WhatsApp ID <input type="text" id="cfg-zpro-whatsappid"></label>
</div>
<div class="row space-between">
<span class="muted" id="zpro-credenciais-status"></span>
<button class="btn-ghost" id="btn-testar-zpro" type="button">Testar conexão</button>
</div>
<div class="template-sync-box">
<label>URL de templates do GChat <input type="text" id="cfg-gchat-templates-url" placeholder="https://apigchat.gtigrupo.com.br/...templates..."></label>
<label>Token GChat opcional <input type="password" id="cfg-gchat-token" autocomplete="off"></label>
<div class="row space-between">
<span class="muted" id="gchat-template-sync-status"></span>
<button class="btn-ghost" id="btn-sync-gchat-templates" type="button">Sincronizar templates</button>
</div>
</div>
</details>
<details class="settings-section">
<summary>Padrões de exportação e ticket</summary>
<div class="row">
<label>Pipeline <input type="number" id="cfg-pipeline" min="1"></label>
<label>Etapa <input type="number" id="cfg-stage" min="1"></label>
@@ -293,13 +415,15 @@
</div>
<div class="row">
<label>Previsão de fechamento (dias) <input type="number" id="cfg-forecast" min="1"></label>
<label>Fila ticket manual <input type="number" id="cfg-ticket-queue" min="1"></label>
</div>
</div>
<div class="field zona-risco">
<label>Zona de risco</label>
</details>
<details class="settings-section zona-risco">
<summary>Zona de risco</summary>
<p class="muted">Apaga permanentemente todos os leads, exportações, capturas e extrações. Configurações e nichos não são afetados.</p>
<button class="btn-danger" id="btn-limpar-base" type="button">🗑️ Limpar toda a base de leads</button>
</div>
</details>
<div class="row space-between">
<button class="btn-ghost" value="cancel">Fechar</button>
<button class="btn btn-primary" id="btn-salvar-settings" value="default">Salvar</button>
@@ -315,6 +439,7 @@
<div class="field">
<label>Senha de segurança <input type="password" id="reset-base-senha" autocomplete="off"></label>
</div>
<p class="muted erro hidden" id="reset-base-erro"></p>
<div class="row space-between">
<button class="btn-ghost" id="btn-cancelar-reset-base" type="button">Cancelar</button>
<button class="btn-danger" id="btn-confirmar-reset-base" type="button">Confirmar limpeza</button>