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.

1079 lines
27 KiB

​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head th:replace="~{fragments/modules/base/head :: head}"></head>
  4. <style>
  5. </style>
  6. <body>
  7. <div class="wrapper">
  8. <!-- header top menu Start -->
  9. <header th:replace="~{fragments/modules/base/header :: header}"></header>
  10. <!-- header top menu end -->
  11. <div class="page-wrap">
  12. <!--=============== Left Menu side Start ================-->
  13. <div th:replace="~{fragments/modules/base/menu :: menu}"></div>
  14. <!--=============== Left side End ================-->
  15. <div class="main-content">
  16. <div class="container-fluid">
  17. <div class="page-header mb-2">
  18. <div class="row align-items-end">
  19. <div class="col-lg-8">
  20. <div class="page-header-title">
  21. <!-- <i class="far fa-calendar-plus bg-blue"></i> -->
  22. <div class="d-inline">
  23. <h5 >Verification Checklist</h5>
  24. <span>Review and verify applicant information</span>
  25. </div>
  26. </div>
  27. </div>
  28. </div>
  29. </div>
  30. <div class="row">
  31. <div class="col-md-12">
  32. <div class="card" style="margin-top: 15px;">
  33. <div class="card-body">
  34. <input type="hidden" id="loginUserId" th:value="${loginUserId}">
  35. <div class="form-group">
  36. <div class="row" style="row-gap:10px;">
  37. <div class="col-sm-12 col-md-3">
  38. <label class="form-label" for="batchno">Batch No</label>
  39. <input type="text" class="form-control" id="batchno" placeholder="Enter Batch No" required>
  40. </div>
  41. <!-- Start SLNO -->
  42. <div class="col-sm-12 col-md-4">
  43. <label class="form-label" for="startSerialno">
  44. Unique NO
  45. </label>
  46. <input type="text" class="form-control" id="startSerialno" placeholder="Enter From Unique NO" required>
  47. </div>
  48. <!-- TO (Optional Text) -->
  49. <div class="col-sm-12 col-md-1 text-center">
  50. <label class="form-label d-block">&nbsp;</label>
  51. <span class="fw-bold">To</span>
  52. <small class="text-muted d-block">(Optional)</small>
  53. </div>
  54. <!-- End SLNO -->
  55. <div class="col-sm-12 col-md-4">
  56. <label class="form-label" for="endSerialno">&nbsp;</label>
  57. <input type="text" class="form-control" id="endSerialno" placeholder="Enter To Unique NO">
  58. </div>
  59. </div>
  60. <br>
  61. <div class="row" style="row-gap:10px;">
  62. <div class="col-sm-12 col-md-4" >
  63. <label class="form-label" for="mobilenumber">Mobile Number</label>
  64. <input type="text" class="form-control" id="mobilenumber" placeholder="Enter Mobile Number" required>
  65. </div>
  66. <!-- Department -->
  67. <div class="col-sm-12 col-md-4">
  68. <label class="form-label" for="department">Department
  69. </label>
  70. <select class="form-control" id="department" required>
  71. <option value=""> Select Department </option>
  72. </select>
  73. </div>
  74. <!-- Office Name -->
  75. <div class="col-sm-12 col-md-4">
  76. <label class="form-label" for="officename">Office Name
  77. </label>
  78. <select class="form-control" id="officename" required>
  79. <option value="">Select Office Name </option>
  80. </select>
  81. </div>
  82. </div>
  83. <br>
  84. <div class="row" style="row-gap:10px;">
  85. <!-- Left Side: Label + Radio Buttons -->
  86. <div class="col-sm-12 col-md-8">
  87. <label class="form-label d-block">Not Exist</label>
  88. <div class="form-check form-check-inline">
  89. <input class="form-check-input" type="radio" name="notExistOption" id="voterId" value="voterid">
  90. <label class="form-check-label" for="voterId">EPIC Number</label>
  91. </div>
  92. <div class="form-check form-check-inline">
  93. <input class="form-check-input" type="radio" name="notExistOption" id="mobile" value="mobile">
  94. <label class="form-check-label" for="mobile">Mobile Number</label>
  95. </div>
  96. <div class="form-check form-check-inline">
  97. <input class="form-check-input" type="radio" name="notExistOption" id="both" value="both">
  98. <label class="form-check-label" for="both">Both</label>
  99. </div>
  100. </div>
  101. </div>
  102. <div class="row mt-3">
  103. <div class="col-12 d-flex justify-content-center">
  104. <button type="button" class="btn btn-primary mx-2" id="searchBtn">Search</button>
  105. <button type="reset" class="btn btn-danger mx-2" id="resetBtn">Reset</button>
  106. </div>
  107. </div>
  108. </div>
  109. </div>
  110. </div>
  111. </div>
  112. </div>
  113. </div>
  114. <!-- verification data table -->
  115. <div class="row">
  116. <div class="col-12">
  117. <div class="card">
  118. <div class="card-header">
  119. <h3><b>Applicants for Checklist</b></h3>
  120. </div>
  121. <div class="card-body">
  122. <table id="batchDatatable" class="table table-striped table-bordered table-hover dataTable" role="grid" >
  123. <thead class="thead-dark" >
  124. <tr role="row">
  125. <th class="text-center">S.No</th>
  126. <th class="text-center">Unique No / Batch No</th>
  127. <th class="text-center">Name / Pay Scale / Cur.Basic /Grade Pay</th>
  128. <th class="text-center">Sex</th>
  129. <th class="text-center">Designation</th>
  130. <th class="text-center">State /Central</th>
  131. <th class="text-center">Office Address</th>
  132. <th class="text-center">Mobile</th>
  133. <th class="text-center">Residential Address</th>
  134. <th class="text-center">Native Constituency</th>
  135. <th class="text-center">Residential Constituency</th>
  136. <th class="text-center">Working Constituency</th>
  137. <th class="text-center">Enrolled - Part / Sl.No / EPIC /
  138. Assembly Constituency</th>
  139. <th class="text-center">Photo & Signature</th>
  140. <!--<th class="text-center">Verification</th>-->
  141. </tr>
  142. </thead>
  143. <tbody style="text-align:center;">
  144. </tbody>
  145. </table>
  146. <div class="row mt-3">
  147. <div class="col-12 d-flex justify-content-center">
  148. <button id="printBtn" class="btn btn-primary mt-2">
  149. <i class="fa fa-print"></i> Print
  150. </button>
  151. </div>
  152. </div>
  153. </div>
  154. </div>
  155. </div>
  156. </div>
  157. </div>
  158. <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;">
  159. <div style="position: relative; top: 50%; transform: translateY(-50%);">
  160. <div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;">
  161. <span class="sr-only">Loading...</span>
  162. </div>
  163. <!-- Add the 'Please wait' text below the spinner -->
  164. <p style="margin-top: 1rem; font-size: 1.2rem; color: #007bff;">Please wait...</p>
  165. </div>
  166. </div>
  167. <div th:replace="~{fragments/modules/base/app_module_menu_box :: div}"></div>
  168. <footer th:replace="~{fragments/modules/base/footer :: footer}"></footer>
  169. </div>
  170. </div>
  171. <script th:replace="~{fragments/modules/base/script :: script}"></script>
  172. <script type="text/javascript">
  173. document.getElementById('resetBtn').addEventListener('click', function () {
  174. event.preventDefault();
  175. location.reload();
  176. });
  177. $(document).ready(function () {
  178. // MOBILE NO: exactly 10 digits
  179. $('#mobilenumber').on('input', function () {
  180. // Allow only digits
  181. this.value = this.value.replace(/\D/g, '');
  182. // Max 10 digits
  183. if (this.value.length > 10) {
  184. this.value = this.value.slice(0, 10);
  185. }
  186. });
  187. $('#startSerialno').on('input', function () {
  188. // Allow only digits
  189. this.value = this.value.replace(/\D/g, '');
  190. });
  191. $('#endSerialno').on('input', function () {
  192. // Allow only digits
  193. this.value = this.value.replace(/\D/g, '');
  194. });
  195. $('#batchno').on('input', function () {
  196. // Allow only digits
  197. this.value = this.value.replace(/\D/g, '');
  198. });
  199. var table = $('#batchDatatable').DataTable({
  200. dom: 'Bftip',
  201. // columnDefs: [
  202. // { targets: 'no-sort', orderable: false }
  203. columnDefs: [
  204. { width: "150px", targets: 1 }, // Name / Pay Scale column
  205. { width: "150px", targets: 2 }, // Office Address column
  206. { width: "250px", targets: 6 },
  207. {width: "150px", targets: 12},
  208. {width: "100px", targets: 7},
  209. {width: "200px", targets: 8}
  210. ],
  211. lengthMenu: [
  212. [50, 100, 200, 500, -1],
  213. ['50 rows', '100 rows', '200 rows', 'Show all']
  214. ],
  215. scrollY: '80vh',
  216. scrollX: true,
  217. buttons: [
  218. {
  219. extend: 'pageLength',
  220. className: 'btn btn-warning'
  221. },
  222. {
  223. title: 'Data export',
  224. extend: 'copyHtml5',
  225. text: 'Copy',
  226. className: 'btn btn-secondary',
  227. id: 'copyBtn'
  228. },
  229. {
  230. extend: 'excelHtml5',
  231. text: 'Excel',
  232. className: 'btn btn-secondary',
  233. id: 'excelBtn'
  234. },
  235. {
  236. extend: 'csvHtml5',
  237. text: 'CSV',
  238. className: 'btn btn-secondary',
  239. id: 'csvBtn'
  240. },
  241. {
  242. extend: 'pdfHtml5',
  243. text: 'PDF',
  244. className: 'btn btn-secondary',
  245. id: 'pdfBtn'
  246. }
  247. ],
  248. fixedHeader: true,
  249. autoWidth: true,
  250. responsive: false,
  251. searching: true,
  252. select: false,
  253. processing: false
  254. });
  255. // ✅ Load Departments with searchable dropdown
  256. $.ajax({
  257. url: "/election/api/dataentryadmin/getalldepartments",
  258. method: "GET",
  259. success: function (data) {
  260. let department = $("#department");
  261. department.empty().append('<option value="">-- Select Department --</option>');
  262. data.forEach(dept => {
  263. department.append(
  264. `<option value="${dept.dept_id}">${dept.dept_name}</option>`
  265. );
  266. });
  267. // ✅ Enable search inside dropdown
  268. department.select2({
  269. placeholder: "Select Department",
  270. allowClear: true,
  271. width: '100%'
  272. });
  273. }
  274. });
  275. $("#department").on("change", function () {
  276. let deptId = $(this).val();
  277. let office = $("#officename");
  278. // Reset office dropdown
  279. office.empty().append('<option value="">-- Select Office Name --</option>');
  280. //office.select2('destroy'); // ✅ important
  281. if (deptId !== "") {
  282. $.ajax({
  283. url: "/election/api/dataentryadmin/getallofficenames",
  284. method: "GET",
  285. data: { deptId: deptId },
  286. success: function (data) {
  287. data.forEach(o => {
  288. office.append(
  289. `<option value="${o.id}">${o.office_full_address}</option>`
  290. );
  291. });
  292. // ✅ Enable searchable dropdown
  293. office.select2({
  294. placeholder: "Select Office Name",
  295. allowClear: true,
  296. width: '100%'
  297. });
  298. }
  299. });
  300. }
  301. });
  302. $(document).ready(function () {
  303. const initialParams = new URLSearchParams({
  304. batchNo: "",
  305. fromSLno: "",
  306. toSLno: "",
  307. mobileNo: "",
  308. category: "",
  309. officeName: "",
  310. notExist: ""
  311. });
  312. loadApplicants(initialParams.toString());
  313. });
  314. function loadApplicants(paramString) {
  315. $('#pageLoader').show();
  316. $.ajax({
  317. type: "GET",
  318. url: `/election/api/checklistadmin/getApplicants?${paramString}`,
  319. success: function (response) {
  320. console.log("API Response:", response);
  321. $('#pageLoader').hide();
  322. if (response.message === "success" && Array.isArray(response.data)) {
  323. $('#batchDatatable').DataTable({
  324. destroy: true,
  325. searching: true,
  326. autoWidth: true,
  327. paging: true,
  328. info: true,
  329. data: response.data,
  330. columns: [
  331. { data: null, className: 'text-center', render: (d,t,r,m) => m.row + 1 },
  332. {
  333. data: null,
  334. className: "text-center",
  335. render: r => `${r.slno || '-'}<br>/ ${r.batch_no || '-'}`
  336. },
  337. {
  338. data: null,
  339. className: "text-center",
  340. render: r => `
  341. ${r.name || '-'}<br>
  342. <small>
  343. ${r.pay_scale || '-'} /
  344. ${r.basic_pay || '-'} /
  345. ${r.grade_pay || '-'}
  346. </small>`
  347. },
  348. { data: 'sex', className: 'text-center' },
  349. { data: 'new_designation', className: 'text-center' },
  350. { data: 'govt_type', className: 'text-center' },
  351. {
  352. data: null,
  353. className: "text-center",
  354. render: r => `${r.office_name || '-'}<br>/ ${r.address || '-'}`
  355. },
  356. {
  357. data: null,
  358. className: 'text-center',
  359. render: r => `${r.r_mobile_no || ''}`
  360. },
  361. {
  362. data: null,
  363. className: 'text-center',
  364. render: r => `${r.r_address1 || ''} ${r.r_address2 || ''} ${r.r_address3 || ''} - ${r.r_pincode || ''}`
  365. },
  366. { data: null,
  367. className: 'text-center',
  368. render : r => `${r.native_ac_no || ''} - ${r.native_constituency || ''}`
  369. },
  370. { data: null,
  371. className: 'text-center',
  372. render : r => `${r.reside_ac_no || ''} - ${r.residential_constituency || ''}`
  373. },
  374. { data: null,
  375. className: 'text-center',
  376. render : r => `${r.work_ac_no || ''} - ${r.working_constituency || ''}`
  377. },
  378. {
  379. data: null,
  380. className: 'text-center',
  381. render: {
  382. display: r => `
  383. Part: ${r.elector_part_no || '-'}<br>
  384. Sl: ${r.elector_sl_no || '-'}<br>
  385. ${r.elector_epic_no || '-'}<br>
  386. ${r.elector_ac_no || '-'} - ${r.elector_constituency || '-'}
  387. `,
  388. export: r =>
  389. `Part: ${r.elector_part_no || '-'}\n` +
  390. `Sl: ${r.elector_sl_no || '-'}\n` +
  391. `${r.elector_epic_no || '-'}\n` +
  392. `${r.elector_ac_no || '-'} - ${r.elector_constituency || '-'}`
  393. }
  394. },
  395. {
  396. data: 'img_full_path',
  397. className: 'text-center',
  398. render: function (url, type, row) {
  399. if (!url) {
  400. return `<span style="color:red;">No Image</span>`;
  401. }
  402. return `
  403. <img src="${url}"
  404. style="height: 100px; width: 100px; object-fit: cover; border:1px solid #ccc;"
  405. alt="Photo">
  406. `;
  407. }
  408. },
  409. /*{
  410. data: 'poll_person_verify',
  411. className: 'text-center',
  412. render: function (flag, type, row) {
  413. if (flag == 1) {
  414. return `<span class="badge bg-success px-3 py-2"">Verified</span>`;
  415. } else {
  416. return `
  417. <input type="checkbox"
  418. class="verify-checkbox"
  419. value="${row.id}">
  420. `;
  421. }
  422. }
  423. }*/
  424. /*{
  425. data: null,
  426. className: 'text-center',
  427. render: function (data, type, row) {
  428. return `<button class="btn btn-warning btn-sm" onclick="verifyApplicant(${row.id})">
  429. Verify
  430. </button>`;
  431. }
  432. }*/
  433. ],
  434. dom: 'Bfrtip',
  435. buttons: [
  436. {
  437. extend: 'pageLength',
  438. className: 'btn btn-warning'
  439. },
  440. {
  441. title: 'Data export',
  442. extend: 'copyHtml5',
  443. text: 'Copy',
  444. className: 'btn btn-secondary',
  445. id: 'copyBtn'
  446. },
  447. {
  448. extend: 'excelHtml5',
  449. text: 'Excel',
  450. className: 'btn btn-secondary',
  451. id: 'excelBtn',
  452. filename: function () {
  453. return 'polling_personnel_details_' + getTimestamp();
  454. }
  455. },
  456. {
  457. extend: 'csvHtml5',
  458. text: 'CSV',
  459. className: 'btn btn-secondary',
  460. id: 'csvBtn',
  461. filename: function () {
  462. return 'polling_personnel_details_' + getTimestamp();
  463. }
  464. },
  465. {
  466. extend: 'pdfHtml5',
  467. text: 'PDF',
  468. className: 'btn btn-secondary',
  469. id: 'pdfBtn',
  470. title:'Polling Personnel Details',
  471. filename: function () {
  472. return 'polling_personnel_details_' + getTimestamp();
  473. },
  474. orientation: 'landscape',
  475. pageSize: 'A4',
  476. customize: function (doc) {
  477. doc.pageOrientation = 'landscape';
  478. // Reduce page margins to use full width
  479. doc.pageMargins = [10, 10, 10, 10];
  480. // Reduce default font size so columns fit
  481. doc.defaultStyle.fontSize = 7;
  482. doc.styles.tableHeader.fontSize = 8;
  483. // Force table to shrink inside page
  484. doc.content[1].table.widths = [
  485. 20, // S.No
  486. 30, // Unique/Batch
  487. 60, // Name / Pay Scale
  488. 20, // Sex
  489. 60, // Designation
  490. 30, // State / Central
  491. 100, // Office Address
  492. 50, // Mobile
  493. 90, // Residence Address
  494. 45, // Native
  495. 45, // Reside
  496. 45, // Work
  497. 70, // Enrolled
  498. 50 // Photo
  499. ];
  500. // Remove large default paddings
  501. var objLayout = {};
  502. objLayout['hLineWidth'] = function(i) { return 0.3; };
  503. objLayout['vLineWidth'] = function(i) { return 0.3; };
  504. objLayout['hLineColor'] = function(i) { return '#000'; };
  505. objLayout['vLineColor'] = function(i) { return '#000'; };
  506. objLayout['paddingLeft'] = function(i) { return 2; };
  507. objLayout['paddingRight'] = function(i) { return 2; };
  508. objLayout['paddingTop'] = function(i) { return 2; };
  509. objLayout['paddingBottom'] = function(i) { return 2; };
  510. doc.content[1].layout = objLayout;
  511. }
  512. }
  513. ],
  514. columnDefs: [
  515. { width: "150px", targets: 1 },
  516. { width: "150px", targets: 2 },
  517. { width: "250px", targets: 6 },
  518. {width: "150px", targets: 12},
  519. {width: "100px", targets: 7},
  520. {width: "200px", targets: 8}
  521. ],
  522. scrollY: '80vh',
  523. scrollX: true,
  524. responsive: false
  525. });
  526. } else {
  527. Swal.fire("No Data", "No records found", "warning");
  528. }
  529. },
  530. error: function (xhr) {
  531. $('#pageLoader').hide();
  532. console.log(" Server Error:", xhr.responseText);
  533. Swal.fire({
  534. icon: 'error',
  535. title: 'Error',
  536. text: 'Server error! Check console.',
  537. confirmButtonText: 'OK',
  538. allowOutsideClick: false,
  539. allowEscapeKey: false,
  540. allowEnterKey: false
  541. }).then(() => {
  542. location.reload(); // optional action
  543. });
  544. }
  545. });
  546. }
  547. document.getElementById('searchBtn').addEventListener('click', function () {
  548. let batchNo = document.getElementById('batchno').value || "";
  549. let fromSLno = document.getElementById('startSerialno').value || "";
  550. let toSLno = document.getElementById('endSerialno').value || "";
  551. let mobileNo = document.getElementById('mobilenumber').value || "";
  552. let category = document.getElementById('department').value || "";
  553. let officeName = document.getElementById('officename').value || "";
  554. let notExistRadio = document.querySelector('input[name="notExistOption"]:checked');
  555. let notExist = notExistRadio ? notExistRadio.value : "";
  556. if (
  557. !batchNo &&
  558. !fromSLno &&
  559. !toSLno &&
  560. !mobileNo &&
  561. !category &&
  562. !officeName &&
  563. !notExist
  564. ) {
  565. Swal.fire({
  566. icon: 'warning',
  567. title: 'Validation Error',
  568. text: 'Please select at least one field to search.',
  569. confirmButtonText: 'OK',
  570. allowOutsideClick: false,
  571. allowEscapeKey: false
  572. });
  573. return;
  574. }
  575. if (!fromSLno && toSLno) {
  576. Swal.fire({
  577. icon: 'warning',
  578. title: 'Validation Error',
  579. text: 'Please Enter SL No (From) to search.',
  580. confirmButtonText: 'OK',
  581. allowOutsideClick: false,
  582. allowEscapeKey: false
  583. });
  584. return;
  585. }
  586. if(mobileNo){
  587. // Rule 1: Must be exactly 10 digits & must not start with 0
  588. if (!/^[1-9][0-9]{9}$/.test(mobileNo)) {
  589. $('#pageLoader').hide();
  590. $('#saveBtn').prop('disabled', false).text('Update');
  591. Swal.fire({
  592. icon: 'warning',
  593. title: 'Invalid Mobile Number',
  594. text: 'Mobile number must be 10 digits and cannot start with 0.'
  595. });
  596. return;
  597. }
  598. // Rule 2: Reject sequential numbers like 1234567890
  599. if (mobileNo === "1234567890") {
  600. $('#pageLoader').hide();
  601. $('#saveBtn').prop('disabled', false).text('Update');
  602. Swal.fire({
  603. icon: 'warning',
  604. title: 'Invalid Mobile Number',
  605. text: 'Sequential numbers like 1234567890 are not allowed.'
  606. });
  607. return;
  608. }
  609. // Rule 3: Reject all digits same (1111111111, 2222222222, etc.)
  610. if (/^(\d)\1{9}$/.test(mobileNo)) {
  611. $('#pageLoader').hide();
  612. $('#saveBtn').prop('disabled', false).text('Update');
  613. Swal.fire({
  614. icon: 'warning',
  615. title: 'Invalid Mobile Number',
  616. text: 'All digits cannot be the same.'
  617. });
  618. return;
  619. }
  620. }
  621. const params = new URLSearchParams({
  622. batchNo,
  623. fromSLno,
  624. toSLno,
  625. mobileNo,
  626. category,
  627. officeName,
  628. notExist
  629. });
  630. loadApplicants(params.toString());
  631. });
  632. });
  633. /* $(document).on("change", ".verify-checkbox", function () {
  634. let checkedCount = $(".verify-checkbox:checked").length;
  635. if (checkedCount > 0) {
  636. $("#verifySelectedBtn").show();
  637. } else {
  638. $("#verifySelectedBtn").hide();
  639. }
  640. });*/
  641. /*$("#verifySelectedBtn").click(function () {
  642. let selectedIds = [];
  643. $(".verify-checkbox:checked").each(function () {
  644. selectedIds.push($(this).val());
  645. });
  646. if (selectedIds.length === 0) {
  647. Swal.fire("Warning", "Select at least one record", "warning");
  648. return;
  649. }
  650. Swal.fire({
  651. title: "Confirm Verification?",
  652. text: `Verify ${selectedIds.length} applicant(s)?`,
  653. icon: "question",
  654. showCancelButton: true,
  655. confirmButtonText: "Yes, Verify",
  656. allowOutsideClick: false,
  657. allowEscapeKey: false,
  658. allowEnterKey: false
  659. }).then((result) => {
  660. if (!result.isConfirmed) return;
  661. $.ajax({
  662. url: "/election/api/checklistadmin/verifyApplicants",
  663. type: "POST",
  664. traditional: true,
  665. data: { id: selectedIds },
  666. success: function (response) {
  667. if (response === "success") {
  668. Swal.fire({
  669. icon: "success",
  670. title: "Success",
  671. text: "Applicants Verified Successfully",
  672. confirmButtonText: "OK",
  673. allowOutsideClick: false,
  674. allowEscapeKey: false,
  675. allowEnterKey: false
  676. }).then((result) => {
  677. if (result.isConfirmed) {
  678. location.reload(); // ✅ Reload ONLY after OK click
  679. }
  680. });
  681. $("#verifySelectedBtn").hide();
  682. }
  683. },
  684. error: function () {
  685. Swal.fire({
  686. icon: "error",
  687. title: "Error",
  688. text: "Verification Failed",
  689. confirmButtonText: "OK",
  690. allowOutsideClick: false,
  691. allowEscapeKey: false,
  692. allowEnterKey: false
  693. });
  694. }
  695. });
  696. });
  697. });*/
  698. $(document).on("click", "#printBtn", function () {
  699. $('#pageLoader').show();
  700. let batchNo = $('#batchno').val() || "";
  701. let fromSLno = $('#startSerialno').val() || "";
  702. let toSLno = $('#endSerialno').val() || "";
  703. let mobileNo = $('#mobilenumber').val() || "";
  704. let category = $('#department').val() || "";
  705. let officeName = $('#officename').val() || "";
  706. let notExist = $("input[name='notExistOption']:checked").val() || "";
  707. const params = {
  708. batchNo,
  709. fromSLno,
  710. toSLno,
  711. mobileNo,
  712. category,
  713. officeName,
  714. notExist
  715. };
  716. $.ajax({
  717. url: "/election/api/report/checklist",
  718. method: "GET",
  719. data: params,
  720. xhrFields: {
  721. responseType: 'blob' // IMPORTANT
  722. },
  723. success: function (data, status, xhr) {
  724. $('#pageLoader').hide();
  725. /* console.log("Data: ", data);
  726. console.log("Status: ", status);
  727. console.log("Xhr: ", xhr); */
  728. if (xhr.status === 204 || data.size === 0) {
  729. Swal.fire("No Data Found", "No records available", "warning");
  730. return;
  731. }
  732. // Get filename from backend header
  733. let disposition = xhr.getResponseHeader("Content-Disposition");
  734. let fileName = "checklist_report.pdf"; // fallback
  735. if (disposition && disposition.indexOf("filename=") !== -1) {
  736. fileName = disposition.split("filename=")[1].trim();
  737. }
  738. const blob = new Blob([data], { type: "application/pdf" });
  739. const link = document.createElement("a");
  740. link.href = window.URL.createObjectURL(blob);
  741. link.download = fileName; // <-- use backend filename
  742. link.click();
  743. },
  744. error: function () {
  745. $('#pageLoader').hide();
  746. Swal.fire("Error", "PDF download failed", "error");
  747. }
  748. });
  749. });
  750. /* $(document).on("click", "#printBtn", function () {
  751. let table = $('#batchDatatable').DataTable();
  752. let rows = table.rows({ search: 'applied' }).nodes();
  753. let thead = $(".dataTables_scrollHead thead").clone();
  754. let printTable = `
  755. <table border="1" style="width:100%; border-collapse:collapse; text-align:center; font-size:12px;">
  756. ${thead.prop("outerHTML")}
  757. <tbody>
  758. `;
  759. rows.each(function (row) {
  760. printTable += `<tr>${row.innerHTML}</tr>`;
  761. });
  762. printTable += `</tbody></table>`;
  763. let printWindow = window.open("", "", "width=1200,height=800");
  764. printWindow.document.write(`
  765. <!DOCTYPE html>
  766. <html>
  767. <head>
  768. <title>Verification Checklist</title>
  769. <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
  770. <style>
  771. @page {
  772. size: landscape;
  773. }
  774. body {
  775. padding: 20px;
  776. font-family: Arial, sans-serif;
  777. font-size: 14px;
  778. }
  779. h4 {
  780. text-align: center;
  781. margin-bottom: 20px;
  782. font-size: 20px;
  783. font-weight: bold;
  784. }
  785. th, td {
  786. border: 1px solid #000;
  787. padding: 8px;
  788. text-align: center;
  789. vertical-align: top;
  790. white-space: normal;
  791. word-wrap: break-word;
  792. overflow-wrap: break-word;
  793. font-size: 15px;
  794. }
  795. th:nth-child(7),
  796. td:nth-child(7) {
  797. width: 220px;
  798. text-align: left;
  799. }
  800. table {
  801. width: 100%;
  802. border-collapse: collapse;
  803. table-layout: fixed;
  804. font-size: 13px;
  805. }
  806. input[type="checkbox"] {
  807. display: none;
  808. }
  809. button {
  810. display: none;
  811. }
  812. thead {
  813. display: table-header-group;
  814. }
  815. </style>
  816. </head>
  817. <body>
  818. <h4>Verification Checklist Report</h4>
  819. ${printTable}
  820. <script>
  821. window.onload = function () {
  822. window.print();
  823. window.close();
  824. };
  825. <\/script>
  826. </body>
  827. </html>
  828. `);
  829. printWindow.document.close();
  830. }); */
  831. function getTimestamp() {
  832. const now = new Date();
  833. const yyyy = now.getFullYear();
  834. const mm = String(now.getMonth() + 1).padStart(2, '0');
  835. const dd = String(now.getDate()).padStart(2, '0');
  836. const hh = String(now.getHours()).padStart(2, '0');
  837. const mi = String(now.getMinutes()).padStart(2, '0');
  838. const ss = String(now.getSeconds()).padStart(2, '0');
  839. return `${yyyy}${mm}${dd}_${hh}${mi}${ss}`;
  840. }
  841. </script>
  842. </body>
  843. </html>