Online Employee Productivity Score Tracker

Employee Productivity Score Tracker

Productivity Overview

Average Productivity Score by Employee

Task Status Distribution

Manage Employees

Track Task Productivity

Logged Tasks

Export Productivity Report

Download a comprehensive productivity report for all employees and tasks as a PDF document.

${emp.name}

`).join(''); populateEmployeeSelect(); } function populateEmployeeSelect() { taskEmployeeSelect.innerHTML = employees.map(emp => ``).join(''); } function renderTaskList() { const table = ` ${tasks.map(task => { const employee = employees.find(e => e.id === task.employeeId); return `` }).join('')}
Task Assigned To Status Time (hrs) Actions
${task.name} ${employee ? employee.name : 'N/A'} ${task.status} ${task.time}
`; taskListContainer.innerHTML = table; } function renderCharts() { if(charts.scoreChart) charts.scoreChart.destroy(); if(charts.statusChart) charts.statusChart.destroy(); // Score Chart const employeeScores = employees.map(emp => { const empTasks = tasks.filter(t => t.employeeId === emp.id && t.status === 'Completed'); const avgScore = empTasks.length > 0 ? empTasks.reduce((sum, t) => sum + t.score, 0) / empTasks.length : 0; return avgScore; }); const scoreCtx = document.getElementById('scoreChart').getContext('2d'); charts.scoreChart = new Chart(scoreCtx, { type: 'bar', data: { labels: employees.map(e => e.name), datasets: [{ label: 'Average Score', data: employeeScores, backgroundColor: 'rgba(59, 130, 246, 0.5)', borderColor: 'rgba(59, 130, 246, 1)', borderWidth: 1 }] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, max: 100 } } } }); // Status Chart const statusCounts = tasks.reduce((acc, task) => { acc[task.status] = (acc[task.status] || 0) + 1; return acc; }, {}); const statusCtx = document.getElementById('statusChart').getContext('2d'); charts.statusChart = new Chart(statusCtx, { type: 'pie', data: { labels: Object.keys(statusCounts), datasets: [{ data: Object.values(statusCounts), backgroundColor: ['#10B981', '#F59E0B', '#EF4444'], }] }, options: { responsive: true, maintainAspectRatio: false } }); } // --- LOGIC FUNCTIONS --- function calculateProductivityScore(time, status) { if (status !== 'Completed') return 0; // Simple score: less time is better. Capped at 100. let score = Math.max(0, 100 - (time * 5)); if (status === 'Overdue') score *= 0.8; // Penalty for being overdue return Math.round(score); } function clearTaskForm() { taskForm.reset(); taskIdInput.value = ''; saveTaskBtn.textContent = 'Log Task'; } // --- EVENT HANDLERS --- employeeForm.addEventListener('submit', (e) => { e.preventDefault(); const id = employeeIdInput.value ? parseInt(employeeIdInput.value) : null; const name = employeeNameInput.value; if (id) { const index = employees.findIndex(emp => emp.id === id); employees[index].name = name; } else { const newId = employees.length > 0 ? Math.max(...employees.map(e => e.id)) + 1 : 1; employees.push({ id: newId, name }); } employeeForm.reset(); employeeIdInput.value = ''; saveEmployeeBtn.textContent = 'Add Employee'; renderAll(); }); taskForm.addEventListener('submit', (e) => { e.preventDefault(); const id = taskIdInput.value ? parseInt(taskIdInput.value) : null; const taskData = { name: taskNameInput.value, employeeId: parseInt(taskEmployeeSelect.value), status: taskStatusSelect.value, time: parseFloat(taskTimeInput.value), }; taskData.score = calculateProductivityScore(taskData.time, taskData.status); if (id) { const index = tasks.findIndex(t => t.id === id); tasks[index] = { ...tasks[index], ...taskData }; } else { const newId = tasks.length > 0 ? Math.max(...tasks.map(t => t.id)) + 1 : 1; tasks.push({ id: newId, ...taskData }); } clearTaskForm(); renderAll(); }); window.editEmployee = (id) => { const emp = employees.find(e => e.id === id); employeeIdInput.value = emp.id; employeeNameInput.value = emp.name; saveEmployeeBtn.textContent = 'Update'; }; window.deleteEmployee = (id) => { if (confirm('Are you sure? This will also unassign their tasks.')) { employees = employees.filter(e => e.id !== id); tasks.forEach(t => { if(t.employeeId === id) t.employeeId = null; }); renderAll(); } }; window.editTask = (id) => { const task = tasks.find(t => t.id === id); taskIdInput.value = task.id; taskNameInput.value = task.name; taskEmployeeSelect.value = task.employeeId; taskStatusSelect.value = task.status; taskTimeInput.value = task.time; saveTaskBtn.textContent = 'Update Task'; changeTab(null, 'tracker'); }; window.deleteTask = (id) => { if (confirm('Delete this task?')) { tasks = tasks.filter(t => t.id !== id); renderAll(); } }; function downloadPDF() { const { jsPDF } = window.jspdf; const pdfContentEl = document.getElementById('pdf-content'); let reportHTML = `

Productivity Report

`; employees.forEach(emp => { const empTasks = tasks.filter(t => t.employeeId === emp.id); const avgScore = empTasks.length > 0 ? Math.round(empTasks.reduce((sum, t) => sum + t.score, 0) / empTasks.length) : 'N/A'; reportHTML += `

${emp.name} - Avg Score: ${avgScore}

${empTasks.map(t => ` `).join('')}
Task Status Time (hrs) Score
${t.name} ${t.status} ${t.time} ${t.score}
`; }); pdfContentEl.innerHTML = `
${reportHTML}
`; html2canvas(pdfContentEl, { scale: 2 }).then(canvas => { const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'portrait', unit: 'pt', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const imgProps = pdf.getImageProperties(imgData); const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width; pdf.addImage(imgData, 'PNG', 20, 20, pdfWidth - 40, pdfHeight - 40); pdf.save('Productivity_Report.pdf'); }); } function renderAll() { renderEmployeeList(); renderTaskList(); renderCharts(); } // --- TAB NAVIGATION --- window.changeTab = function(evt, tabName) { document.querySelectorAll(".tab-content").forEach(tc => tc.classList.remove('active')); document.querySelectorAll(".tab-button").forEach(tb => tb.classList.remove('active')); document.getElementById(tabName).classList.add('active'); const button = evt ? evt.currentTarget : document.querySelector(`.tab-button[onclick*="'${tabName}'"]`); if(button) button.classList.add('active'); currentTab = tabName; updateNavButtons(); if (tabName === 'dashboard') renderCharts(); } function updateNavButtons() { const currentIndex = tabs.indexOf(currentTab); prevBtn.disabled = currentIndex === 0; nextBtn.disabled = currentIndex === tabs.length - 1; prevBtn.classList.toggle('opacity-50', prevBtn.disabled); nextBtn.classList.toggle('opacity-50', nextBtn.disabled); } prevBtn.addEventListener('click', () => { const currentIndex = tabs.indexOf(currentTab); if (currentIndex > 0) changeTab(null, tabs[currentIndex - 1]); }); nextBtn.addEventListener('click', () => { const currentIndex = tabs.indexOf(currentTab); if (currentIndex < tabs.length - 1) changeTab(null, tabs[currentIndex + 1]); }); // --- INITIALIZATION --- clearFormBtn.addEventListener('click', clearTaskForm); downloadPdfBtn.addEventListener('click', downloadPDF); renderAll(); updateNavButtons(); });
Scroll to Top