285 lines
10 KiB
JavaScript
285 lines
10 KiB
JavaScript
// ==UserScript==
|
|
// @name Автоподстановка лидов
|
|
// @namespace http://tampermonkey.net/
|
|
// @version 6.3
|
|
// @include https://admin2.gtn.ru/lead/newlead.php
|
|
// @updateURL http://10.8.25.20:8765/lead_autofill.user.js
|
|
// @downloadURL http://10.8.25.20:8765/lead_autofill.user.js
|
|
// @grant none
|
|
// ==/UserScript==
|
|
|
|
(function() {
|
|
'use strict';
|
|
|
|
const SERVER_URL = 'http://10.8.25.20:8765';
|
|
let lastQueueSize = 0;
|
|
|
|
// Получение следующего лида (первый из очереди)
|
|
async function fetchNextLead() {
|
|
try {
|
|
const res = await fetch(`${SERVER_URL}/lead`);
|
|
const data = await res.json();
|
|
if (data.lead) {
|
|
fillForm(data.lead);
|
|
showNotification(`Подставлено. Осталось: ${data.queue_size}`);
|
|
updateCounter(data.queue_size);
|
|
} else {
|
|
showNotification('Нет лидов в очереди');
|
|
}
|
|
} catch(e) {
|
|
console.error(e);
|
|
showNotification('Сервер не доступен');
|
|
}
|
|
}
|
|
|
|
// Получение лида по индексу (из меню)
|
|
async function fetchLeadByIndex(index) {
|
|
try {
|
|
const res = await fetch(`${SERVER_URL}/lead?index=${index}`);
|
|
const data = await res.json();
|
|
if (data.lead) {
|
|
fillForm(data.lead);
|
|
showNotification(`Подставлен выбранный лид. Осталось: ${data.queue_size}`);
|
|
updateCounter(data.queue_size);
|
|
} else {
|
|
showNotification('Ошибка при загрузке лида');
|
|
}
|
|
} catch(e) {
|
|
console.error(e);
|
|
showNotification('Сервер не доступен');
|
|
}
|
|
}
|
|
|
|
// Получение списка лидов для меню
|
|
async function fetchQueueList() {
|
|
try {
|
|
const res = await fetch(`${SERVER_URL}/queue_list`);
|
|
const data = await res.json();
|
|
return data.list || [];
|
|
} catch(e) {
|
|
console.error(e);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
// Обновление счётчика на кнопке
|
|
async function updateCounter(forceSize = null) {
|
|
try {
|
|
if (forceSize !== null) {
|
|
lastQueueSize = forceSize;
|
|
} else {
|
|
const res = await fetch(`${SERVER_URL}/queue`);
|
|
const data = await res.json();
|
|
lastQueueSize = data.size;
|
|
}
|
|
const btn = document.getElementById('lead-queue-btn');
|
|
if (btn) {
|
|
btn.innerHTML = `Лиды (${lastQueueSize})`;
|
|
btn.style.background = lastQueueSize > 0 ? '#4CAF50' : '#9E9E9E';
|
|
}
|
|
} catch(e) {
|
|
console.error('Ошибка обновления счётчика:', e);
|
|
const btn = document.getElementById('lead-queue-btn');
|
|
if (btn) {
|
|
btn.innerHTML = `?? Ошибка`;
|
|
btn.style.background = '#f44336';
|
|
}
|
|
}
|
|
}
|
|
|
|
// Заполнение формы
|
|
function fillForm(lead) {
|
|
// Имя
|
|
const firstName = document.querySelector('[name="first_name"]');
|
|
if (firstName && lead.first_name) firstName.value = lead.first_name;
|
|
|
|
// Фамилия
|
|
const surname = document.querySelector('[name="surname"]');
|
|
if (surname && lead.surname) surname.value = lead.surname;
|
|
|
|
// Отчество
|
|
const secondName = document.querySelector('[name="second_name"]');
|
|
if (secondName && lead.second_name) secondName.value = lead.second_name;
|
|
|
|
// Телефон (только цифры, без +7)
|
|
const phoneField = document.querySelector('[name="phone[0]"]');
|
|
if (phoneField && lead.phone) {
|
|
let cleanPhone = lead.phone.replace(/[^\d]/g, '');
|
|
if (cleanPhone.startsWith('7') && cleanPhone.length === 11) {
|
|
cleanPhone = cleanPhone.substring(1);
|
|
}
|
|
phoneField.value = cleanPhone;
|
|
}
|
|
|
|
// Email
|
|
const emailField = document.querySelector('[name="email[0]"]');
|
|
if (emailField && lead.email) emailField.value = lead.email;
|
|
|
|
// Город
|
|
if (lead.town) {
|
|
const select = document.querySelector('select[name="town_id"]');
|
|
if (select) {
|
|
for (let opt of select.options) {
|
|
if (opt.text.toLowerCase().includes(lead.town.toLowerCase())) {
|
|
select.value = opt.value;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Тип клиента
|
|
if (lead.client_type) {
|
|
const clientType = document.querySelector('#client_type, select[name="client_type_id"]');
|
|
if (clientType) {
|
|
const typeLower = lead.client_type.toLowerCase();
|
|
if (typeLower.includes('физическое') || typeLower.includes('физ')) {
|
|
clientType.value = '1';
|
|
} else if (typeLower.includes('юридическое') || typeLower.includes('юр')) {
|
|
clientType.value = '2';
|
|
}
|
|
}
|
|
}
|
|
|
|
// Всё в комментарий
|
|
const commentField = document.querySelector('[name="address_comment"]');
|
|
if (commentField && lead.addition) {
|
|
commentField.value = lead.addition;
|
|
}
|
|
|
|
console.log('Форма заполнена:', lead.first_name, lead.phone);
|
|
}
|
|
|
|
// Показать уведомление
|
|
function showNotification(text) {
|
|
const div = document.createElement('div');
|
|
div.textContent = text;
|
|
div.style.cssText = `
|
|
position: fixed;
|
|
top: 20px;
|
|
right: 20px;
|
|
background: #4CAF50;
|
|
color: white;
|
|
padding: 10px 20px;
|
|
border-radius: 5px;
|
|
z-index: 100000;
|
|
font-size: 14px;
|
|
font-family: sans-serif;
|
|
box-shadow: 0 2px 10px rgba(0,0,0,0.2);
|
|
`;
|
|
document.body.appendChild(div);
|
|
setTimeout(() => div.remove(), 3000);
|
|
}
|
|
|
|
// Показать меню со списком лидов
|
|
async function showMenu() {
|
|
const list = await fetchQueueList();
|
|
if (list.length === 0) {
|
|
showNotification('?? Нет лидов в очереди');
|
|
return;
|
|
}
|
|
|
|
// Удаляем старое меню, если есть
|
|
const oldMenu = document.getElementById('lead-menu');
|
|
if (oldMenu) oldMenu.remove();
|
|
|
|
let menuHtml = `
|
|
<div id="lead-menu" style="position:fixed; bottom:80px; right:20px; background:white; border:1px solid #ccc; border-radius:8px; box-shadow:0 2px 10px rgba(0,0,0,0.2); z-index:100000; width:320px; max-height:400px; overflow-y:auto;">
|
|
<div style="padding:10px; background:#2196F3; color:white; border-radius:8px 8px 0 0; font-weight:bold; cursor:pointer;" id="menu-header">Выберите лид (${list.length})</div>
|
|
<div style="max-height:350px; overflow-y:auto;">
|
|
`;
|
|
|
|
list.forEach((lead, idx) => {
|
|
const name = lead.first_name || 'Без имени';
|
|
const phone = lead.phone || 'без телефона';
|
|
const email = lead.email || '';
|
|
const timeStr = lead.received_at ? ` [${escapeHtml(lead.received_at)}]` : '';
|
|
menuHtml += `
|
|
<div class="menu-item" data-index="${idx}" style="padding:10px 12px; border-bottom:1px solid #eee; cursor:pointer;">
|
|
<div><strong>${escapeHtml(name)}</strong>${timeStr}</div>
|
|
<div style="font-size:12px; color:#666;">${escapeHtml(phone)} ${email ? '| ' + escapeHtml(email) : ''}</div>
|
|
</div>
|
|
`;
|
|
});
|
|
|
|
menuHtml += `
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
const menuDiv = document.createElement('div');
|
|
menuDiv.innerHTML = menuHtml;
|
|
document.body.appendChild(menuDiv);
|
|
|
|
// Закрытие по клику на крестик/заголовок
|
|
document.getElementById('menu-header').addEventListener('click', () => menuDiv.remove());
|
|
|
|
// Обработка выбора лида
|
|
menuDiv.querySelectorAll('.menu-item').forEach(item => {
|
|
item.addEventListener('click', () => {
|
|
const idx = parseInt(item.dataset.index);
|
|
fetchLeadByIndex(idx);
|
|
menuDiv.remove();
|
|
});
|
|
});
|
|
|
|
// Закрытие при клике вне меню
|
|
setTimeout(() => {
|
|
document.addEventListener('click', function closeMenu(e) {
|
|
if (!menuDiv.contains(e.target) && e.target.id !== 'lead-queue-btn') {
|
|
menuDiv.remove();
|
|
document.removeEventListener('click', closeMenu);
|
|
}
|
|
});
|
|
}, 100);
|
|
}
|
|
|
|
|
|
function escapeHtml(str) {
|
|
if (!str) return '';
|
|
return str.replace(/[&<>]/g, function(m) {
|
|
if (m === '&') return '&';
|
|
if (m === '<') return '<';
|
|
if (m === '>') return '>';
|
|
return m;
|
|
});
|
|
}
|
|
|
|
// Создание кнопки
|
|
const btn = document.createElement('button');
|
|
btn.id = 'lead-queue-btn';
|
|
btn.textContent = 'Лиды (0)';
|
|
btn.style.cssText = `
|
|
position: fixed;
|
|
bottom: 20px;
|
|
right: 20px;
|
|
z-index: 9999;
|
|
background: #9E9E9E;
|
|
color: white;
|
|
border: none;
|
|
padding: 12px 24px;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
font-size: 14px;
|
|
font-weight: bold;
|
|
font-family: sans-serif;
|
|
transition: all 0.2s;
|
|
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
|
`;
|
|
|
|
// Клик левой кнопкой — показать меню
|
|
btn.onclick = showMenu;
|
|
|
|
// Клик правой кнопкой — взять следующий лид (без меню)
|
|
btn.oncontextmenu = (e) => {
|
|
e.preventDefault();
|
|
fetchNextLead();
|
|
return false;
|
|
};
|
|
|
|
window.addEventListener('load', () => {
|
|
document.body.appendChild(btn);
|
|
updateCounter();
|
|
setInterval(updateCounter, 10000);
|
|
});
|
|
})(); |