You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

625 lines
15 KiB

<!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>