Воронка пейвола, «Ожидают оплаты», публичная оферта, внешние алерты

- WEB_FUNNEL: paywall_shown/pay_click (фронт, /api/track) + pay_success (серверно);
  в админке раздел «Воронка пейвола» с конверсией шагов (30 дн / всего)
- Раздел «Ожидают оплаты» — придержанные файлы (awaiting_payment) как лиды
- /offer|/oferta: публичная оферта (подписка, автопродление, возвраты); ссылки в футере
  (7 языков) и в пейволе («Оплачивая, вы принимаете условия…»)
- POST /api/alert (ALERT_TOKEN, антифлуд 60с) → Telegram владельцу; используется скриптом
  лечения туннеля на vds178

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
berkio_admin_gitea
2026-07-07 14:25:15 +00:00
parent ee5ef3f08b
commit 39b45d3a64
2 changed files with 248 additions and 1 deletions

View File

@@ -1113,6 +1113,7 @@
<input type="checkbox" id="paywall-autorenew" checked style="width:16px;height:16px;cursor:pointer">
<span data-i18n="paywall_autorenew">Продлевать автоматически каждый месяц</span>
</label>
<div style="font-size:11.5px;color:var(--text-secondary);margin-top:8px"><span data-i18n="paywall_offer">Оплачивая, вы принимаете условия</span> <a href="/offer" target="_blank" style="color:var(--blue)" data-i18n="paywall_offer_link">публичной оферты</a></div>
<div id="paywall-msg" style="font-size:12px;color:var(--text-secondary);margin-top:10px"></div>
<button onclick="resetApp()" style="margin-top:8px;background:none;border:none;color:var(--text-secondary);font-size:13px;cursor:pointer;text-decoration:underline;font-family:inherit" data-i18n="paywall_cancel">Отмена</button>
</div>
@@ -1223,7 +1224,7 @@
</section>
<footer>
pdf2scan &mdash; <span data-i18n="footer_text">превращаем PDF в скан</span> &nbsp;|&nbsp; <a href="https://t.me/pdf2scan_bot" style="color:var(--blue); text-decoration:none;" data-i18n="footer_tg">Telegram-бот</a> &nbsp;|&nbsp; <a href="/developers" style="color:var(--blue); text-decoration:none;" data-i18n="footer_api">API для бизнеса</a> &nbsp;|&nbsp; <a href="#" onclick="showDonateCard(false);document.getElementById('donate-card').scrollIntoView({behavior:'smooth'});return false;" style="color:var(--blue); text-decoration:none;" data-i18n="footer_donate">🍩 Поддержать</a>
pdf2scan &mdash; <span data-i18n="footer_text">превращаем PDF в скан</span> &nbsp;|&nbsp; <a href="https://t.me/pdf2scan_bot" style="color:var(--blue); text-decoration:none;" data-i18n="footer_tg">Telegram-бот</a> &nbsp;|&nbsp; <a href="/developers" style="color:var(--blue); text-decoration:none;" data-i18n="footer_api">API для бизнеса</a> &nbsp;|&nbsp; <a href="#" onclick="showDonateCard(false);document.getElementById('donate-card').scrollIntoView({behavior:'smooth'});return false;" style="color:var(--blue); text-decoration:none;" data-i18n="footer_donate">🍩 Поддержать</a> &nbsp;|&nbsp; <a href="/offer" style="color:var(--blue); text-decoration:none;" data-i18n="footer_offer">Оферта</a>
</footer>
<script>
@@ -1323,6 +1324,9 @@
footer_tg: 'Telegram-бот',
footer_api: 'API для бизнеса',
footer_donate: '🍩 Поддержать',
footer_offer: 'Оферта',
paywall_offer: 'Оплачивая, вы принимаете условия',
paywall_offer_link: 'публичной оферты',
err_no_file: 'Файл не выбран',
err_task_not_found:'Задача не найдена. Попробуйте отправить файл снова.',
err_network: 'Ошибка сети при загрузке файла',
@@ -1467,6 +1471,9 @@
footer_tg: 'Telegram bot',
footer_api: 'API for business',
footer_donate: '🍩 Support',
footer_offer: 'Terms',
paywall_offer: 'By paying you accept the',
paywall_offer_link: 'public offer terms',
err_no_file: 'No file selected',
err_task_not_found:'Task not found. Please try submitting the file again.',
err_network: 'Network error while uploading',
@@ -1612,6 +1619,9 @@
footer_tg: 'Telegram-Bot',
footer_api: 'API für Unternehmen',
footer_donate: '🍩 Unterstützen',
footer_offer: 'AGB',
paywall_offer: 'Mit der Zahlung akzeptieren Sie die',
paywall_offer_link: 'Angebotsbedingungen',
err_no_file: 'Keine Datei ausgewählt',
err_task_not_found:'Aufgabe nicht gefunden. Bitte versuchen Sie, die Datei erneut zu senden.',
err_network: 'Netzwerkfehler beim Hochladen',
@@ -1757,6 +1767,9 @@
footer_tg: 'Bot Telegram',
footer_api: 'API pour entreprises',
footer_donate: '🍩 Soutenir',
footer_offer: 'Conditions',
paywall_offer: 'En payant vous acceptez les',
paywall_offer_link: 'conditions générales',
err_no_file: 'Aucun fichier sélectionné',
err_task_not_found:'Tâche introuvable. Veuillez soumettre le fichier à nouveau.',
err_network: 'Erreur réseau lors du téléchargement',
@@ -1902,6 +1915,9 @@
footer_tg: 'Bot Telegram',
footer_api: 'API per aziende',
footer_donate: '🍩 Sostieni',
footer_offer: 'Termini',
paywall_offer: 'Pagando accetti i',
paywall_offer_link: 'termini di offerta',
err_no_file: 'Nessun file selezionato',
err_task_not_found:'Attività non trovata. Prova a inviare nuovamente il file.',
err_network: 'Errore di rete durante il caricamento',
@@ -2047,6 +2063,9 @@
footer_tg: 'Bot de Telegram',
footer_api: 'API para empresas',
footer_donate: '🍩 Apoyar',
footer_offer: 'Términos',
paywall_offer: 'Al pagar aceptas los',
paywall_offer_link: 'términos de la oferta',
err_no_file: 'Ningún archivo seleccionado',
err_task_not_found:'Tarea no encontrada. Intenta enviar el archivo de nuevo.',
err_network: 'Error de red al subir',
@@ -2192,6 +2211,9 @@
footer_tg: 'Bot do Telegram',
footer_api: 'API para empresas',
footer_donate: '🍩 Apoiar',
footer_offer: 'Termos',
paywall_offer: 'Ao pagar você aceita os',
paywall_offer_link: 'termos da oferta',
err_no_file: 'Nenhum arquivo selecionado',
err_task_not_found:'Tarefa não encontrada. Tente enviar o arquivo novamente.',
err_network: 'Erro de rede ao fazer upload',
@@ -2391,7 +2413,12 @@
} catch (e) { return { requires_payment: false, sub_active: false, paywall_enabled: false, file_price: 99, sub_price: 299 }; }
}
function track(event) {
try { fetch('/api/track', { method: 'POST', keepalive: true, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ event: event }) }).catch(function(){}); } catch (_) {}
}
function showPaywall(jobId, filePrice, subPrice, mode) {
track('paywall_shown');
paywallMode = mode || 'file';
paywallJob = jobId;
paywallFilePrice = filePrice || 99;
@@ -2420,6 +2447,7 @@
}
async function _payViaKassa(purpose) {
track('pay_click');
const email = (document.getElementById('paywall-email').value || '').trim();
const msg = document.getElementById('paywall-msg');
if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email)) { msg.textContent = t('pay_need_email'); return; }