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.

1117 lines
30 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 >Micro-Observer 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="serialno">
  44. Unique Number
  45. </label>
  46. <input type="text" class="form-control" id="startSerialno" placeholder="Enter From Unique Number" 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="serialno">&nbsp;</label>
  57. <input type="text" class="form-control" id="endSerialno" placeholder="Enter To Unique Number">
  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. $.ajax({
  256. url: "/election/api/dataentryadmin/getalldepartments",
  257. method: "GET",
  258. success: function (data) {
  259. let department = $("#department");
  260. department.empty().append('<option value="">-- Select Department --</option>');
  261. data.forEach(dept => {
  262. department.append(
  263. `<option value="${dept.dept_id}">${dept.dept_name}</option>`
  264. );
  265. });
  266. // ✅ Enable search inside dropdown
  267. department.select2({
  268. placeholder: "Select Department",
  269. allowClear: true,
  270. width: '100%'
  271. });
  272. }
  273. });
  274. /* $.ajax({
  275. url: "/election/api/dataentryadmin/getalldepartments",
  276. method: "GET",
  277. success: function (data) {
  278. console.log("Departments data:", data);
  279. let department = $("#department");
  280. department.empty().append('<option value="">-- Select Department --</option>');
  281. data.forEach(dept => {
  282. department.append(`<option value="${dept.dept_id}">${dept.dept_name}</option>`);
  283. });
  284. }
  285. }); */
  286. // load office name
  287. $("#department").on("change", function () {
  288. let deptId = $(this).val();
  289. let office = $("#officename");
  290. // Reset office dropdown
  291. office.empty().append('<option value="">-- Select Office Name --</option>');
  292. //office.select2('destroy'); // ✅ important
  293. if (deptId !== "") {
  294. $.ajax({
  295. url: "/election/api/dataentryadmin/getallofficenames",
  296. method: "GET",
  297. data: { deptId: deptId },
  298. success: function (data) {
  299. data.forEach(o => {
  300. office.append(
  301. `<option value="${o.id}">${o.office_full_address}</option>`
  302. );
  303. });
  304. // ✅ Enable searchable dropdown
  305. office.select2({
  306. placeholder: "Select Office Name",
  307. allowClear: true,
  308. width: '100%'
  309. });
  310. }
  311. });
  312. }
  313. });
  314. /* // load office name
  315. $("#department").on("change", function () {
  316. let deptId = $(this).val();
  317. console.log("dpetId",deptId)
  318. $("#officename").empty().append('<option value="">-- Select Office Name --</option>');
  319. if (deptId !== "") {
  320. $.ajax({
  321. url: "/election/api/dataentryadmin/getallofficenames",
  322. method: "GET",
  323. data: { deptId: deptId }, // <-- Correct parameter name
  324. success: function (data) {
  325. console.log("data",data)
  326. data.forEach(o => {
  327. $("#officename").append(
  328. `<option value="${o.id}">${o.office_name}</option>`
  329. );
  330. });
  331. }
  332. });
  333. }
  334. }); */
  335. $(document).ready(function () {
  336. const initialParams = new URLSearchParams({
  337. batchNo: "",
  338. fromSLno: "",
  339. toSLno: "",
  340. mobileNo: "",
  341. category: "",
  342. officeName: "",
  343. notExist: ""
  344. });
  345. loadApplicants(initialParams.toString());
  346. });
  347. function loadApplicants(paramString) {
  348. $('#pageLoader').show();
  349. $.ajax({
  350. type: "GET",
  351. url: `/election/api/checklistadminmob/getApplicants?${paramString}`,
  352. success: function (response) {
  353. console.log("API Response:", response);
  354. $('#pageLoader').hide();
  355. if (response.message === "success" && Array.isArray(response.data)) {
  356. $('#batchDatatable').DataTable({
  357. destroy: true,
  358. searching: true,
  359. autoWidth: true,
  360. paging: true,
  361. info: true,
  362. data: response.data,
  363. columns: [
  364. { data: null, className: 'text-center', render: (d,t,r,m) => m.row + 1 },
  365. {
  366. data: null,
  367. className: "text-center",
  368. render: r => `${r.slno || '-'}<br>/ ${r.batch_no || '-'}`
  369. },
  370. {
  371. data: null,
  372. className: "text-center",
  373. render: r => `
  374. ${r.name || '-'}<br>
  375. <small>
  376. ${r.pay_scale || '-'} /
  377. ${r.basic_pay || '-'} /
  378. ${r.grade_pay || '-'}
  379. </small>`
  380. },
  381. { data: 'sex', className: 'text-center' },
  382. { data: 'new_designation', className: 'text-center' },
  383. { data: 'govt_type', className: 'text-center' },
  384. {
  385. data: null,
  386. className: "text-center",
  387. render: r => `${r.office_name || '-'}<br>/ ${r.address || '-'}`
  388. },
  389. {
  390. data: null,
  391. className: 'text-center',
  392. render: r => `${r.r_mobile_no || ''}`
  393. },
  394. {
  395. data: null,
  396. className: 'text-center',
  397. render: r => `${r.r_address1 || ''} ${r.r_address2 || ''} ${r.r_address3 || ''} - ${r.r_pincode || ''}`
  398. },
  399. { data: null,
  400. className: 'text-center',
  401. render : r => `${r.native_ac_no || ''} - ${r.native_constituency || ''}`
  402. },
  403. { data: null,
  404. className: 'text-center',
  405. render : r => `${r.reside_ac_no || ''} - ${r.residential_constituency || ''}`
  406. },
  407. { data: null,
  408. className: 'text-center',
  409. render : r => `${r.work_ac_no || ''} - ${r.working_constituency || ''}`
  410. },
  411. {
  412. data: null,
  413. className: 'text-center',
  414. render: {
  415. display: r => `
  416. Part: ${r.elector_part_no || '-'}<br>
  417. Sl: ${r.elector_sl_no || '-'}<br>
  418. ${r.elector_epic_no || '-'}<br>
  419. ${r.elector_ac_no || '-'} - ${r.elector_constituency || '-'}
  420. `,
  421. export: r =>
  422. `Part: ${r.elector_part_no || '-'}\n` +
  423. `Sl: ${r.elector_sl_no || '-'}\n` +
  424. `${r.elector_epic_no || '-'}\n` +
  425. `${r.elector_ac_no || '-'} - ${r.elector_constituency || '-'}`
  426. }
  427. },
  428. {
  429. data: 'img_full_path',
  430. className: 'text-center',
  431. render: function (url, type, row) {
  432. if (!url) {
  433. return `<span style="color:red;">No Image</span>`;
  434. }
  435. return `
  436. <img src="${url}"
  437. style="height: 100px; width: 100px; object-fit: cover; border:1px solid #ccc;"
  438. alt="Photo">
  439. `;
  440. }
  441. },
  442. /*{
  443. data: 'poll_person_verify',
  444. className: 'text-center',
  445. render: function (flag, type, row) {
  446. if (flag == 1) {
  447. return `<span class="badge bg-success px-3 py-2"">Verified</span>`;
  448. } else {
  449. return `
  450. <input type="checkbox"
  451. class="verify-checkbox"
  452. value="${row.id}">
  453. `;
  454. }
  455. }
  456. }*/
  457. /*{
  458. data: null,
  459. className: 'text-center',
  460. render: function (data, type, row) {
  461. return `<button class="btn btn-warning btn-sm" onclick="verifyApplicant(${row.id})">
  462. Verify
  463. </button>`;
  464. }
  465. }*/
  466. ],
  467. dom: 'Bfrtip',
  468. buttons: [
  469. {
  470. extend: 'pageLength',
  471. className: 'btn btn-warning'
  472. },
  473. {
  474. title: 'Data export',
  475. extend: 'copyHtml5',
  476. text: 'Copy',
  477. className: 'btn btn-secondary',
  478. id: 'copyBtn'
  479. },
  480. {
  481. extend: 'excelHtml5',
  482. text: 'Excel',
  483. className: 'btn btn-secondary',
  484. id: 'excelBtn',
  485. filename: function () {
  486. return 'micro_observer_details_' + getTimestamp();
  487. }
  488. },
  489. {
  490. extend: 'csvHtml5',
  491. text: 'CSV',
  492. className: 'btn btn-secondary',
  493. id: 'csvBtn',
  494. filename: function () {
  495. return 'micro_observer_details_' + getTimestamp();
  496. }
  497. },
  498. {
  499. extend: 'pdfHtml5',
  500. text: 'PDF',
  501. className: 'btn btn-secondary',
  502. id: 'pdfBtn',
  503. title:'Micro Observer Details',
  504. filename: function () {
  505. return 'micro_observer_details_' + getTimestamp();
  506. },
  507. orientation: 'landscape', // ⭐ important line
  508. pageSize: 'A4',
  509. customize: function (doc) {
  510. doc.pageOrientation = 'landscape';
  511. // Reduce page margins to use full width
  512. doc.pageMargins = [10, 10, 10, 10];
  513. // Reduce default font size so columns fit
  514. doc.defaultStyle.fontSize = 7;
  515. doc.styles.tableHeader.fontSize = 8;
  516. // ⭐ Force table to shrink inside page
  517. doc.content[1].table.widths = [
  518. 20, // S.No
  519. 40, // Unique/Batch
  520. 80, // Name / Pay Scale
  521. 20, // Sex
  522. 60, // Designation
  523. 30, // State / Central
  524. 100, // Office Address
  525. 50, // Mobile
  526. 90, // Residence Address
  527. 40, // Native
  528. 40, // Reside
  529. 40, // Work
  530. 70, // Enrolled
  531. 50, // Photo
  532. ];
  533. // ⭐ Remove large default paddings
  534. var objLayout = {};
  535. objLayout['hLineWidth'] = function(i) { return 0.3; };
  536. objLayout['vLineWidth'] = function(i) { return 0.3; };
  537. objLayout['hLineColor'] = function(i) { return '#000'; };
  538. objLayout['vLineColor'] = function(i) { return '#000'; };
  539. objLayout['paddingLeft'] = function(i) { return 2; };
  540. objLayout['paddingRight'] = function(i) { return 2; };
  541. objLayout['paddingTop'] = function(i) { return 2; };
  542. objLayout['paddingBottom'] = function(i) { return 2; };
  543. doc.content[1].layout = objLayout;
  544. }
  545. }
  546. ],
  547. columnDefs: [
  548. { width: "150px", targets: 1 },
  549. { width: "150px", targets: 2 },
  550. { width: "250px", targets: 6 },
  551. {width: "150px", targets: 12},
  552. {width: "100px", targets: 7},
  553. {width: "200px", targets: 8}
  554. ],
  555. scrollY: '80vh',
  556. scrollX: true,
  557. responsive: false
  558. });
  559. } else {
  560. Swal.fire("No Data", "No records found", "warning");
  561. }
  562. },
  563. error: function (xhr) {
  564. $('#pageLoader').hide();
  565. console.log(" Server Error:", xhr.responseText);
  566. Swal.fire({
  567. icon: 'error',
  568. title: 'Error',
  569. text: 'Server error! Check console.',
  570. confirmButtonText: 'OK',
  571. allowOutsideClick: false,
  572. allowEscapeKey: false,
  573. allowEnterKey: false
  574. }).then(() => {
  575. location.reload(); // optional action
  576. });
  577. }
  578. });
  579. }
  580. document.getElementById('searchBtn').addEventListener('click', function () {
  581. let batchNo = document.getElementById('batchno').value || "";
  582. let fromSLno = document.getElementById('startSerialno').value || "";
  583. let toSLno = document.getElementById('endSerialno').value || "";
  584. let mobileNo = document.getElementById('mobilenumber').value || "";
  585. let category = document.getElementById('department').value || "";
  586. let officeName = document.getElementById('officename').value || "";
  587. let notExistRadio = document.querySelector('input[name="notExistOption"]:checked');
  588. let notExist = notExistRadio ? notExistRadio.value : "";
  589. if (
  590. !batchNo &&
  591. !fromSLno &&
  592. !toSLno &&
  593. !mobileNo &&
  594. !category &&
  595. !officeName &&
  596. !notExist
  597. ) {
  598. Swal.fire({
  599. icon: 'warning',
  600. title: 'Validation Error',
  601. text: 'Please select at least one field to search.',
  602. confirmButtonText: 'OK',
  603. allowOutsideClick: false,
  604. allowEscapeKey: false
  605. });
  606. return;
  607. }
  608. if (!fromSLno && toSLno) {
  609. Swal.fire({
  610. icon: 'warning',
  611. title: 'Validation Error',
  612. text: 'Please Enter SL No (From) to search.',
  613. confirmButtonText: 'OK',
  614. allowOutsideClick: false,
  615. allowEscapeKey: false
  616. });
  617. return;
  618. }
  619. if(mobileNo){
  620. // Rule 1: Must be exactly 10 digits & must not start with 0
  621. if (!/^[1-9][0-9]{9}$/.test(mobileNo)) {
  622. $('#pageLoader').hide();
  623. $('#saveBtn').prop('disabled', false).text('Update');
  624. Swal.fire({
  625. icon: 'warning',
  626. title: 'Invalid Mobile Number',
  627. text: 'Mobile number must be 10 digits and cannot start with 0.'
  628. });
  629. return;
  630. }
  631. // Rule 2: Reject sequential numbers like 1234567890
  632. if (mobileNo === "1234567890") {
  633. $('#pageLoader').hide();
  634. $('#saveBtn').prop('disabled', false).text('Update');
  635. Swal.fire({
  636. icon: 'warning',
  637. title: 'Invalid Mobile Number',
  638. text: 'Sequential numbers like 1234567890 are not allowed.'
  639. });
  640. return;
  641. }
  642. // Rule 3: Reject all digits same (1111111111, 2222222222, etc.)
  643. if (/^(\d)\1{9}$/.test(mobileNo)) {
  644. $('#pageLoader').hide();
  645. $('#saveBtn').prop('disabled', false).text('Update');
  646. Swal.fire({
  647. icon: 'warning',
  648. title: 'Invalid Mobile Number',
  649. text: 'All digits cannot be the same.'
  650. });
  651. return;
  652. }
  653. }
  654. const params = new URLSearchParams({
  655. batchNo,
  656. fromSLno,
  657. toSLno,
  658. mobileNo,
  659. category,
  660. officeName,
  661. notExist
  662. });
  663. loadApplicants(params.toString());
  664. });
  665. });
  666. /* $(document).on("change", ".verify-checkbox", function () {
  667. let checkedCount = $(".verify-checkbox:checked").length;
  668. if (checkedCount > 0) {
  669. $("#verifySelectedBtn").show();
  670. } else {
  671. $("#verifySelectedBtn").hide();
  672. }
  673. });*/
  674. /*$("#verifySelectedBtn").click(function () {
  675. let selectedIds = [];
  676. $(".verify-checkbox:checked").each(function () {
  677. selectedIds.push($(this).val());
  678. });
  679. if (selectedIds.length === 0) {
  680. Swal.fire("Warning", "Select at least one record", "warning");
  681. return;
  682. }
  683. Swal.fire({
  684. title: "Confirm Verification?",
  685. text: `Verify ${selectedIds.length} applicant(s)?`,
  686. icon: "question",
  687. showCancelButton: true,
  688. confirmButtonText: "Yes, Verify",
  689. allowOutsideClick: false,
  690. allowEscapeKey: false,
  691. allowEnterKey: false
  692. }).then((result) => {
  693. if (!result.isConfirmed) return;
  694. $.ajax({
  695. url: "/election/api/checklistadmin/verifyApplicants",
  696. type: "POST",
  697. traditional: true,
  698. data: { id: selectedIds },
  699. success: function (response) {
  700. if (response === "success") {
  701. Swal.fire({
  702. icon: "success",
  703. title: "Success",
  704. text: "Applicants Verified Successfully",
  705. confirmButtonText: "OK",
  706. allowOutsideClick: false,
  707. allowEscapeKey: false,
  708. allowEnterKey: false
  709. }).then((result) => {
  710. if (result.isConfirmed) {
  711. location.reload(); // ✅ Reload ONLY after OK click
  712. }
  713. });
  714. $("#verifySelectedBtn").hide();
  715. }
  716. },
  717. error: function () {
  718. Swal.fire({
  719. icon: "error",
  720. title: "Error",
  721. text: "Verification Failed",
  722. confirmButtonText: "OK",
  723. allowOutsideClick: false,
  724. allowEscapeKey: false,
  725. allowEnterKey: false
  726. });
  727. }
  728. });
  729. });
  730. });*/
  731. $(document).on("click", "#printBtn", function () {
  732. $('#pageLoader').show();
  733. let batchNo = $('#batchno').val() || "";
  734. let fromSLno = $('#startSerialno').val() || "";
  735. let toSLno = $('#endSerialno').val() || "";
  736. let mobileNo = $('#mobilenumber').val() || "";
  737. let category = $('#department').val() || "";
  738. let officeName = $('#officename').val() || "";
  739. let notExist = $("input[name='notExistOption']:checked").val() || "";
  740. const params = {
  741. batchNo,
  742. fromSLno,
  743. toSLno,
  744. mobileNo,
  745. category,
  746. officeName,
  747. notExist
  748. };
  749. $.ajax({
  750. url: "/election/api/report/mobchecklist",
  751. method: "GET",
  752. data: params,
  753. xhrFields: {
  754. responseType: 'blob' // IMPORTANT
  755. },
  756. success: function (data, status, xhr) {
  757. $('#pageLoader').hide();
  758. /* console.log("Data: ", data);
  759. console.log("Status: ", status);
  760. console.log("Xhr: ", xhr); */
  761. if (xhr.status === 204 || data.size === 0) {
  762. Swal.fire("No Data Found", "No records available", "warning");
  763. return;
  764. }
  765. // Get filename from backend header
  766. let disposition = xhr.getResponseHeader("Content-Disposition");
  767. let fileName = "mob_checklist_report_.pdf"; // fallback
  768. if (disposition && disposition.indexOf("filename=") !== -1) {
  769. fileName = disposition.split("filename=")[1].trim();
  770. }
  771. const blob = new Blob([data], { type: "application/pdf" });
  772. const link = document.createElement("a");
  773. link.href = window.URL.createObjectURL(blob);
  774. link.download = fileName; // <-- use backend filename
  775. link.click();
  776. },
  777. error: function () {
  778. $('#pageLoader').hide();
  779. Swal.fire("Error", "PDF download failed", "error");
  780. }
  781. });
  782. });
  783. /* $(document).on("click", "#printBtn", function () {
  784. let table = $('#batchDatatable').DataTable();
  785. let rows = table.rows({ search: 'applied' }).nodes();
  786. let thead = $(".dataTables_scrollHead thead").clone();
  787. let printTable = `
  788. <table border="1" style="width:100%; border-collapse:collapse; text-align:center; font-size:12px;">
  789. ${thead.prop("outerHTML")}
  790. <tbody>
  791. `;
  792. rows.each(function (row) {
  793. printTable += `<tr>${row.innerHTML}</tr>`;
  794. });
  795. printTable += `</tbody></table>`;
  796. let printWindow = window.open("", "", "width=1200,height=800");
  797. printWindow.document.write(`
  798. <!DOCTYPE html>
  799. <html>
  800. <head>
  801. <title>Verification Checklist</title>
  802. <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css">
  803. <style>
  804. @page {
  805. size: landscape;
  806. }
  807. body {
  808. padding: 20px;
  809. font-family: Arial, sans-serif;
  810. font-size: 14px;
  811. }
  812. h4 {
  813. text-align: center;
  814. margin-bottom: 20px;
  815. font-size: 20px;
  816. font-weight: bold;
  817. }
  818. th, td {
  819. border: 1px solid #000;
  820. padding: 8px;
  821. text-align: center;
  822. vertical-align: top;
  823. white-space: normal;
  824. word-wrap: break-word;
  825. overflow-wrap: break-word;
  826. font-size: 15px;
  827. }
  828. th:nth-child(7),
  829. td:nth-child(7) {
  830. width: 220px;
  831. text-align: left;
  832. }
  833. table {
  834. width: 100%;
  835. border-collapse: collapse;
  836. table-layout: fixed;
  837. font-size: 13px;
  838. }
  839. input[type="checkbox"] {
  840. display: none;
  841. }
  842. button {
  843. display: none;
  844. }
  845. thead {
  846. display: table-header-group;
  847. }
  848. </style>
  849. </head>
  850. <body>
  851. <h4>Verification Checklist Report</h4>
  852. ${printTable}
  853. <script>
  854. window.onload = function () {
  855. window.print();
  856. window.close();
  857. };
  858. <\/script>
  859. </body>
  860. </html>
  861. `);
  862. printWindow.document.close();
  863. }); */
  864. function getTimestamp() {
  865. const now = new Date();
  866. const yyyy = now.getFullYear();
  867. const mm = String(now.getMonth() + 1).padStart(2, '0');
  868. const dd = String(now.getDate()).padStart(2, '0');
  869. const hh = String(now.getHours()).padStart(2, '0');
  870. const mi = String(now.getMinutes()).padStart(2, '0');
  871. const ss = String(now.getSeconds()).padStart(2, '0');
  872. return `${yyyy}${mm}${dd}_${hh}${mi}${ss}`;
  873. }
  874. </script>
  875. </body>
  876. </html>