Browse Source

Park Attendance Dashboard Updated code

master
kanimozhi 8 months ago
parent
commit
849aa6002f
  1. 74
      src/main/java/com/gcc/commissionerreview/service/AttendanceService.java
  2. 96
      src/main/resources/templates/modules/attendance-dashboard.html

74
src/main/java/com/gcc/commissionerreview/service/AttendanceService.java

@ -107,6 +107,71 @@ public class AttendanceService {
String dateColumn;
String filterDateColumn;
if (category != null && category.equalsIgnoreCase("notmarked")) {
dateColumn = "att.indatetime";
filterDateColumn = "att.indatetime";
String sql = "SELECT et.enrollment_id, et.name, et.designation, et.department, et.incharge_name, et.incharge_phoneno, et.park_name, emp.image as image "
+ " FROM enrollment_table et "
+ " left join gccfacialdb.employees emp on et.enrollment_id = emp.employeeid "
+ " where et.isactive =1 and et.isdelete = 0 and et.emp_type = ? and et.zone !=0 "
+ " and et.enrollment_id not in (select enrollment_id from attendance where date(indatetime) between ? and ?) ";
java.util.List<Object> params = new java.util.ArrayList<>();
params.add(empType);
params.add(fromDate);
params.add(toDate);
if (zone != null) {
sql += " and et.zone = ? ";
params.add(zone);
}
if (parkName != null && !parkName.isEmpty() && !parkName.equals("-")) {
sql += " and et.park_name = ? ";
params.add(parkName);
}
if (parkName != null && !parkName.isEmpty() && parkName.equals("-")) {
sql += " and et.park_name = '' ";
}
// sql += " order by " + dateColumn + " desc ";
System.out.println("EmpType: " + empType + ", Category: " + category + ", From: " + fromDateTime + ", To: "
+ toDateTime + ", Zone: " + zone + ", ParkName: " + parkName);
return jdbcTemplate.queryForList(sql, params.toArray());
} else if (category != null && category.equals("notregistered")) {
String sql = "SELECT et.enrollment_id, et.name, et.designation, et.department, et.incharge_name, et.incharge_phoneno, et.park_name, emp.image as image "
+ " FROM enrollment_table et "
+ " left join gccfacialdb.employees emp on et.enrollment_id = emp.employeeid "
+ " where et.isactive =1 and et.isdelete = 0 and et.emp_type = ? and et.zone !=0 and facial_attendance = 0 ";
java.util.List<Object> params = new java.util.ArrayList<>();
params.add(empType);
if (zone != null) {
sql += " and et.zone = ? ";
params.add(zone);
}
if (parkName != null && !parkName.isEmpty() && !parkName.equals("-")) {
sql += " and et.park_name = ? ";
params.add(parkName);
}
if (parkName != null && !parkName.isEmpty() && parkName.equals("-")) {
sql += " and et.park_name = '' ";
}
// sql += " order by " + dateColumn + " desc ";
System.out.println("EmpType: " + empType + ", Category: " + category + ", From: " + fromDateTime + ", To: "
+ toDateTime + ", Zone: " + zone + ", ParkName: " + parkName);
return jdbcTemplate.queryForList(sql, params.toArray());
} else {
switch (category == null ? "present" : category.toLowerCase()) {
case "od":
dateColumn = "att.oddatetime";
@ -154,6 +219,7 @@ public class AttendanceService {
+ toDateTime + ", Zone: " + zone + ", ParkName: " + parkName);
return jdbcTemplate.queryForList(sql, params.toArray());
}
}
public List<Map<String, Object>> getParkWiseSummary(String fromDateStr, String toDateStr, Integer zone) {
LocalDate fromDate;
@ -181,10 +247,10 @@ public class AttendanceService {
+ "SUM(CASE WHEN facial_attendance = 1 THEN 1 ELSE 0 END) AS facialRegistered, "
+ "SUM(CASE WHEN facial_attendance = 0 THEN 1 ELSE 0 END) AS facialNotRegistered "
+ "FROM enrollment_table "
+ "WHERE isactive = 1 AND isdelete = 0 AND emp_type = 'Park' AND zone = ? AND park_name != '' "
+ "WHERE isactive = 1 AND isdelete = 0 AND emp_type = 'Park' AND zone = ? "
+ "GROUP BY park_name "
+ ") "
+ "SELECT et.park_name, COUNT(DISTINCT et.enrollment_id) AS TotalCount, "
+ "SELECT et.park_name, COUNT(DISTINCT et.enrollment_id) AS TotalCount, et.incharge_name, et.incharge_phoneno, "
+ "COALESCE(fd.facialRegistered, 0) AS facialRegistered, COALESCE(fd.facialNotRegistered, 0) AS facialNotRegistered, "
+ "COUNT(DISTINCT CASE WHEN att.indatetime >= ? AND att.indatetime <= ? THEN att.enrollment_id END) AS AttendanceMarked, "
+ "COUNT(DISTINCT CASE WHEN att.oddatetime >= ? AND att.oddatetime <= ? THEN att.enrollment_id END) AS ODCount, "
@ -192,8 +258,8 @@ public class AttendanceService {
+ "FROM enrollment_table et "
+ "LEFT JOIN attendance att ON et.enrollment_id = att.enrollment_id "
+ "LEFT JOIN facial_data fd ON et.park_name = fd.park_name "
+ "WHERE et.isactive = 1 AND et.isdelete = 0 AND et.emp_type = 'Park' AND et.zone != 0 AND et.zone = ? AND et.park_name != '' "
+ "GROUP BY et.park_name, fd.facialRegistered, fd.facialNotRegistered "
+ "WHERE et.isactive = 1 AND et.isdelete = 0 AND et.emp_type = 'Park' AND et.zone != 0 AND et.zone = ? "
+ "GROUP BY et.park_name, fd.facialRegistered, fd.facialNotRegistered, et.incharge_name, et.incharge_phoneno "
+ "ORDER BY et.park_name";
return jdbcTemplate.queryForList(sql, new Object[] { zone, fromDateTime, toDateTime, fromDateTime, toDateTime,

96
src/main/resources/templates/modules/attendance-dashboard.html

@ -224,7 +224,7 @@
if (!Array.isArray(data)) { target.innerText = JSON.stringify(data); return; }
if (data.length === 0) { target.innerHTML = '<div class="alert alert-info">No records</div>'; return; }
const rows = data.slice().sort((a, b) => String(a.zone || '').localeCompare(String(b.zone || ''), undefined, { numeric: true }));
let html = '<table class="table table-sm table-striped"><thead><tr><th>Zone</th><th class="text-center">Total</th><th class="text-center">Facial Registered</th><th class="text-center">Facial Not Registered</th><th class="text-center">Present</th><th class="text-center">OD</th><th class="text-center">Leave</th></tr></thead><tbody>';
let html = '<table class="table table-sm table-striped"><thead><tr><th>Zone</th><th class="text-center">Total</th><th class="text-center">Facial Registered</th><th class="text-center">Facial Not Registered</th><th class="text-center">Present</th><th class="text-center">OD</th><th class="text-center">Leave</th><th class="text-center">Not Marked</th></tr></thead><tbody>';
rows.forEach(r => {
const zone = r.zone;
const total = Number(r.TotalCount) || 0;
@ -233,11 +233,14 @@
const present = Number(r.AttendanceMarked) || 0;
const od = Number(r.ODCount) || 0;
const leave = Number(r.LeaveCount) || 0;
const notMarked = total - present - od - leave;
html += `<tr><td>${zone || '-'}</td>`;
html += `<td class="text-center">${total}</td>`;
html += `<td class="text-center">${facialRegistered}</td>`;
html += `<td class="text-center">${facialNotRegistered}</td>`;
html += `<td class="text-center">` + (facialNotRegistered > 0
? `<a href="#" class="zone-count" data-zone="${zone}" data-emptype="${empType}" data-category="notregistered">${facialNotRegistered}</a>`
: `<span class="disabled-count">${facialNotRegistered}</span>`) + `</td>`;
html += `<td class="text-center">` + (present > 0
? `<a href="#" class="zone-count" data-zone="${zone}" data-emptype="${empType}" data-category="present">${present}</a>`
: `<span class="disabled-count">${present}</span>`) + `</td>`;
@ -247,9 +250,39 @@
html += `<td class="text-center">` + (leave > 0
? `<a href="#" class="zone-count" data-zone="${zone}" data-emptype="${empType}" data-category="leave">${leave}</a>`
: `<span class="disabled-count">${leave}</span>`) + `</td>`;
html += `<td class="text-center">` + (notMarked > 0
? `<a href="#" class="zone-count" data-zone="${zone}" data-emptype="${empType}" data-category="notmarked">${notMarked}</a>`
: `<span class="disabled-count">${notMarked}</span>`) + `</td>`;
html += '</tr>';
});
html += '</tbody></table>';
// Compute grand totals
let grandTotal = 0, grandFacialReg = 0, grandFacialNotReg = 0, grandPresent = 0, grandOd = 0, grandLeave = 0, grandNotMarked = 0;
rows.forEach(r => {
const total = Number(r.TotalCount) || 0;
const facialRegistered = Number(r.facialRegistered) || 0;
const facialNotRegistered = Number(r.facialNotRegistered) || 0;
const present = Number(r.AttendanceMarked) || 0;
const od = Number(r.ODCount) || 0;
const leave = Number(r.LeaveCount) || 0;
grandTotal += total;
grandFacialReg += facialRegistered;
grandFacialNotReg += facialNotRegistered;
grandPresent += present;
grandOd += od;
grandLeave += leave;
grandNotMarked += (total - present - od - leave);
});
html += '</tbody><tfoot><tr style="font-weight:bold; background-color:#e9ecef;">';
html += '<td>Total</td>';
html += `<td class="text-center">${grandTotal}</td>`;
html += `<td class="text-center">${grandFacialReg}</td>`;
html += `<td class="text-center">${grandFacialNotReg}</td>`;
html += `<td class="text-center">${grandPresent}</td>`;
html += `<td class="text-center">${grandOd}</td>`;
html += `<td class="text-center">${grandLeave}</td>`;
html += `<td class="text-center">${grandNotMarked}</td>`;
html += '</tr></tfoot></table>';
target.innerHTML = html;
}
@ -336,27 +369,63 @@
if (data.length === 0) { modalBody.innerHTML = '<div class="alert alert-info">No park-wise records</div>'; return; }
let html = '<div class="table-responsive"><table class="table table-sm table-striped"><thead><tr>';
html += '<th>Park Name</th><th class="text-center">Total</th><th class="text-center">Facial Registered</th><th class="text-center">Facial Not Registered</th><th class="text-center">Present</th><th class="text-center">OD</th><th class="text-center">Leave</th>';
html += '<th>Park Name</th><th>Incharge Name</th><th>Mobile Number</th><th class="text-center">Total</th><th class="text-center">Facial Registered</th><th class="text-center">Facial Not Registered</th><th class="text-center">Present</th><th class="text-center">OD</th><th class="text-center">Leave</th><th class="text-center">Not Marked</th>';
html += '</tr></thead><tbody>';
data.forEach(r => {
const park = r.park_name || '-';
const inchargeName = r.incharge_name || '-';
const inchargePhone = r.incharge_phoneno || '-';
const total = Number(r.TotalCount) || 0;
const facialRegistered = Number(r.facialRegistered) || 0;
const facialNotRegistered = Number(r.facialNotRegistered) || 0;
const present = Number(r.AttendanceMarked) || 0;
const od = Number(r.ODCount) || 0;
const leave = Number(r.LeaveCount) || 0;
const notMarked = total - present - od - leave;
html += '<tr>';
html += `<td>${park}</td>`;
html += `<td>${inchargeName}</td>`;
html += `<td>${inchargePhone}</td>`;
html += `<td class="text-center">${total}</td>`;
html += `<td class="text-center">${facialRegistered}</td>`;
html += `<td class="text-center">${facialNotRegistered}</td>`;
// html += `<td class="text-center">${facialNotRegistered}</td>`;
html += `<td class="text-center">` + (facialNotRegistered > 0 ? `<a href="#" class="park-employee-count" data-zone="${zone}" data-park="${park}" data-category="notregistered">${facialNotRegistered}</a>` : `<span class="disabled-count">${facialNotRegistered}</span>`) + `</td>`;
html += `<td class="text-center">` + (present > 0 ? `<a href="#" class="park-employee-count" data-zone="${zone}" data-park="${park}" data-category="present">${present}</a>` : `<span class="disabled-count">${present}</span>`) + `</td>`;
html += `<td class="text-center">` + (od > 0 ? `<a href="#" class="park-employee-count" data-zone="${zone}" data-park="${park}" data-category="od">${od}</a>` : `<span class="disabled-count">${od}</span>`) + `</td>`;
html += `<td class="text-center">` + (leave > 0 ? `<a href="#" class="park-employee-count" data-zone="${zone}" data-park="${park}" data-category="leave">${leave}</a>` : `<span class="disabled-count">${leave}</span>`) + `</td>`;
html += `<td class="text-center">` + (notMarked > 0 ? `<a href="#" class="park-employee-count" data-zone="${zone}" data-park="${park}" data-category="notmarked">${notMarked}</a>` : `<span class="disabled-count">${notMarked}</span>`) + `</td>`;
html += '</tr>';
});
html += '</tbody></table></div>';
// Compute grand totals for park-wise summary
let grandTotal = 0, grandFacialReg = 0, grandFacialNotReg = 0, grandPresent = 0, grandOd = 0, grandLeave = 0, grandNotMarked = 0;
data.forEach(r => {
const total = Number(r.TotalCount) || 0;
const facialRegistered = Number(r.facialRegistered) || 0;
const facialNotRegistered = Number(r.facialNotRegistered) || 0;
const present = Number(r.AttendanceMarked) || 0;
const od = Number(r.ODCount) || 0;
const leave = Number(r.LeaveCount) || 0;
grandTotal += total;
grandFacialReg += facialRegistered;
grandFacialNotReg += facialNotRegistered;
grandPresent += present;
grandOd += od;
grandLeave += leave;
grandNotMarked += (total - present - od - leave);
});
html += '</tbody><tfoot><tr style="font-weight:bold; background-color:#e9ecef;">';
html += '<td>Total</td>';
html += '<td></td>';
html += '<td></td>';
html += `<td class="text-center">${grandTotal}</td>`;
html += `<td class="text-center">${grandFacialReg}</td>`;
html += `<td class="text-center">${grandFacialNotReg}</td>`;
html += `<td class="text-center">${grandPresent}</td>`;
html += `<td class="text-center">${grandOd}</td>`;
html += `<td class="text-center">${grandLeave}</td>`;
html += `<td class="text-center">${grandNotMarked}</td>`;
html += '</tr></tfoot></table></div>';
modalBody.innerHTML = html;
} catch (e) {
modalBody.innerHTML = `<div class="alert alert-danger">Error: ${e}</div>`;
@ -454,6 +523,12 @@
displayColumns = ['enrollment_id', 'name', 'designation', 'department', 'incharge_name', 'incharge_phoneno', 'App Version', 'App Type', 'Location'];
if (empType === 'Park') displayColumns.push('park_name');
displayColumns.push('odtime', 'odby');
} else if (catLower === 'notmarked') {
displayColumns = ['enrollment_id', 'name', 'designation', 'department', 'incharge_name', 'incharge_phoneno', 'image'];
// if (empType === 'Park') displayColumns.push('park_name');
} else if (catLower === 'notregistered') {
displayColumns = ['enrollment_id', 'name', 'designation', 'department', 'incharge_name', 'incharge_phoneno'];
// if (empType === 'Park') displayColumns.push('park_name');
} else {
displayColumns = Object.keys(data[0]);
}
@ -490,7 +565,8 @@
incharge_phoneno: 'Incharge Contact',
appversion: 'App Version',
apptype: 'App Type',
location: 'Location'
location: 'Location',
image: 'Image'
};
if (map[key]) return map[key];
return key.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
@ -516,7 +592,7 @@
// html += `<td>${val != null ? val : '-'}</td>`;
// }
if ((k === 'inphoto' || k === 'outphoto') && val) {
if ((k === 'inphoto' || k === 'outphoto' || k === 'image') && val) {
html += `<td>
<img src="${val}" alt="photo"
style="max-width: 100px; max-height: 100px; cursor: pointer;"
@ -607,7 +683,8 @@
<!-- Park-wise Summary Modal -->
<div class="modal fade" id="parkWiseSummaryModal" tabindex="-1" aria-labelledby="parkWiseSummaryModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-scrollable">
<!-- <div class="modal-dialog modal-lg modal-dialog-scrollable"> -->
<div class="modal-dialog modal-xl modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="parkWiseSummaryModalLabel">Park-wise Summary</h5>
@ -630,6 +707,7 @@
<!-- Detail modal -->
<div class="modal fade" id="detailModal" tabindex="-1" aria-labelledby="detailModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl modal-dialog-scrollable">
<!-- <div class="modal-dialog modal-fullscreen modal-dialog-scrollable"> -->
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="detailModalLabel">Details</h5>

Loading…
Cancel
Save