Moodle Report Builder

Moodle Report Builder

Configure your report in the 'Report Builder' tab and click 'Generate Report' to see the results here.

${completedCount}

Average Grade

${avgGrade ? avgGrade.toFixed(1) + '%' : 'N/A'}

`; // Table and Chart outputHTML += `
`; outputHTML += `
${renderTable(data, columns)}
`; outputHTML += `

Grade Distribution

`; outputHTML += `
`; reportOutput.innerHTML = outputHTML; renderGradeDistributionChart(data); } function renderTable(data, columns) { if (data.length === 0) return '

No data matches your selected filters.

'; let table = '
'; table += ''; columns.forEach(col => { table += ``; }); table += ''; data.forEach(row => { table += ''; columns.forEach(col => { table += ``; }); table += ''; }); table += '
${col.label}
${row[col.id] !== null ? row[col.id] : 'N/A'}
'; return table; } function renderGradeDistributionChart(data) { const ctx = document.getElementById('gradeDistChart')?.getContext('2d'); if (!ctx) return; if (gradeDistChart) gradeDistChart.destroy(); const gradeBins = { '90-100': 0, '80-89': 0, '70-79': 0, '60-69': 0, '<60': 0 }; data.forEach(item => { if (item.grade === null) return; if (item.grade >= 90) gradeBins['90-100']++; else if (item.grade >= 80) gradeBins['80-89']++; else if (item.grade >= 70) gradeBins['70-79']++; else if (item.grade >= 60) gradeBins['60-69']++; else gradeBins['<60']++; }); gradeDistChart = new Chart(ctx, { type: 'bar', data: { labels: Object.keys(gradeBins), datasets: [{ label: 'Number of Students', data: Object.values(gradeBins), backgroundColor: ['#10b981', '#3b82f6', '#f59e0b', '#ef4444', '#8b5cf6'] }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: false } } } }); } // --- PDF and UI Helpers --- function addEventListeners() { reportViewTab.addEventListener('click', () => setActiveTab(reportViewTab)); builderTab.addEventListener('click', () => setActiveTab(builderTab)); generateReportBtn.addEventListener('click', handleGenerateReport); downloadPdfBtn.addEventListener('click', handlePdfDownload); document.getElementById('alert-close-btn').addEventListener('click', hideAlert); document.getElementById('courses-data').addEventListener('keyup', updateCourseFilter); } function setActiveTab(tabElement) { [reportViewTab, builderTab].forEach(t => t.classList.replace('tab-active', 'tab-inactive')); [reportViewContent, builderContent].forEach(c => c.classList.add('hidden')); tabElement.classList.replace('tab-inactive', 'tab-active'); document.getElementById(tabElement.getAttribute('aria-controls')).classList.remove('hidden'); } function showAlert(title, message) { const modal = document.getElementById('alert-modal'); document.getElementById('alert-title').textContent = title; document.getElementById('alert-message').textContent = message; modal.classList.remove('hidden'); modal.classList.add('flex'); } function hideAlert() { document.getElementById('alert-modal').classList.add('hidden'); } async function handlePdfDownload() { const { jsPDF } = window.jspdf; const pdfContent = document.getElementById('pdf-content'); if (!pdfContent) { showAlert('Error', 'Could not find content to download.'); return; } const originalButtonText = downloadPdfBtn.textContent; downloadPdfBtn.textContent = 'Generating...'; downloadPdfBtn.disabled = true; try { const canvas = await html2canvas(pdfContent, { scale: 2, useCORS: true, logging: false, backgroundColor: '#ffffff' }); const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'portrait', unit: 'pt', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const pdfHeight = pdf.internal.pageSize.getHeight(); const margin = 40; const imgProps = pdf.getImageProperties(imgData); const ratio = imgProps.width / imgProps.height; let finalWidth = pdfWidth - margin * 2; let finalHeight = finalWidth / ratio; if (finalHeight > pdfHeight - margin * 2) { finalHeight = pdfHeight - margin * 2; finalWidth = finalHeight * ratio; } const x = (pdfWidth - finalWidth) / 2; const y = margin; pdf.addImage(imgData, 'PNG', x, y, finalWidth, finalHeight); const reportTitle = document.getElementById('report-title-input').value || 'report'; pdf.save(`${reportTitle.replace(/ /g, '_')}.pdf`); } catch (error) { console.error('Error generating PDF:', error); showAlert('PDF Error', 'An error occurred while generating the PDF.'); } finally { downloadPdfBtn.textContent = originalButtonText; downloadPdfBtn.disabled = false; } } // --- Run Initialization --- initialize(); });
Scroll to Top