$(document).ready(() => { if (!window.isAdmin()) { $(".container").html( '

Доступ запрещён

Только администраторы могут просматривать аналитику

На главную
' ); return; } let loansChart = null; let returnsChart = null; let currentPeriod = 30; init(); function init() { $("#period-select").on("change", function () { currentPeriod = parseInt($(this).val()); loadAnalytics(); }); $("#refresh-btn").on("click", loadAnalytics); loadAnalytics(); } async function loadAnalytics() { try { const data = await Api.get(`/api/loans/analytics?days=${currentPeriod}`); renderSummary(data.summary); renderCharts(data); renderTopBooks(data.top_books); } catch (error) { console.error("Failed to load analytics", error); Utils.showToast("Ошибка загрузки аналитики", "error"); } } function renderSummary(summary) { $("#total-loans").text(summary.total_loans || 0); $("#active-loans").text(summary.active_loans || 0); $("#returned-loans").text(summary.returned_loans || 0); $("#overdue-loans").text(summary.overdue_loans || 0); $("#reserved-books").text(summary.reserved_books || 0); $("#borrowed-books").text(summary.borrowed_books || 0); } function renderCharts(data) { // Подготовка данных для графиков const startDate = new Date(data.start_date); const endDate = new Date(data.end_date); const dates = []; const loansData = []; const returnsData = []; for (let d = new Date(startDate); d <= endDate; d.setDate(d.getDate() + 1)) { const dateStr = d.toISOString().split("T")[0]; dates.push(new Date(d).toLocaleDateString("ru-RU", { day: "2-digit", month: "2-digit" })); loansData.push(data.daily_loans[dateStr] || 0); returnsData.push(data.daily_returns[dateStr] || 0); } // График выдач const loansCtx = document.getElementById("loans-chart"); if (loansChart) { loansChart.destroy(); } loansChart = new Chart(loansCtx, { type: "line", data: { labels: dates, datasets: [ { label: "Выдачи", data: loansData, borderColor: "rgb(75, 85, 99)", backgroundColor: "rgba(75, 85, 99, 0.05)", borderWidth: 1.5, fill: true, tension: 0.3, pointRadius: 2.5, pointHoverRadius: 4, pointBackgroundColor: "rgb(75, 85, 99)", pointBorderColor: "#fff", pointBorderWidth: 1.5, pointStyle: "circle", }, ], }, options: { responsive: true, maintainAspectRatio: true, interaction: { intersect: false, mode: "index", }, plugins: { legend: { display: false, }, tooltip: { backgroundColor: "rgba(0, 0, 0, 0.8)", padding: 10, titleFont: { size: 12, weight: "500" }, bodyFont: { size: 11 }, cornerRadius: 6, displayColors: false, borderColor: "rgba(255, 255, 255, 0.08)", borderWidth: 1, titleSpacing: 4, bodySpacing: 4, }, }, scales: { y: { beginAtZero: true, grid: { color: "rgba(0, 0, 0, 0.03)", drawBorder: false, lineWidth: 1, }, ticks: { precision: 0, font: { size: 10 }, color: "rgba(0, 0, 0, 0.4)", padding: 8, }, }, x: { grid: { display: false, }, ticks: { maxRotation: 0, minRotation: 0, font: { size: 10 }, color: "rgba(0, 0, 0, 0.4)", padding: 8, }, }, }, }, }); // График возвратов const returnsCtx = document.getElementById("returns-chart"); if (returnsChart) { returnsChart.destroy(); } returnsChart = new Chart(returnsCtx, { type: "line", data: { labels: dates, datasets: [ { label: "Возвраты", data: returnsData, borderColor: "rgb(107, 114, 128)", backgroundColor: "rgba(107, 114, 128, 0.05)", borderWidth: 1.5, fill: true, tension: 0.3, pointRadius: 2.5, pointHoverRadius: 4, pointBackgroundColor: "rgb(107, 114, 128)", pointBorderColor: "#fff", pointBorderWidth: 1.5, pointStyle: "circle", }, ], }, options: { responsive: true, maintainAspectRatio: true, interaction: { intersect: false, mode: "index", }, plugins: { legend: { display: false, }, tooltip: { backgroundColor: "rgba(0, 0, 0, 0.8)", padding: 10, titleFont: { size: 12, weight: "500" }, bodyFont: { size: 11 }, cornerRadius: 6, displayColors: false, borderColor: "rgba(255, 255, 255, 0.08)", borderWidth: 1, titleSpacing: 4, bodySpacing: 4, }, }, scales: { y: { beginAtZero: true, grid: { color: "rgba(0, 0, 0, 0.03)", drawBorder: false, lineWidth: 1, }, ticks: { precision: 0, font: { size: 10 }, color: "rgba(0, 0, 0, 0.4)", padding: 8, }, }, x: { grid: { display: false, }, ticks: { maxRotation: 0, minRotation: 0, font: { size: 10 }, color: "rgba(0, 0, 0, 0.4)", padding: 8, }, }, }, }, }); } function renderTopBooks(topBooks) { const $container = $("#top-books-container"); $container.empty(); if (!topBooks || topBooks.length === 0) { $container.html( '
Нет данных
' ); return; } topBooks.forEach((book, index) => { const $item = $(`
${index + 1}
${book.loan_count} ${book.loan_count === 1 ? "выдача" : book.loan_count < 5 ? "выдачи" : "выдач"}
`); $container.append($item); }); } });