|
|
<!DOCTYPE html><html lang="en" xmlns:th="http://www.thymeleaf.org"><head th:replace="~{fragments/modules/base/head :: head}"> <style>
</style></head><body>
<div class="wrapper"> <!-- header top menu Start --> <header th:replace="~{fragments/modules/base/header :: header}"></header> <!-- header top menu end --> <div class="page-wrap"> <!--=============== Left Menu side Start ================--> <div th:replace="~{fragments/modules/base/menu :: menu}"></div> <!--=============== Left side End ================--> <div class="main-content"> <div class="container-fluid">
<div class="page-header mb-2"> <div class="row align-items-end"> <div class="col-lg-7"> <div class="page-header-title"> <i class="fas fa-file-invoice bg-blue"></i> <div class="d-inline"> <h5>Attendance</h5> <span>Manage the Attendance file</span> </div> </div> </div> <div class="col-lg-5"> <span id="constituencySpan"></span> </div> </div> </div>
<div class="row"> <div class="col-md-12"> <div class="card mt-2"> <div class="card-header" style="font-weight: bold;"> To Get Attendance Training Template </div> <div class="card-body d-flex align-items-end">
<span th:text="${loginUserId}" style="display:none;" id="userIdSpan"></span> <span th:text="${mapped_ac}" style="display:none;" id="mapped_ac"></span>
<!-- Dropdown --> <div class="col-sm-4"> <label for="attendance">Select Training</label> <select id="attendance" class="form-control"> <option value="">Select</option><!-- <option value="1" selected="selected">First Training Attendance</option>--> <!-- <option value="2" selected="selected">Second Training Attendance</option> --> <!-- <option value="3" selected="selected">Second Repeat Training Attendance</option> --> <option value="4" selected="selected">Third Training Attendance</option> </select> </div>
<!-- Button (hidden initially) --> <div class="col-sm-4" id="downloadBtnDiv" > <button id="downloadTemplateBtn" class="btn btn-primary"> Template Download </button> </div>
</div>
<div class="mt-3"> <div class="alert alert-info mb-0"> <strong>Note:</strong> <ol class="mb-0 pl-3"> <li>
Kindly download the template, <b>update only the absentees’ Sl.No.</b> along with the required details, and upload the Excel file. <!-- Only the <b>Attendance Status</b> field is editable in the downloaded Excel file. Kindly update the attendance status and upload the file.--> </li> <li> Re-uploading will <b>clear previous attendance </b> and new attendance will be captured. Please review before proceeding . </li> </ol> </div> </div>
</div> </div> </div>
<div class="row mt-1"> <div class="col-md-12"> <div class="card mt-2"> <div class="card-header" style="font-weight: bold;"> Upload Attendance Training Data </div> <div class="card-body d-flex align-items-end">
<!-- Dropdown --> <div class="col-sm-4"> <label for="dattendance">Select Training</label> <select id="dattendance" class="form-control"> <option value="">Select</option><!-- <option value="1" selected="selected">First Training Attendance</option>--> <!-- <option value="2" selected="selected">Second Training Attendance</option> --> <!-- <option value="3" selected="selected">Second Repeat Training Attendance</option> --> <option value="4" selected="selected">Third Training Attendance</option> </select> </div> <div class="col-sm-4"> <label for="fileUpload">File Upload</label> <input type="file" id="fileUpload" class="form-control" accept=".xlsx,.csv">
</div>
<!-- Button (hidden initially) --> <div class="col-sm-4" id="uploadBtnDiv"> <button id="uploadTemplateBtn" class="btn btn-primary"> File Upload </button> <button id="resetBtn" class="btn btn-secondary"> Reset </button> </div>
</div>
<div class="mt-3"> <div class="alert alert-info mb-0"> <strong>Note:</strong> <ol class="mb-0 pl-3"> <li>
Kindly download the template, <b>update only the absentees’ Sl.No.</b> along with the required details, and upload the Excel file. </li> <li> Re-uploading will <b>clear previous attendance </b> and new attendance will be captured. Please review before proceeding . </li> </ol> </div> </div>
</div> </div> </div>
</div> </div> <div id="pageLoader" style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); z-index: 9999; text-align: center;"> <div style="position: relative; top: 50%; transform: translateY(-50%);"> <div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;"> <span class="sr-only">Loading...</span> </div> <!-- Add the 'Please wait' text below the spinner --> <p style="margin-top: 1rem; font-size: 1.2rem; color: #007bff;">Please wait...</p> </div> </div>
<div th:replace="~{fragments/modules/base/app_module_menu_box :: div}"></div>
<footer th:replace="~{fragments/modules/base/footer :: footer}"></footer> </div></div>
<script th:replace="~{fragments/modules/base/script :: script}"></script>
<script src="dist/js/xlsx.full.min.js"></script>
<!-- \static\assets\dist\js\xlsx.full.min.js -->
<script type="text/javascript"> let userId = document.getElementById('userIdSpan').textContent; let mapped_ac = document.getElementById('mapped_ac').textContent; $(document).ready(function() {
$.ajax({ url: "/election/api/dataentryadmin/attendance/trainingconstituencies", method: "GET", data:{c_code:mapped_ac}, success: function (data) { console.log("Response:", data);
let spanText = "";
if (data && data.length > 0) {
$.each(data, function (index, item) { spanText += item.c_code +'-'+ item.display_name;
// if multiple records → add comma or line break if (index !== data.length - 1) { spanText += ", "; // OR use "<br>" for new line } });
} else { spanText = "No Constituency Found"; }
$('#constituencySpan').html(spanText); }, error: function () { alert("Failed to fetch allocated training constituency"); } });
});
$('#attendance').on('change', function () { let selectedAtt = $(this).val(); if (selectedAtt) { console.log("selectedAtt="+selectedAtt); console.log("userId="+userId); console.log("mapped_ac="+mapped_ac); if(!userId){ Swal.fire({ icon: 'warning', title: 'No UserId Mapped', text: 'Issue in login userid' });
return; } if(!mapped_ac){ Swal.fire({ icon: 'warning', title: 'No Mapped Ac', text: 'Issue in AC Mapping' }); //$('#downloadBtnDiv').hide(); return; } //$('#downloadBtnDiv').show();
} else{ //$('#downloadBtnDiv').hide(); return; } });
$('#downloadTemplateBtn').on('click', function () { let ctraining=$('#attendance').val(); if(!ctraining){ Swal.fire({ icon: 'warning', title: 'Missing Training', text: 'Please Select Training' });
return; }
getTemplate(mapped_ac,ctraining); });
$('#resetBtn').on('click', function () {
$('#fileUpload').val(''); });
$('#dattendance').on('change', function () { let selectedAtt = $(this).val(); if (selectedAtt) { console.log("selectedAtt="+selectedAtt); console.log("userId="+userId); console.log("mapped_ac="+mapped_ac); if(!userId){ Swal.fire({ icon: 'warning', title: 'No UserId Mapped', text: 'Issue in login userid' });
return; } if(!mapped_ac){ Swal.fire({ icon: 'warning', title: 'No Mapped Ac', text: 'Issue in AC Mapping' }); //$('#downloadBtnDiv').hide(); return; } //$('#uploadBtnDiv').show();
} else{ //$('#uploadBtnDiv').hide(); return; } });
$('#uploadTemplateBtn').on('click', function () {
let fileInput = $('#fileUpload')[0]; let file = fileInput.files[0]; let training=$('#dattendance').val();
if (!training) { Swal.fire({ icon: 'warning', title: 'No Attendance Training Selected', text: 'Please Select Attendance Training' }); return; }
if (!file) { Swal.fire({ icon: 'warning', title: 'No File Selected', text: 'Please choose a file to upload' }); return; }
let fileName = file.name.toLowerCase();
if (!(fileName.endsWith('.xlsx') || fileName.endsWith('.csv'))) { Swal.fire({ icon: 'error', title: 'Invalid File Type', text: 'Only .xlsx or .csv files are allowed' });
$('#fileUpload').val(''); return; }
// Valid file console.log("File ready for upload:", fileName); uploadfile(training,userId,mapped_ac,file);
});
function uploadfile(training, userId, mapped_ac, file) {
if(training=="4"){ const expectedHeaders = ["HALL_NO","CATEGORY","SLNO", "NAME"];
const reader = new FileReader();
reader.onload = function (e) { const data = new Uint8Array(e.target.result); const workbook = XLSX.read(data, { type: 'array' });
const sheetName = workbook.SheetNames[0]; const sheet = workbook.Sheets[sheetName];
const jsonData = XLSX.utils.sheet_to_json(sheet, { header: 1 });
// 1. Check Header let header = jsonData[0];
if (!header || header.length < 4) { Swal.fire("Invalid File", "Header row missing or incorrect", "error"); return; }
for (let i = 0; i < expectedHeaders.length; i++) { if ((header[i] || '').toString().trim().toUpperCase() !== expectedHeaders[i]) { Swal.fire("Invalid Header", "Excel header mismatch", "error"); return; } }
// 2. Validate Rows let validData = [];
for (let i = 1; i < jsonData.length; i++) { let row = jsonData[i];
if (!row || row.length === 0) continue;
let hallno =row[0]; let cat =row[1]; let slno = row[2]; let name = row[3];
// Empty check if (!hallno || !cat ||!slno || !name) { Swal.fire("Invalid Data", `Empty cell found at row ${i + 1}`, "error"); return; }
// HallNo validation (reject 01, 02, etc.) let hallStr = hallno.toString().trim();
if (hallStr.startsWith('0') && hallStr.length > 1) { Swal.fire("Invalid HallNo", `HallNo should not start with 0 at row ${i + 1}`, "error"); return; }
validData.push({ hallno:hallno, cat:cat, slno: slno, name: name
}); }
$.ajax({ url: "/election/api/election_attendance/getAttendanceId", type: "GET", data: { training: training, mappedAc: mapped_ac // match param name in controller }, success: function (res) {
console.log("Attendance ID response:", res);
let attendanceFileId = res.attendanceId;
if (!attendanceFileId) {
saveAttendanceData(training, userId, mapped_ac, validData, file); return; }
Swal.fire({ title: "Data Already Exists", text: "Do you want to overwrite existing attendance?", icon: "warning", showCancelButton: true, confirmButtonText: "Yes, Update", cancelButtonText: "Cancel" }).then((result) => {
if (result.isConfirmed) {
$.ajax({ url: "/election/api/election_attendance/deactivateAttendance", type: "POST", contentType: "application/json", data: JSON.stringify({ attendanceId: attendanceFileId, data : validData, mappedAc:mapped_ac }), success: function (updateRes) {
console.log("Deactivate response:", updateRes);
if (updateRes.status === "error") { Swal.fire({ icon: "error", title: updateRes.message }); return; }
saveAttendanceData(training, userId, mapped_ac, validData, file); }, error: function () {
Swal.fire("Error", "Failed to deactivate old data", "error"); } });
} else { console.log("User cancelled"); } });
}, error: function () { Swal.fire("Error", "Failed to fetch attendance file ID", "error"); } });
};
reader.readAsArrayBuffer(file); }/* else if(training=="5"){ Swal.fire("Please Select Current Training", "No Template For this Training", "error"); return; } */ else{ Swal.fire("Please Select Current Training", "No Template For this Training", "error"); return; }
}
function saveAttendanceData(training, userId, mapped_ac, dataList, file) {
$('#pageLoader').show();
let formData = new FormData();
formData.append("file", file); formData.append("training", training); formData.append("userId", userId); formData.append("mapped_ac", mapped_ac); formData.append("data", JSON.stringify(dataList));
$.ajax({ url: '/election/api/election_attendance/uploadAttendance', type: 'POST', data: formData, processData: false, contentType: false, success: function () { $('#pageLoader').hide();
Swal.fire({ icon: 'success', title: 'Uploaded Successfully', allowOutsideClick: false, allowEscapeKey: false, allowEnterKey: false }).then(() => { location.reload(); }); }, error: function (xhr) { $('#pageLoader').hide();
let msg = "Upload Failed";
if (xhr.responseText) { msg = xhr.responseText; }
Swal.fire({ icon: 'warning', title: msg }); } }); }
function getTemplate(mapped_ac,ctraining) {
if (!mapped_ac) { Swal.fire({ icon: 'warning', title: 'Missing AC', text: 'AC value is required' }); return; } if (!ctraining) { Swal.fire({ icon: 'warning', title: 'Missing Training', text: 'Select Training is required' }); return; }
$('#pageLoader').show();
// Step 1: Check data first $.ajax({ url: '/election/api/election_attendance/checkAttendanceData', type: 'GET', data: { mapped_ac: mapped_ac,ctraining:ctraining }, success: function (res) {
if (res.status) {
// Step 2: Trigger download using iframe let iframe = document.createElement('iframe'); iframe.style.display = 'none';
iframe.src = '/election/api/election_attendance/getAttendanceExcel?mapped_ac=' + mapped_ac+'&ctraining='+ctraining;
document.body.appendChild(iframe);
// Keep loader for a few seconds (until download triggers) setTimeout(function () { $('#pageLoader').hide(); }, 3000);
} else { $('#pageLoader').hide(); Swal.fire({ icon: 'warning', title: res.message }); } }, error: function () { $('#pageLoader').hide(); Swal.fire({ icon: 'error', title: 'Error', text: 'Unable to process request' }); } }); }
</script></body></html>
|