From 758fc7f7a9f641fa48d657a0c3fe871c157f510e Mon Sep 17 00:00:00 2001 From: Nguyen Ngo Date: Tue, 19 Aug 2025 17:19:25 -0400 Subject: [PATCH] Attendance report add employee name column --- app.py | 8 ++- static/css/attendance.css | 17 +++++ static/js/attendance_report.js | 109 ++++++++++++++++--------------- templates/attendance_report.html | 23 ++++--- 4 files changed, 93 insertions(+), 64 deletions(-) diff --git a/app.py b/app.py index 089cfa5..6d24d5c 100644 --- a/app.py +++ b/app.py @@ -3257,9 +3257,11 @@ def attendance_report(): ad.longitude, ad.location_accuracy, ad.accuracy as gps_accuracy, - ad.device_info + ad.device_info, + CONCAT(e.firstName, ' ', e.lastName) as employee_name FROM attendance_data ad LEFT JOIN qr_codes qc ON ad.qr_code_id = qc.id + LEFT JOIN employee e ON ad.employee_id = e.id WHERE 1=1 """ else: @@ -3278,9 +3280,11 @@ def attendance_report(): ad.longitude, NULL as location_accuracy, ad.accuracy as gps_accuracy, - ad.device_info + ad.device_info, + CONCAT(e.firstName, ' ', e.lastName) as employee_name FROM attendance_data ad LEFT JOIN qr_codes qc ON ad.qr_code_id = qc.id + LEFT JOIN employee e ON ad.employee_id = e.id WHERE 1=1 """ diff --git a/static/css/attendance.css b/static/css/attendance.css index d9d23de..49750cb 100644 --- a/static/css/attendance.css +++ b/static/css/attendance.css @@ -393,6 +393,23 @@ border-radius: var(--radius); } +.employee-name { + display: flex; + align-items: center; + gap: var(--spacing-2); + color: var(--gray-700); + font-weight: 500; +} + +.employee-name i { + color: var(--primary-color); + font-size: var(--font-size-sm); +} + +.employee-name span { + font-weight: 500; +} + .location-info { display: flex; align-items: center; diff --git a/static/js/attendance_report.js b/static/js/attendance_report.js index 98cd4dc..00b9e8b 100644 --- a/static/js/attendance_report.js +++ b/static/js/attendance_report.js @@ -69,31 +69,27 @@ function loadTableData() { } return { - id: row.dataset.recordId, - index: index + 1, - employeeId: cells[1] ? cells[1].textContent.trim() : "", - location: cells[2] ? cells[2].textContent.trim() : "", - event: cells[3] ? cells[3].textContent.trim() : "", - date: cells[4] ? cells[4].textContent.trim() : "", - time: cells[5] ? cells[5].textContent.trim() : "", - qr_address: cells[6] - ? cells[6].getAttribute("title") || cells[6].textContent.trim() - : "", - checked_in_address: cells[7] - ? cells[7].getAttribute("title") || cells[7].textContent.trim() - : "", - // FIXED: Extract location accuracy for address display logic - location_accuracy: cells[8] ? extractLocationAccuracy(cells[8]) : null, - accuracy_level: cells[8] - ? extractLocationAccuracyLevel(cells[8]) - : "unknown", - device: cells[9] - ? cells[9].getAttribute("title") || cells[9].textContent.trim() - : "", - has_location_data: cells[8] - ? !cells[8].textContent.includes("Unknown") - : false, - coordinates: extractCoordinates(cells[8]), + id: row.dataset.recordId, + index: index + 1, + employeeId: cells[1] ? cells[1].textContent.trim() : "", + employeeName: cells[2] ? cells[2].textContent.trim() : "", + location: cells[3] ? cells[3].textContent.trim() : "", + event: cells[4] ? cells[4].textContent.trim() : "", + date: cells[5] ? cells[5].textContent.trim() : "", + time: cells[6] ? cells[6].textContent.trim() : "", + qr_address: cells[7] + ? cells[7].getAttribute("title") || cells[7].textContent.trim() + : "", + checked_in_address: cells[8] + ? cells[8].getAttribute("title") || cells[8].textContent.trim() + : "", + location_accuracy: cells[9] ? extractLocationAccuracy(cells[9]) : null, + accuracy_level: cells[9] + ? extractLocationAccuracyLevel(cells[9]) + : "unknown", + device: cells[10] + ? cells[10].textContent.trim() + : "" }; }); @@ -568,31 +564,28 @@ function loadTableData() { attendanceData = Array.from(rows).map((row, index) => { const cells = row.querySelectorAll("td"); return { - id: row.dataset.recordId, - index: index + 1, - employeeId: cells[1] ? cells[1].textContent.trim() : "", - location: cells[2] ? cells[2].textContent.trim() : "", - event: cells[3] ? cells[3].textContent.trim() : "", - date: cells[4] ? cells[4].textContent.trim() : "", - time: cells[5] ? cells[5].textContent.trim() : "", - qr_address: cells[6] - ? cells[6].getAttribute("title") || cells[6].textContent.trim() - : "", - checked_in_address: cells[7] - ? cells[7].getAttribute("title") || cells[7].textContent.trim() - : "", - // FIXED: Extract location accuracy for address display logic - location_accuracy: cells[8] ? extractLocationAccuracy(cells[8]) : null, - accuracy_level: cells[8] - ? extractLocationAccuracyLevel(cells[8]) - : "unknown", - device: cells[9] - ? cells[9].getAttribute("title") || cells[9].textContent.trim() - : "", - has_location_data: cells[8] - ? !cells[8].textContent.includes("Unknown") - : false, - coordinates: extractCoordinates(cells[8]), + id: row.dataset.recordId, + index: index + 1, + employeeId: cells[1] ? cells[1].textContent.trim() : "", + employeeName: cells[2] ? cells[2].textContent.trim() : "", // NEW: Employee Name column + location: cells[3] ? cells[3].textContent.trim() : "", // Updated from cells[2] + event: cells[4] ? cells[4].textContent.trim() : "", // Updated from cells[3] + date: cells[5] ? cells[5].textContent.trim() : "", // Updated from cells[4] + time: cells[6] ? cells[6].textContent.trim() : "", // Updated from cells[5] + qr_address: cells[7] // Updated from cells[6] + ? cells[7].getAttribute("title") || cells[7].textContent.trim() + : "", + checked_in_address: cells[8] // Updated from cells[7] + ? cells[8].getAttribute("title") || cells[8].textContent.trim() + : "", + // FIXED: Extract location accuracy for address display logic + location_accuracy: cells[9] ? extractLocationAccuracy(cells[9]) : null, // Updated from cells[8] + accuracy_level: cells[9] // Updated from cells[8] + ? extractLocationAccuracyLevel(cells[9]) + : "unknown", + device: cells[10] // Updated from cells[9] + ? cells[10].textContent.trim() + : "" }; }); @@ -787,6 +780,12 @@ function createTableRow(record, displayIndex) { ${record.employeeId} + +
+ + ${record.employeeName || 'Unknown'} +
+
@@ -966,7 +965,9 @@ function getAccuracyLevelColor(level) { function exportAttendanceWithAccuracy() { // Build CSV header with location accuracy const headers = [ + "#", "Employee ID", + "Employee Name", "Location", "Event", "Date", @@ -979,17 +980,17 @@ function exportAttendanceWithAccuracy() { ]; // Build CSV rows - const rows = filteredData.map((record) => [ + const rows = filteredData.map((record, index) => [ + index + 1, record.employeeId, + record.employeeName || "Unknown", record.location, record.event, record.date, record.time, record.qr_address, record.checked_in_address, - record.location_accuracy !== null - ? record.location_accuracy.toFixed(3) - : "Unknown", + record.location_accuracy ? record.location_accuracy.toFixed(3) : "Unknown", record.accuracy_level, record.device, ]); diff --git a/templates/attendance_report.html b/templates/attendance_report.html index 53ebb4c..bb702fd 100644 --- a/templates/attendance_report.html +++ b/templates/attendance_report.html @@ -163,17 +163,18 @@ # Employee ID - Location - Event - Date - Time - QR Address - Check-in Address - + Employee Name + Location + Event + Date + Time + QR Address + Check-in Address + {% if has_location_accuracy_feature %}Location Accuracy{% else %}GPS Accuracy{% endif %} - Device + Device Actions @@ -186,6 +187,12 @@ {{ record.employee_id }}
+ +
+ + {{ record.employee_name if record.employee_name else 'Unknown' }} +
+