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.
 
 
 
 
 

1080 lines
27 KiB

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:replace="~{fragments/modules/base/head :: head}"></head>
<style>
</style>
<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-8">
<div class="page-header-title">
<!-- <i class="far fa-calendar-plus bg-blue"></i> -->
<div class="d-inline">
<h5 >Verification Checklist</h5>
<span>Review and verify applicant information</span>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="card" style="margin-top: 15px;">
<div class="card-body">
<input type="hidden" id="loginUserId" th:value="${loginUserId}">
<div class="form-group">
<div class="row" style="row-gap:10px;">
<div class="col-sm-12 col-md-3">
<label class="form-label" for="batchno">Batch No</label>
<input type="text" class="form-control" id="batchno" placeholder="Enter Batch No" required>
</div>
<!-- Start SLNO -->
<div class="col-sm-12 col-md-4">
<label class="form-label" for="startSerialno">
Unique NO
</label>
<input type="text" class="form-control" id="startSerialno" placeholder="Enter From Unique NO" required>
</div>
<!-- TO (Optional Text) -->
<div class="col-sm-12 col-md-1 text-center">
<label class="form-label d-block">&nbsp;</label>
<span class="fw-bold">To</span>
<small class="text-muted d-block">(Optional)</small>
</div>
<!-- End SLNO -->
<div class="col-sm-12 col-md-4">
<label class="form-label" for="endSerialno">&nbsp;</label>
<input type="text" class="form-control" id="endSerialno" placeholder="Enter To Unique NO">
</div>
</div>
<br>
<div class="row" style="row-gap:10px;">
<div class="col-sm-12 col-md-4" >
<label class="form-label" for="mobilenumber">Mobile Number</label>
<input type="text" class="form-control" id="mobilenumber" placeholder="Enter Mobile Number" required>
</div>
<!-- Department -->
<div class="col-sm-12 col-md-4">
<label class="form-label" for="department">Department
</label>
<select class="form-control" id="department" required>
<option value=""> Select Department </option>
</select>
</div>
<!-- Office Name -->
<div class="col-sm-12 col-md-4">
<label class="form-label" for="officename">Office Name
</label>
<select class="form-control" id="officename" required>
<option value="">Select Office Name </option>
</select>
</div>
</div>
<br>
<div class="row" style="row-gap:10px;">
<!-- Left Side: Label + Radio Buttons -->
<div class="col-sm-12 col-md-8">
<label class="form-label d-block">Not Exist</label>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="notExistOption" id="voterId" value="voterid">
<label class="form-check-label" for="voterId">EPIC Number</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="notExistOption" id="mobile" value="mobile">
<label class="form-check-label" for="mobile">Mobile Number</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="notExistOption" id="both" value="both">
<label class="form-check-label" for="both">Both</label>
</div>
</div>
</div>
<div class="row mt-3">
<div class="col-12 d-flex justify-content-center">
<button type="button" class="btn btn-primary mx-2" id="searchBtn">Search</button>
<button type="reset" class="btn btn-danger mx-2" id="resetBtn">Reset</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- verification data table -->
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h3><b>Applicants for Checklist</b></h3>
</div>
<div class="card-body">
<table id="batchDatatable" class="table table-striped table-bordered table-hover dataTable" role="grid" >
<thead class="thead-dark" >
<tr role="row">
<th class="text-center">S.No</th>
<th class="text-center">Unique No / Batch No</th>
<th class="text-center">Name / Pay Scale / Cur.Basic /Grade Pay</th>
<th class="text-center">Sex</th>
<th class="text-center">Designation</th>
<th class="text-center">State /Central</th>
<th class="text-center">Office Address</th>
<th class="text-center">Mobile</th>
<th class="text-center">Residential Address</th>
<th class="text-center">Native Constituency</th>
<th class="text-center">Residential Constituency</th>
<th class="text-center">Working Constituency</th>
<th class="text-center">Enrolled - Part / Sl.No / EPIC /
Assembly Constituency</th>
<th class="text-center">Photo & Signature</th>
<!--<th class="text-center">Verification</th>-->
</tr>
</thead>
<tbody style="text-align:center;">
</tbody>
</table>
<div class="row mt-3">
<div class="col-12 d-flex justify-content-center">
<button id="printBtn" class="btn btn-primary mt-2">
<i class="fa fa-print"></i> Print
</button>
</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 type="text/javascript">
document.getElementById('resetBtn').addEventListener('click', function () {
event.preventDefault();
location.reload();
});
$(document).ready(function () {
// MOBILE NO: exactly 10 digits
$('#mobilenumber').on('input', function () {
// Allow only digits
this.value = this.value.replace(/\D/g, '');
// Max 10 digits
if (this.value.length > 10) {
this.value = this.value.slice(0, 10);
}
});
$('#startSerialno').on('input', function () {
// Allow only digits
this.value = this.value.replace(/\D/g, '');
});
$('#endSerialno').on('input', function () {
// Allow only digits
this.value = this.value.replace(/\D/g, '');
});
$('#batchno').on('input', function () {
// Allow only digits
this.value = this.value.replace(/\D/g, '');
});
var table = $('#batchDatatable').DataTable({
dom: 'Bftip',
// columnDefs: [
// { targets: 'no-sort', orderable: false }
columnDefs: [
{ width: "150px", targets: 1 }, // Name / Pay Scale column
{ width: "150px", targets: 2 }, // Office Address column
{ width: "250px", targets: 6 },
{width: "150px", targets: 12},
{width: "100px", targets: 7},
{width: "200px", targets: 8}
],
lengthMenu: [
[50, 100, 200, 500, -1],
['50 rows', '100 rows', '200 rows', 'Show all']
],
scrollY: '80vh',
scrollX: true,
buttons: [
{
extend: 'pageLength',
className: 'btn btn-warning'
},
{
title: 'Data export',
extend: 'copyHtml5',
text: 'Copy',
className: 'btn btn-secondary',
id: 'copyBtn'
},
{
extend: 'excelHtml5',
text: 'Excel',
className: 'btn btn-secondary',
id: 'excelBtn'
},
{
extend: 'csvHtml5',
text: 'CSV',
className: 'btn btn-secondary',
id: 'csvBtn'
},
{
extend: 'pdfHtml5',
text: 'PDF',
className: 'btn btn-secondary',
id: 'pdfBtn'
}
],
fixedHeader: true,
autoWidth: true,
responsive: false,
searching: true,
select: false,
processing: false
});
// ✅ Load Departments with searchable dropdown
$.ajax({
url: "/election/api/dataentryadmin/getalldepartments",
method: "GET",
success: function (data) {
let department = $("#department");
department.empty().append('<option value="">-- Select Department --</option>');
data.forEach(dept => {
department.append(
`<option value="${dept.dept_id}">${dept.dept_name}</option>`
);
});
// ✅ Enable search inside dropdown
department.select2({
placeholder: "Select Department",
allowClear: true,
width: '100%'
});
}
});
$("#department").on("change", function () {
let deptId = $(this).val();
let office = $("#officename");
// Reset office dropdown
office.empty().append('<option value="">-- Select Office Name --</option>');
//office.select2('destroy'); // ✅ important
if (deptId !== "") {
$.ajax({
url: "/election/api/dataentryadmin/getallofficenames",
method: "GET",
data: { deptId: deptId },
success: function (data) {
data.forEach(o => {
office.append(
`<option value="${o.id}">${o.office_full_address}</option>`
);
});
// ✅ Enable searchable dropdown
office.select2({
placeholder: "Select Office Name",
allowClear: true,
width: '100%'
});
}
});
}
});
$(document).ready(function () {
const initialParams = new URLSearchParams({
batchNo: "",
fromSLno: "",
toSLno: "",
mobileNo: "",
category: "",
officeName: "",
notExist: ""
});
loadApplicants(initialParams.toString());
});
function loadApplicants(paramString) {
$('#pageLoader').show();
$.ajax({
type: "GET",
url: `/election/api/checklistadmin/getApplicants?${paramString}`,
success: function (response) {
console.log("API Response:", response);
$('#pageLoader').hide();
if (response.message === "success" && Array.isArray(response.data)) {
$('#batchDatatable').DataTable({
destroy: true,
searching: true,
autoWidth: true,
paging: true,
info: true,
data: response.data,
columns: [
{ data: null, className: 'text-center', render: (d,t,r,m) => m.row + 1 },
{
data: null,
className: "text-center",
render: r => `${r.slno || '-'}<br>/ ${r.batch_no || '-'}`
},
{
data: null,
className: "text-center",
render: r => `
${r.name || '-'}<br>
<small>
${r.pay_scale || '-'} /
${r.basic_pay || '-'} /
${r.grade_pay || '-'}
</small>`
},
{ data: 'sex', className: 'text-center' },
{ data: 'new_designation', className: 'text-center' },
{ data: 'govt_type', className: 'text-center' },
{
data: null,
className: "text-center",
render: r => `${r.office_name || '-'}<br>/ ${r.address || '-'}`
},
{
data: null,
className: 'text-center',
render: r => `${r.r_mobile_no || ''}`
},
{
data: null,
className: 'text-center',
render: r => `${r.r_address1 || ''} ${r.r_address2 || ''} ${r.r_address3 || ''} - ${r.r_pincode || ''}`
},
{ data: null,
className: 'text-center',
render : r => `${r.native_ac_no || ''} - ${r.native_constituency || ''}`
},
{ data: null,
className: 'text-center',
render : r => `${r.reside_ac_no || ''} - ${r.residential_constituency || ''}`
},
{ data: null,
className: 'text-center',
render : r => `${r.work_ac_no || ''} - ${r.working_constituency || ''}`
},
{
data: null,
className: 'text-center',
render: {
display: r => `
Part: ${r.elector_part_no || '-'}<br>
Sl: ${r.elector_sl_no || '-'}<br>
${r.elector_epic_no || '-'}<br>
${r.elector_ac_no || '-'} - ${r.elector_constituency || '-'}
`,
export: r =>
`Part: ${r.elector_part_no || '-'}\n` +
`Sl: ${r.elector_sl_no || '-'}\n` +
`${r.elector_epic_no || '-'}\n` +
`${r.elector_ac_no || '-'} - ${r.elector_constituency || '-'}`
}
},
{
data: 'img_full_path',
className: 'text-center',
render: function (url, type, row) {
if (!url) {
return `<span style="color:red;">No Image</span>`;
}
return `
<img src="${url}"
style="height: 100px; width: 100px; object-fit: cover; border:1px solid #ccc;"
alt="Photo">
`;
}
},
/*{
data: 'poll_person_verify',
className: 'text-center',
render: function (flag, type, row) {
if (flag == 1) {
return `<span class="badge bg-success px-3 py-2"">Verified</span>`;
} else {
return `
<input type="checkbox"
class="verify-checkbox"
value="${row.id}">
`;
}
}
}*/
/*{
data: null,
className: 'text-center',
render: function (data, type, row) {
return `<button class="btn btn-warning btn-sm" onclick="verifyApplicant(${row.id})">
Verify
</button>`;
}
}*/
],
dom: 'Bfrtip',
buttons: [
{
extend: 'pageLength',
className: 'btn btn-warning'
},
{
title: 'Data export',
extend: 'copyHtml5',
text: 'Copy',
className: 'btn btn-secondary',
id: 'copyBtn'
},
{
extend: 'excelHtml5',
text: 'Excel',
className: 'btn btn-secondary',
id: 'excelBtn',
filename: function () {
return 'polling_personnel_details_' + getTimestamp();
}
},
{
extend: 'csvHtml5',
text: 'CSV',
className: 'btn btn-secondary',
id: 'csvBtn',
filename: function () {
return 'polling_personnel_details_' + getTimestamp();
}
},
{
extend: 'pdfHtml5',
text: 'PDF',
className: 'btn btn-secondary',
id: 'pdfBtn',
title:'Polling Personnel Details',
filename: function () {
return 'polling_personnel_details_' + getTimestamp();
},
orientation: 'landscape',
pageSize: 'A4',
customize: function (doc) {
doc.pageOrientation = 'landscape';
// Reduce page margins to use full width
doc.pageMargins = [10, 10, 10, 10];
// Reduce default font size so columns fit
doc.defaultStyle.fontSize = 7;
doc.styles.tableHeader.fontSize = 8;
// Force table to shrink inside page
doc.content[1].table.widths = [
20, // S.No
30, // Unique/Batch
60, // Name / Pay Scale
20, // Sex
60, // Designation
30, // State / Central
100, // Office Address
50, // Mobile
90, // Residence Address
45, // Native
45, // Reside
45, // Work
70, // Enrolled
50 // Photo
];
// Remove large default paddings
var objLayout = {};
objLayout['hLineWidth'] = function(i) { return 0.3; };
objLayout['vLineWidth'] = function(i) { return 0.3; };
objLayout['hLineColor'] = function(i) { return '#000'; };
objLayout['vLineColor'] = function(i) { return '#000'; };
objLayout['paddingLeft'] = function(i) { return 2; };
objLayout['paddingRight'] = function(i) { return 2; };
objLayout['paddingTop'] = function(i) { return 2; };
objLayout['paddingBottom'] = function(i) { return 2; };
doc.content[1].layout = objLayout;
}
}
],
columnDefs: [
{ width: "150px", targets: 1 },
{ width: "150px", targets: 2 },
{ width: "250px", targets: 6 },
{width: "150px", targets: 12},
{width: "100px", targets: 7},
{width: "200px", targets: 8}
],
scrollY: '80vh',
scrollX: true,
responsive: false
});
} else {
Swal.fire("No Data", "No records found", "warning");
}
},
error: function (xhr) {
$('#pageLoader').hide();
console.log(" Server Error:", xhr.responseText);
Swal.fire({
icon: 'error',
title: 'Error',
text: 'Server error! Check console.',
confirmButtonText: 'OK',
allowOutsideClick: false,
allowEscapeKey: false,
allowEnterKey: false
}).then(() => {
location.reload(); // optional action
});
}
});
}
document.getElementById('searchBtn').addEventListener('click', function () {
let batchNo = document.getElementById('batchno').value || "";
let fromSLno = document.getElementById('startSerialno').value || "";
let toSLno = document.getElementById('endSerialno').value || "";
let mobileNo = document.getElementById('mobilenumber').value || "";
let category = document.getElementById('department').value || "";
let officeName = document.getElementById('officename').value || "";
let notExistRadio = document.querySelector('input[name="notExistOption"]:checked');
let notExist = notExistRadio ? notExistRadio.value : "";
if (
!batchNo &&
!fromSLno &&
!toSLno &&
!mobileNo &&
!category &&
!officeName &&
!notExist
) {
Swal.fire({
icon: 'warning',
title: 'Validation Error',
text: 'Please select at least one field to search.',
confirmButtonText: 'OK',
allowOutsideClick: false,
allowEscapeKey: false
});
return;
}
if (!fromSLno && toSLno) {
Swal.fire({
icon: 'warning',
title: 'Validation Error',
text: 'Please Enter SL No (From) to search.',
confirmButtonText: 'OK',
allowOutsideClick: false,
allowEscapeKey: false
});
return;
}
if(mobileNo){
// Rule 1: Must be exactly 10 digits & must not start with 0
if (!/^[1-9][0-9]{9}$/.test(mobileNo)) {
$('#pageLoader').hide();
$('#saveBtn').prop('disabled', false).text('Update');
Swal.fire({
icon: 'warning',
title: 'Invalid Mobile Number',
text: 'Mobile number must be 10 digits and cannot start with 0.'
});
return;
}
// Rule 2: Reject sequential numbers like 1234567890
if (mobileNo === "1234567890") {
$('#pageLoader').hide();
$('#saveBtn').prop('disabled', false).text('Update');
Swal.fire({
icon: 'warning',
title: 'Invalid Mobile Number',
text: 'Sequential numbers like 1234567890 are not allowed.'
});
return;
}
// Rule 3: Reject all digits same (1111111111, 2222222222, etc.)
if (/^(\d)\1{9}$/.test(mobileNo)) {
$('#pageLoader').hide();
$('#saveBtn').prop('disabled', false).text('Update');
Swal.fire({
icon: 'warning',
title: 'Invalid Mobile Number',
text: 'All digits cannot be the same.'
});
return;
}
}
const params = new URLSearchParams({
batchNo,
fromSLno,
toSLno,
mobileNo,
category,
officeName,
notExist
});
loadApplicants(params.toString());
});
});
/* $(document).on("change", ".verify-checkbox", function () {
let checkedCount = $(".verify-checkbox:checked").length;
if (checkedCount > 0) {
$("#verifySelectedBtn").show();
} else {
$("#verifySelectedBtn").hide();
}
});*/
/*$("#verifySelectedBtn").click(function () {
let selectedIds = [];
$(".verify-checkbox:checked").each(function () {
selectedIds.push($(this).val());
});
if (selectedIds.length === 0) {
Swal.fire("Warning", "Select at least one record", "warning");
return;
}
Swal.fire({
title: "Confirm Verification?",
text: `Verify ${selectedIds.length} applicant(s)?`,
icon: "question",
showCancelButton: true,
confirmButtonText: "Yes, Verify",
allowOutsideClick: false,
allowEscapeKey: false,
allowEnterKey: false
}).then((result) => {
if (!result.isConfirmed) return;
$.ajax({
url: "/election/api/checklistadmin/verifyApplicants",
type: "POST",
traditional: true,
data: { id: selectedIds },
success: function (response) {
if (response === "success") {
Swal.fire({
icon: "success",
title: "Success",
text: "Applicants Verified Successfully",
confirmButtonText: "OK",
allowOutsideClick: false,
allowEscapeKey: false,
allowEnterKey: false
}).then((result) => {
if (result.isConfirmed) {
location.reload(); // ✅ Reload ONLY after OK click
}
});
$("#verifySelectedBtn").hide();
}
},
error: function () {
Swal.fire({
icon: "error",
title: "Error",
text: "Verification Failed",
confirmButtonText: "OK",
allowOutsideClick: false,
allowEscapeKey: false,
allowEnterKey: false
});
}
});
});
});*/
$(document).on("click", "#printBtn", function () {
$('#pageLoader').show();
let batchNo = $('#batchno').val() || "";
let fromSLno = $('#startSerialno').val() || "";
let toSLno = $('#endSerialno').val() || "";
let mobileNo = $('#mobilenumber').val() || "";
let category = $('#department').val() || "";
let officeName = $('#officename').val() || "";
let notExist = $("input[name='notExistOption']:checked").val() || "";
const params = {
batchNo,
fromSLno,
toSLno,
mobileNo,
category,
officeName,
notExist
};
$.ajax({
url: "/election/api/report/checklist",
method: "GET",
data: params,
xhrFields: {
responseType: 'blob' // IMPORTANT
},
success: function (data, status, xhr) {
$('#pageLoader').hide();
/* console.log("Data: ", data);
console.log("Status: ", status);
console.log("Xhr: ", xhr); */
if (xhr.status === 204 || data.size === 0) {
Swal.fire("No Data Found", "No records available", "warning");
return;
}
// Get filename from backend header
let disposition = xhr.getResponseHeader("Content-Disposition");
let fileName = "checklist_report.pdf"; // fallback
if (disposition && disposition.indexOf("filename=") !== -1) {
fileName = disposition.split("filename=")[1].trim();
}
const blob = new Blob([data], { type: "application/pdf" });
const link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = fileName; // <-- use backend filename
link.click();
},
error: function () {
$('#pageLoader').hide();
Swal.fire("Error", "PDF download failed", "error");
}
});
});
/* $(document).on("click", "#printBtn", function () {
let table = $('#batchDatatable').DataTable();
let rows = table.rows({ search: 'applied' }).nodes();
let thead = $(".dataTables_scrollHead thead").clone();
let printTable = `
<table border="1" style="width:100%; border-collapse:collapse; text-align:center; font-size:12px;">
${thead.prop("outerHTML")}
<tbody>
`;
rows.each(function (row) {
printTable += `<tr>${row.innerHTML}</tr>`;
});
printTable += `</tbody></table>`;
let printWindow = window.open("", "", "width=1200,height=800");
printWindow.document.write(`
<!DOCTYPE html>
<html>
<head>
<title>Verification Checklist</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
<style>
@page {
size: landscape;
}
body {
padding: 20px;
font-family: Arial, sans-serif;
font-size: 14px;
}
h4 {
text-align: center;
margin-bottom: 20px;
font-size: 20px;
font-weight: bold;
}
th, td {
border: 1px solid #000;
padding: 8px;
text-align: center;
vertical-align: top;
white-space: normal;
word-wrap: break-word;
overflow-wrap: break-word;
font-size: 15px;
}
th:nth-child(7),
td:nth-child(7) {
width: 220px;
text-align: left;
}
table {
width: 100%;
border-collapse: collapse;
table-layout: fixed;
font-size: 13px;
}
input[type="checkbox"] {
display: none;
}
button {
display: none;
}
thead {
display: table-header-group;
}
</style>
</head>
<body>
<h4>Verification Checklist Report</h4>
${printTable}
<script>
window.onload = function () {
window.print();
window.close();
};
<\/script>
</body>
</html>
`);
printWindow.document.close();
}); */
function getTimestamp() {
const now = new Date();
const yyyy = now.getFullYear();
const mm = String(now.getMonth() + 1).padStart(2, '0');
const dd = String(now.getDate()).padStart(2, '0');
const hh = String(now.getHours()).padStart(2, '0');
const mi = String(now.getMinutes()).padStart(2, '0');
const ss = String(now.getSeconds()).padStart(2, '0');
return `${yyyy}${mm}${dd}_${hh}${mi}${ss}`;
}
</script>
</body>
</html>