Files
tp/main_dc/valitovgaziz/html/JavaScript/analytics.js
T
valitovgaziz a013fcacd8 modified: main_dc/docker-compose.yml
modified:   main_dc/nginx/nginx-ssl.conf
	new file:   main_dc/valitovgaziz/analytics/Dockerfile
	new file:   main_dc/valitovgaziz/analytics/package.json
	new file:   main_dc/valitovgaziz/analytics/server.js
	new file:   main_dc/valitovgaziz/html/JavaScript/analytics.js
	modified:   main_dc/valitovgaziz/html/index.html
add nginx settings for api logs for valitovgaziz.ru site,
add container for metrica container,
add metrica scripts on site valitovgaziz.ru
2025-11-11 03:22:14 +05:00

270 lines
9.3 KiB
JavaScript

// analytics.js - собственный счетчик аналитики для браузера
class CustomAnalytics {
constructor() {
this.endpoint = 'https://valitovgaziz.ru/api/analytics'; // Ваш endpoint для сбора данных
this.queue = [];
this.isOnline = navigator.onLine;
this.sessionId = this.getSessionId();
this.init();
}
init() {
// Загружаем сохраненные данные из localStorage
this.loadFromStorage();
// Отслеживание событий
this.trackPageView();
this.setupEventListeners();
// Периодическая отправка данных
setInterval(() => this.flushQueue(), 30000);
// Отслеживание онлайн/офлайн статуса
window.addEventListener('online', () => {
this.isOnline = true;
this.flushQueue();
});
window.addEventListener('offline', () => {
this.isOnline = false;
});
// Отправка данных перед закрытием страницы
window.addEventListener('beforeunload', () => {
this.trackEvent('page', 'unload');
this.flushQueueSync();
});
}
trackPageView() {
const data = {
type: 'pageview',
url: window.location.href,
referrer: document.referrer,
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent,
screen: `${screen.width}x${screen.height}`,
language: navigator.language,
sessionId: this.sessionId
};
this.addToQueue(data);
}
trackEvent(category, action, label = null, value = null) {
const data = {
type: 'event',
category,
action,
label,
value,
timestamp: new Date().toISOString(),
url: window.location.href,
sessionId: this.sessionId
};
this.addToQueue(data);
}
trackClick(element, context = 'unknown') {
const data = {
type: 'click',
element: element.tagName,
text: element.textContent?.substring(0, 100),
context,
timestamp: new Date().toISOString(),
url: window.location.href,
sessionId: this.sessionId
};
this.addToQueue(data);
}
addToQueue(data) {
this.queue.push(data);
// Сохраняем в localStorage
this.saveToStorage();
// Отправляем сразу если онлайн и очередь большая
if (this.isOnline && this.queue.length >= 3) {
this.flushQueue();
}
}
async flushQueue() {
if (!this.isOnline || this.queue.length === 0) return;
const batch = [...this.queue];
try {
const response = await fetch(this.endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
events: batch,
sessionId: this.sessionId
}),
keepalive: true // Позволяет отправлять данные даже при закрытии страницы
});
if (response.ok) {
// Удаляем отправленные данные из очереди
this.queue = this.queue.filter(item => !batch.includes(item));
this.saveToStorage();
}
} catch (error) {
console.log('Analytics offline, storing locally');
}
}
flushQueueSync() {
if (this.queue.length === 0) return;
// Используем sendBeacon для надежной отправки при закрытии страницы
const data = JSON.stringify({
events: this.queue,
sessionId: this.sessionId
});
if (navigator.sendBeacon) {
navigator.sendBeacon(this.endpoint, data);
}
}
getSessionId() {
let sessionId = localStorage.getItem('ga_session_id');
const now = Date.now();
if (!sessionId) {
sessionId = 'sess_' + now + '_' + Math.random().toString(36).substr(2, 9);
localStorage.setItem('ga_session_id', sessionId);
localStorage.setItem('ga_session_start', now);
}
// Обновляем время последней активности
localStorage.setItem('ga_last_activity', now);
return sessionId;
}
saveToStorage() {
try {
localStorage.setItem('ga_queue', JSON.stringify(this.queue));
} catch (e) {
console.warn('Cannot save analytics to localStorage');
}
}
loadFromStorage() {
try {
const stored = localStorage.getItem('ga_queue');
if (stored) {
const parsed = JSON.parse(stored);
if (Array.isArray(parsed)) {
this.queue = parsed;
}
}
} catch (e) {
console.warn('Cannot load analytics from localStorage');
}
}
setupEventListeners() {
// Отслеживание кликов по кнопкам
document.addEventListener('click', (e) => {
if (e.target.matches('button, .btn, a[href]')) {
const context = e.target.closest('.section') ?
e.target.closest('.section').querySelector('h2')?.textContent || 'unknown' :
'global';
this.trackClick(e.target, context);
// Специальные события для кнопок сотрудничества
if (e.target.textContent.includes('сотрудничество') || e.target.textContent.includes('Написать')) {
this.trackEvent('conversion', 'contact_click', e.target.textContent.trim());
}
}
});
// Отслеживание отправки форм
document.addEventListener('submit', (e) => {
this.trackEvent('form', 'submit', e.target.id || 'unknown');
});
// Отслеживание видимости секций
this.setupSectionTracking();
// Отслеживание внешних ссылок
document.addEventListener('click', (e) => {
const link = e.target.closest('a[href]');
if (link && link.hostname !== window.location.hostname) {
this.trackEvent('outbound', 'click', link.href);
}
});
}
setupSectionTracking() {
const sections = document.querySelectorAll('.section');
const observedSections = new Set();
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {
const sectionId = entry.target.id ||
entry.target.querySelector('h2')?.textContent?.substring(0, 50) ||
'unknown_section';
if (!observedSections.has(sectionId)) {
observedSections.add(sectionId);
this.trackEvent('content', 'section_view', sectionId);
}
}
});
}, {
threshold: [0.5],
rootMargin: '0px 0px -10% 0px'
});
sections.forEach(section => {
observer.observe(section);
});
}
}
// Инициализация при полной загрузке DOM
document.addEventListener('DOMContentLoaded', () => {
window.analytics = new CustomAnalytics();
// Глобальные функции для ручного отслеживания
window.trackEvent = (category, action, label, value) => {
if (window.analytics) {
window.analytics.trackEvent(category, action, label, value);
}
};
// Отслеживание специальных событий для вашего сайта
const specialButtons = document.querySelectorAll('[onclick*="sendMessageTelegram"]');
specialButtons.forEach(btn => {
btn.addEventListener('click', () => {
trackEvent('business', 'telegram_click', btn.textContent.trim());
});
});
// Отслеживание просмотра ключевых элементов
const keyElements = document.querySelectorAll('.hero, .team-section, .yalarba-section');
const elementObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const elementType = entry.target.className.split(' ')[0];
trackEvent('engagement', `${elementType}_viewed`);
elementObserver.unobserve(entry.target);
}
});
}, { threshold: 0.3 });
keyElements.forEach(el => elementObserver.observe(el));
});
// Fallback для старых браузеров
if (!window.Promise) {
console.warn('Custom analytics requires Promise support');
window.trackEvent = function () { };
}