Attendance report add employee name column
This commit is contained in:
@@ -3257,9 +3257,11 @@ def attendance_report():
|
|||||||
ad.longitude,
|
ad.longitude,
|
||||||
ad.location_accuracy,
|
ad.location_accuracy,
|
||||||
ad.accuracy as gps_accuracy,
|
ad.accuracy as gps_accuracy,
|
||||||
ad.device_info
|
ad.device_info,
|
||||||
|
CONCAT(e.firstName, ' ', e.lastName) as employee_name
|
||||||
FROM attendance_data ad
|
FROM attendance_data ad
|
||||||
LEFT JOIN qr_codes qc ON ad.qr_code_id = qc.id
|
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
|
WHERE 1=1
|
||||||
"""
|
"""
|
||||||
else:
|
else:
|
||||||
@@ -3278,9 +3280,11 @@ def attendance_report():
|
|||||||
ad.longitude,
|
ad.longitude,
|
||||||
NULL as location_accuracy,
|
NULL as location_accuracy,
|
||||||
ad.accuracy as gps_accuracy,
|
ad.accuracy as gps_accuracy,
|
||||||
ad.device_info
|
ad.device_info,
|
||||||
|
CONCAT(e.firstName, ' ', e.lastName) as employee_name
|
||||||
FROM attendance_data ad
|
FROM attendance_data ad
|
||||||
LEFT JOIN qr_codes qc ON ad.qr_code_id = qc.id
|
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
|
WHERE 1=1
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|||||||
@@ -393,6 +393,23 @@
|
|||||||
border-radius: var(--radius);
|
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 {
|
.location-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -69,31 +69,27 @@ function loadTableData() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: row.dataset.recordId,
|
id: row.dataset.recordId,
|
||||||
index: index + 1,
|
index: index + 1,
|
||||||
employeeId: cells[1] ? cells[1].textContent.trim() : "",
|
employeeId: cells[1] ? cells[1].textContent.trim() : "",
|
||||||
location: cells[2] ? cells[2].textContent.trim() : "",
|
employeeName: cells[2] ? cells[2].textContent.trim() : "",
|
||||||
event: cells[3] ? cells[3].textContent.trim() : "",
|
location: cells[3] ? cells[3].textContent.trim() : "",
|
||||||
date: cells[4] ? cells[4].textContent.trim() : "",
|
event: cells[4] ? cells[4].textContent.trim() : "",
|
||||||
time: cells[5] ? cells[5].textContent.trim() : "",
|
date: cells[5] ? cells[5].textContent.trim() : "",
|
||||||
qr_address: cells[6]
|
time: cells[6] ? cells[6].textContent.trim() : "",
|
||||||
? cells[6].getAttribute("title") || cells[6].textContent.trim()
|
qr_address: cells[7]
|
||||||
: "",
|
? cells[7].getAttribute("title") || cells[7].textContent.trim()
|
||||||
checked_in_address: cells[7]
|
: "",
|
||||||
? cells[7].getAttribute("title") || cells[7].textContent.trim()
|
checked_in_address: cells[8]
|
||||||
: "",
|
? cells[8].getAttribute("title") || cells[8].textContent.trim()
|
||||||
// FIXED: Extract location accuracy for address display logic
|
: "",
|
||||||
location_accuracy: cells[8] ? extractLocationAccuracy(cells[8]) : null,
|
location_accuracy: cells[9] ? extractLocationAccuracy(cells[9]) : null,
|
||||||
accuracy_level: cells[8]
|
accuracy_level: cells[9]
|
||||||
? extractLocationAccuracyLevel(cells[8])
|
? extractLocationAccuracyLevel(cells[9])
|
||||||
: "unknown",
|
: "unknown",
|
||||||
device: cells[9]
|
device: cells[10]
|
||||||
? cells[9].getAttribute("title") || cells[9].textContent.trim()
|
? cells[10].textContent.trim()
|
||||||
: "",
|
: ""
|
||||||
has_location_data: cells[8]
|
|
||||||
? !cells[8].textContent.includes("Unknown")
|
|
||||||
: false,
|
|
||||||
coordinates: extractCoordinates(cells[8]),
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -568,31 +564,28 @@ function loadTableData() {
|
|||||||
attendanceData = Array.from(rows).map((row, index) => {
|
attendanceData = Array.from(rows).map((row, index) => {
|
||||||
const cells = row.querySelectorAll("td");
|
const cells = row.querySelectorAll("td");
|
||||||
return {
|
return {
|
||||||
id: row.dataset.recordId,
|
id: row.dataset.recordId,
|
||||||
index: index + 1,
|
index: index + 1,
|
||||||
employeeId: cells[1] ? cells[1].textContent.trim() : "",
|
employeeId: cells[1] ? cells[1].textContent.trim() : "",
|
||||||
location: cells[2] ? cells[2].textContent.trim() : "",
|
employeeName: cells[2] ? cells[2].textContent.trim() : "", // NEW: Employee Name column
|
||||||
event: cells[3] ? cells[3].textContent.trim() : "",
|
location: cells[3] ? cells[3].textContent.trim() : "", // Updated from cells[2]
|
||||||
date: cells[4] ? cells[4].textContent.trim() : "",
|
event: cells[4] ? cells[4].textContent.trim() : "", // Updated from cells[3]
|
||||||
time: cells[5] ? cells[5].textContent.trim() : "",
|
date: cells[5] ? cells[5].textContent.trim() : "", // Updated from cells[4]
|
||||||
qr_address: cells[6]
|
time: cells[6] ? cells[6].textContent.trim() : "", // Updated from cells[5]
|
||||||
? cells[6].getAttribute("title") || cells[6].textContent.trim()
|
qr_address: cells[7] // Updated from cells[6]
|
||||||
: "",
|
? cells[7].getAttribute("title") || cells[7].textContent.trim()
|
||||||
checked_in_address: cells[7]
|
: "",
|
||||||
? 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[8] ? extractLocationAccuracy(cells[8]) : null,
|
// FIXED: Extract location accuracy for address display logic
|
||||||
accuracy_level: cells[8]
|
location_accuracy: cells[9] ? extractLocationAccuracy(cells[9]) : null, // Updated from cells[8]
|
||||||
? extractLocationAccuracyLevel(cells[8])
|
accuracy_level: cells[9] // Updated from cells[8]
|
||||||
: "unknown",
|
? extractLocationAccuracyLevel(cells[9])
|
||||||
device: cells[9]
|
: "unknown",
|
||||||
? cells[9].getAttribute("title") || cells[9].textContent.trim()
|
device: cells[10] // Updated from cells[9]
|
||||||
: "",
|
? cells[10].textContent.trim()
|
||||||
has_location_data: cells[8]
|
: ""
|
||||||
? !cells[8].textContent.includes("Unknown")
|
|
||||||
: false,
|
|
||||||
coordinates: extractCoordinates(cells[8]),
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -787,6 +780,12 @@ function createTableRow(record, displayIndex) {
|
|||||||
<span class="employee-id">${record.employeeId}</span>
|
<span class="employee-id">${record.employeeId}</span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="employee-name">
|
||||||
|
<i class="fas fa-user"></i>
|
||||||
|
<span>${record.employeeName || 'Unknown'}</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="location-info">
|
<div class="location-info">
|
||||||
<i class="fas fa-map-marker-alt"></i>
|
<i class="fas fa-map-marker-alt"></i>
|
||||||
@@ -966,7 +965,9 @@ function getAccuracyLevelColor(level) {
|
|||||||
function exportAttendanceWithAccuracy() {
|
function exportAttendanceWithAccuracy() {
|
||||||
// Build CSV header with location accuracy
|
// Build CSV header with location accuracy
|
||||||
const headers = [
|
const headers = [
|
||||||
|
"#",
|
||||||
"Employee ID",
|
"Employee ID",
|
||||||
|
"Employee Name",
|
||||||
"Location",
|
"Location",
|
||||||
"Event",
|
"Event",
|
||||||
"Date",
|
"Date",
|
||||||
@@ -979,17 +980,17 @@ function exportAttendanceWithAccuracy() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
// Build CSV rows
|
// Build CSV rows
|
||||||
const rows = filteredData.map((record) => [
|
const rows = filteredData.map((record, index) => [
|
||||||
|
index + 1,
|
||||||
record.employeeId,
|
record.employeeId,
|
||||||
|
record.employeeName || "Unknown",
|
||||||
record.location,
|
record.location,
|
||||||
record.event,
|
record.event,
|
||||||
record.date,
|
record.date,
|
||||||
record.time,
|
record.time,
|
||||||
record.qr_address,
|
record.qr_address,
|
||||||
record.checked_in_address,
|
record.checked_in_address,
|
||||||
record.location_accuracy !== null
|
record.location_accuracy ? record.location_accuracy.toFixed(3) : "Unknown",
|
||||||
? record.location_accuracy.toFixed(3)
|
|
||||||
: "Unknown",
|
|
||||||
record.accuracy_level,
|
record.accuracy_level,
|
||||||
record.device,
|
record.device,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -163,17 +163,18 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th onclick="sortTable(0)">#</th>
|
<th onclick="sortTable(0)">#</th>
|
||||||
<th onclick="sortTable(1)">Employee ID <i class="fas fa-sort"></i></th>
|
<th onclick="sortTable(1)">Employee ID <i class="fas fa-sort"></i></th>
|
||||||
<th onclick="sortTable(2)">Location <i class="fas fa-sort"></i></th>
|
<th onclick="sortTable(2)">Employee Name <i class="fas fa-sort"></i></th>
|
||||||
<th onclick="sortTable(3)">Event <i class="fas fa-sort"></i></th>
|
<th onclick="sortTable(3)">Location <i class="fas fa-sort"></i></th>
|
||||||
<th onclick="sortTable(4)">Date <i class="fas fa-sort"></i></th>
|
<th onclick="sortTable(4)">Event <i class="fas fa-sort"></i></th>
|
||||||
<th onclick="sortTable(5)">Time <i class="fas fa-sort"></i></th>
|
<th onclick="sortTable(5)">Date <i class="fas fa-sort"></i></th>
|
||||||
<th onclick="sortTable(6)" class="address-column">QR Address <i class="fas fa-sort"></i></th>
|
<th onclick="sortTable(6)">Time <i class="fas fa-sort"></i></th>
|
||||||
<th onclick="sortTable(7)" class="address-column">Check-in Address <i class="fas fa-sort"></i></th>
|
<th onclick="sortTable(7)" class="address-column">QR Address <i class="fas fa-sort"></i></th>
|
||||||
<th onclick="sortTable(8)">
|
<th onclick="sortTable(8)" class="address-column">Check-in Address <i class="fas fa-sort"></i></th>
|
||||||
|
<th onclick="sortTable(9)">
|
||||||
{% if has_location_accuracy_feature %}Location Accuracy{% else %}GPS Accuracy{% endif %}
|
{% if has_location_accuracy_feature %}Location Accuracy{% else %}GPS Accuracy{% endif %}
|
||||||
<i class="fas fa-sort"></i>
|
<i class="fas fa-sort"></i>
|
||||||
</th>
|
</th>
|
||||||
<th onclick="sortTable(9)">Device <i class="fas fa-sort"></i></th>
|
<th onclick="sortTable(10)">Device <i class="fas fa-sort"></i></th>
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -186,6 +187,12 @@
|
|||||||
<span class="employee-id">{{ record.employee_id }}</span>
|
<span class="employee-id">{{ record.employee_id }}</span>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="employee-name">
|
||||||
|
<i class="fas fa-user"></i>
|
||||||
|
<span>{{ record.employee_name if record.employee_name else 'Unknown' }}</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="location-info">
|
<div class="location-info">
|
||||||
<i class="fas fa-map-marker-alt"></i>
|
<i class="fas fa-map-marker-alt"></i>
|
||||||
|
|||||||
Reference in New Issue
Block a user