diff --git a/frontend/src/components/layout/footer/VisitorCounter.astro b/frontend/src/components/layout/footer/VisitorCounter.astro index f1476fa..77b9658 100644 --- a/frontend/src/components/layout/footer/VisitorCounter.astro +++ b/frontend/src/components/layout/footer/VisitorCounter.astro @@ -29,8 +29,13 @@ const { today = 0, total = 0 } = Astro.props; if (valueEls.length < 2) return; const todayStr = new Date().toDateString(); + const lastVisit = localStorage.getItem('site_visited'); - fetch('/api/visitors').then(r => r.json()).then(d => { + // Если уже посещали сегодня - помечаем как повторный визит + const isRepeat = lastVisit === todayStr; + const apiUrl = isRepeat ? '/api/visitors?repeat=true' : '/api/visitors'; + + fetch(apiUrl).then(r => r.json()).then(d => { if (typeof d.todayVisitors === 'number') { if (d.isNewVisitor) { localStorage.setItem('site_visited', todayStr); diff --git a/frontend/src/pages/api/visitors.ts b/frontend/src/pages/api/visitors.ts index 22e95f2..3fcf99b 100644 --- a/frontend/src/pages/api/visitors.ts +++ b/frontend/src/pages/api/visitors.ts @@ -17,7 +17,12 @@ function getClientIp(request: Request): string { } function generateVisitorHash(ip: string, userAgent: string): string { - return crypto.createHash('sha256').update(ip + userAgent).digest('hex').slice(0, 32); + // Упрощаем - используем только IP (без порта) для стабильности + const stableIP = ip.split(':').pop() || ip; + // Используем только первые 2 слова из userAgent (браузер + платформа) + const uaParts = userAgent.split(' '); + const stableUA = uaParts.slice(0, 2).join(' '); + return crypto.createHash('sha256').update(stableIP + stableUA).digest('hex').slice(0, 32); } async function pbRequest(method: string, path: string, body?: object) { @@ -48,6 +53,9 @@ function jsonResponse(data: object, status = 200): Response { export const GET: APIRoute = async ({ request }) => { try { + const url = new URL(request.url); + const isRepeatVisit = url.searchParams.get('repeat') === 'true'; + const ip = getClientIp(request); const userAgent = request.headers.get('user-agent') || 'unknown'; const visitorHash = generateVisitorHash(ip, userAgent); @@ -55,7 +63,8 @@ export const GET: APIRoute = async ({ request }) => { const now = new Date(); // Начало текущего дня по UTC (00:00 UTC) const todayStart = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), 0, 0, 0, 0)); - const todayStartStr = todayStart.toISOString(); + // PocketBase использует формат YYYY-MM-DD HH:MM:SS + const todayStartStr = todayStart.toISOString().replace('T', ' ').replace('Z', ''); // Проверяем был ли посетитель сегодня (с 00:00 UTC) const filterTodayVisitor = `visitor_hash="${visitorHash}" && created >= "${todayStartStr}"`; @@ -70,8 +79,12 @@ export const GET: APIRoute = async ({ request }) => { let isNewVisitor = false; + // Если это повторный визит по данным клиента - не создаём запись + if (isRepeatVisit) { + isNewVisitor = false; + } // Создаём запись только если НЕ было посещения сегодня - if (existingVisitor.totalItems === 0) { + else if (existingVisitor.totalItems === 0) { isNewVisitor = true; try { await pbRequest('POST', '/api/collections/site_visitors/records', {