// data_sources.js — logic for /data-sources page function getDateRange() { const to = document.getElementById('date_to').value; const from = document.getElementById('date_from').value; return { date_from: from, date_to: to }; } function qs(params) { return Object.entries(params).filter(([, v]) => v).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&'); } async function fetchJSON(url) { const r = await fetch(url); if (!r.ok) throw new Error(`HTTP ${r.status}`); return r.json(); } function pct(n, total) { if (!total) return '—'; return (100 * n / total).toFixed(1) + '%'; } // ── Coverage cards ──────────────────────────────────────────── async function loadCoverage() { const el = document.getElementById('coverage-cards'); const chart = document.getElementById('coverage-chart'); try { const data = await fetchJSON('/api/data-sources/coverage?' + qs(getDateRange())); const rows = data.rows || []; const totals = data.totals || {}; // Summary cards const total = totals.total_schedule || 0; el.innerHTML = `

Расписание Яндекс

Всего рейсов${total.toLocaleString()}
Дней${totals.days || 0}

RTL-SDR Локальный

Рейсов с треком${(totals.with_rtlsdr||0).toLocaleString()}${pct(totals.with_rtlsdr, total)}

FR24 API Платный

Рейсов с треком${(totals.with_fr24||0).toLocaleString()}${pct(totals.with_fr24, total)}

FlightAware AeroAPI

Рейсов с треком${(totals.with_fa||0).toLocaleString()}${pct(totals.with_fa, total)}
`; // Stacked bar chart by day if (!rows.length) { chart.innerHTML = '
Нет данных
'; return; } const maxTotal = Math.max(...rows.map(r => r.total_schedule || 0), 1); chart.innerHTML = rows.map(r => { const t = r.total_schedule || 1; const wRtl = ((r.with_rtlsdr || 0) / t * 100).toFixed(1); const wFr = ((r.with_fr24 || 0) / t * 100).toFixed(1); const wFa = ((r.with_fa || 0) / t * 100).toFixed(1); const wSch = (100 - parseFloat(wRtl) - parseFloat(wFr) - parseFloat(wFa)).toFixed(1); return `
${r.coverage_date}
${t}
`; }).join(''); } catch (e) { el.innerHTML = `
Ошибка: ${e.message}
`; } } // ── Quality ─────────────────────────────────────────────────── async function loadQuality() { const el = document.getElementById('quality-table'); try { const data = await fetchJSON('/api/data-sources/quality?' + qs(getDateRange())); const q = data.quality || {}; el.innerHTML = `
МетрикаЗначение
Рейсов с маршрутом${pct(q.with_route, q.total)}
Рейсов с треком${pct(q.with_track, q.total)}
Рейсов с факт. временем${pct(q.with_actual_time, q.total)}
Рейсов с типом ВС${pct(q.with_aircraft_type, q.total)}
Медиана точек (RTL-SDR)${q.median_points_rtlsdr || '—'}
Медиана точек (FR24)${q.median_points_fr24 || '—'}
Медиана точек (FA)${q.median_points_fa || '—'}
`; } catch (e) { el.innerHTML = `
Ошибка: ${e.message}
`; } } // ── Airport load ────────────────────────────────────────────── async function loadAirportLoad() { const el = document.getElementById('airport-load'); try { const data = await fetchJSON('/api/data-sources/airport-load?' + qs(getDateRange())); const rows = data.rows || []; if (!rows.length) { el.innerHTML = '
Нет данных
'; return; } const maxCount = Math.max(...rows.map(r => r.flight_count || 0), 1); el.innerHTML = ` ${rows.map(r => ``).join('')}
АэропортЧас (UTC)Рейсов
${r.airport_iata} ${String(r.hour).padStart(2,'0')}:00 ${r.flight_count}
`; } catch (e) { el.innerHTML = `
Ошибка: ${e.message}
`; } } // ── Top airlines ────────────────────────────────────────────── async function loadTopAirlines() { const el = document.getElementById('top-airlines'); try { const data = await fetchJSON('/api/data-sources/top-airlines?' + qs(getDateRange())); const rows = data.rows || []; if (!rows.length) { el.innerHTML = '
Нет данных
'; return; } const max = rows[0].flight_count || 1; el.innerHTML = ` ${rows.map((r, i) => ``).join('')}
#АвиакомпанияРейсов
${i+1} ${r.airline_iata || '—'} ${r.flight_count}
`; } catch (e) { el.innerHTML = `
Ошибка: ${e.message}
`; } } // ── Top routes ──────────────────────────────────────────────── async function loadTopRoutes() { const el = document.getElementById('top-routes'); try { const data = await fetchJSON('/api/data-sources/top-routes?' + qs(getDateRange())); const rows = data.rows || []; if (!rows.length) { el.innerHTML = '
Нет данных
'; return; } const max = rows[0].flight_count || 1; el.innerHTML = ` ${rows.map((r, i) => ``).join('')}
#МаршрутРейсов
${i+1} ${r.origin_iata || '?'} → ${r.destination_iata || '?'} ${r.flight_count}
`; } catch (e) { el.innerHTML = `
Ошибка: ${e.message}
`; } } // ── Init ────────────────────────────────────────────────────── function loadAll() { loadCoverage(); loadQuality(); loadAirportLoad(); loadTopAirlines(); loadTopRoutes(); } // Set default date range: last 7 days (function initDates() { const today = new Date(); const to = today.toISOString().slice(0, 10); today.setDate(today.getDate() - 7); const from = today.toISOString().slice(0, 10); document.getElementById('date_from').value = from; document.getElementById('date_to').value = to; })(); loadAll();