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.

551 lines
16 KiB

​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
  1. <!DOCTYPE html>
  2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
  3. <head th:replace="~{fragments/modules/base/head :: head}">
  4. <style>
  5. </style>
  6. </head>
  7. <body>
  8. <div class="wrapper">
  9. <!-- header top menu Start -->
  10. <header th:replace="~{fragments/modules/base/header :: header}"></header>
  11. <!-- header top menu end -->
  12. <div class="page-wrap">
  13. <!--=============== Left Menu side Start ================-->
  14. <div th:replace="~{fragments/modules/base/menu :: menu}"></div>
  15. <!--=============== Left side End ================-->
  16. <div class="main-content">
  17. <div class="container-fluid">
  18. <div class="page-header mb-2">
  19. <div class="row align-items-end">
  20. <div class="col-lg-8">
  21. <div class="page-header-title">
  22. <!-- <i class="far fa-calendar-plus bg-blue"></i> -->
  23. <div class="d-inline">
  24. <h5>Create New Batch for Micro-Observer</h5>
  25. <span>Create a new batch for application bundle intake (micro-observer)</span>
  26. </div>
  27. </div>
  28. </div>
  29. </div>
  30. </div>
  31. <div class="row">
  32. <div class="col-md-12">
  33. <div class="card" style="margin-top: 15px;">
  34. <div class="col-lg-8" style="margin-top: 25px;">
  35. <h3>Micro-Observer Batch Information</h3>
  36. <span>Fill in the details for the new micro-observer application batch</span>
  37. </div>
  38. <div class="card-body">
  39. <input type="hidden" id="loginUserId" th:value="${loginUserId}">
  40. <div class="form-group">
  41. <div class="row">
  42. <div class="col-sm-12 col-md-6">
  43. <label class="form-label" for="receivedate">Receiving Date<span
  44. class="text-danger">*</span></label>
  45. <input type="date" class="form-control" id="receivedate" onclick="this.showPicker()" required>
  46. </div>
  47. <!-- Department -->
  48. <div class="col-sm-12 col-md-6">
  49. <label class="form-label" for="department">Department
  50. <span class="text-danger">*</span>
  51. </label>
  52. <select class="form-control" id="department" required>
  53. <option value=""> Select Department </option>
  54. </select>
  55. </div>
  56. <!-- Office Name -->
  57. <div class="col-sm-12 col-md-6" style="margin-top: 15px;">
  58. <label class="form-label" for="officename">Office Name
  59. <span class="text-danger">*</span>
  60. </label>
  61. <select class="form-control" id="officename" required>
  62. <option value="">Select Office Name </option>
  63. </select>
  64. </div>
  65. <div class="col-sm-12 col-md-6" style="margin-top: 15px;">
  66. <label class="form-label" for="noofapplication">Number of Applications<span class="text-danger">*</span></label>
  67. <input type="text" class="form-control" id="noofapplication" oninput="this.value=this.value.replace(/[^0-9]/g,'')"/>
  68. </div>
  69. </div>
  70. </div>
  71. <div class="form-group text-center">
  72. <button type="submit" class="btn btn-primary " id="createdBtn">Create Batch</button>
  73. <button type="reset" class="btn btn-secondary ml-2" id="resetBtn">Reset</button></div>
  74. </div>
  75. </div>
  76. </div>
  77. </div>
  78. <!-- Batch List Table -->
  79. <div class="row">
  80. <div class="col-12">
  81. <div class="card">
  82. <div class="card-header">
  83. <h3><b>All Micro-Observer Batches</b></h3>
  84. </div>
  85. <div class="card-body">
  86. <table id="batchDatatable" class="table table-striped table-bordered table-hover dataTable" role="grid" >
  87. <thead class="thead-dark">
  88. <tr role="row">
  89. <th class="text-center">S.No</th>
  90. <th class="text-center">Batch ID</th>
  91. <th class="text-center">Receiving Date</th>
  92. <th class="text-center">Department</th>
  93. <th class="text-center">Office Name</th>
  94. <th class="text-center">No Of Application</th>
  95. <th class="text-center">Completed</th>
  96. <th class="text-center">Pending</th>
  97. <th class="text-center">Action</th>
  98. </tr>
  99. </thead>
  100. <tbody style="text-align:center;">
  101. </tbody>
  102. </table>
  103. </div>
  104. </div>
  105. </div>
  106. </div>
  107. </div>
  108. </div>
  109. <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;">
  110. <div style="position: relative; top: 50%; transform: translateY(-50%);">
  111. <div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;">
  112. <span class="sr-only">Loading...</span>
  113. </div>
  114. <!-- Add the 'Please wait' text below the spinner -->
  115. <p style="margin-top: 1rem; font-size: 1.2rem; color: #007bff;">Please wait...</p>
  116. </div>
  117. </div>
  118. <div th:replace="~{fragments/modules/base/app_module_menu_box :: div}"></div>
  119. <footer th:replace="~{fragments/modules/base/footer :: footer}"></footer>
  120. </div>
  121. </div>
  122. <!-- modal box -->
  123. <div class="modal fade" id="editBatchModal" tabindex="-1">
  124. <div class="modal-dialog modal-lg">
  125. <div class="modal-content">
  126. <div class="modal-header">
  127. <h5 class="modal-title">Update Micro-Observer Batch Details</h5>
  128. <button type="button" class="close" data-dismiss="modal" aria-label="Close">
  129. <span aria-hidden="true">&times;</span>
  130. </button>
  131. </div>
  132. <div class="modal-body">
  133. <div class="row">
  134. <input type="hidden" id="edit_batch_id">
  135. <div class="col-md-6 mb-4">
  136. <label class="form-label">Receive Date</label>
  137. <input type="date" class="form-control" id="edit_receivedate" readonly>
  138. </div>
  139. <div class="col-md-6 mb-4">
  140. <label class="form-label">Department</label>
  141. <input type="text" class="form-control" id="edit_department" readonly>
  142. </div>
  143. <div class="col-md-12 mb-4">
  144. <label class="form-label">Office Name</label>
  145. <input type="text" class="form-control" id="edit_officename" readonly>
  146. </div>
  147. <div class="col-md-6">
  148. <label class="form-label" for="edit_noofapplication">Number of Applications <span class="text-danger">*</span></label>
  149. <input type="text" class="form-control" id="edit_noofapplication" oninput="this.value=this.value.replace(/[^0-9]/g,'')"/>
  150. </div>
  151. </div>
  152. </div>
  153. <div class="row mb-2 mt-2">
  154. <div class="col-md-12 d-flex justify-content-center">
  155. <button type="button" class="btn btn-primary mx-2" onclick="updateBatch()">Update</button>
  156. </div>
  157. </div>
  158. </div>
  159. </div>
  160. </div>
  161. <script th:replace="~{fragments/modules/base/script :: script}"></script>
  162. <script type="text/javascript">
  163. // ✅ Reset Button
  164. document.getElementById('resetBtn').addEventListener('click', function (e) {
  165. e.preventDefault();
  166. location.reload();
  167. });
  168. // ✅ Disable Future Dates
  169. document.addEventListener("DOMContentLoaded", function () {
  170. var today = new Date().toISOString().split('T')[0];
  171. document.getElementById("receivedate").setAttribute("max", today);
  172. });
  173. $(document).ready(function () {
  174. // ✅✅✅ SINGLE & CORRECT DataTable Initialization
  175. var batchTable = $('#batchDatatable').DataTable({
  176. dom: 'Bftip',
  177. autoWidth: false,
  178. responsive: false,
  179. scrollX: true,
  180. scrollY: '80vh',
  181. scrollCollapse: true,
  182. fixedHeader: true,
  183. lengthMenu: [
  184. [50, 100, 200, 500, -1],
  185. ['50 rows', '100 rows', '200 rows', 'Show all']
  186. ],
  187. buttons: [
  188. { extend: 'pageLength', className: 'btn btn-warning' },
  189. { extend: 'copyHtml5', className: 'btn btn-secondary' },
  190. { extend: 'excelHtml5', className: 'btn btn-secondary' },
  191. { extend: 'csvHtml5', className: 'btn btn-secondary' },
  192. { extend: 'pdfHtml5', className: 'btn btn-secondary' }
  193. ],
  194. ajax: {
  195. url: "/election/api/dataentryadmin_mob/getallbatches",
  196. type: "GET",
  197. dataSrc: ""
  198. },
  199. columns: [
  200. {
  201. data: null,
  202. className: "text-center",
  203. render: (d, t, r, m) => m.row + 1
  204. },
  205. { data: "id", className: "text-center" },
  206. { data: "rec_date", className: "text-center" },
  207. { data: "dept_name", className: "text-center" },
  208. {
  209. data: null,
  210. className: "text-center",
  211. render: function (data, type, row) {
  212. let address = '';
  213. if (row.address1) address += row.address1;
  214. if (row.address2) address += (address ? ', ' : '') + row.address2;
  215. return `
  216. <div>
  217. <span>${row.office_name}</span><br>
  218. <span class="text-muted">${address || '-'}</span>
  219. </div>
  220. `;
  221. }
  222. },
  223. { data: "noof_application", className: "text-center" },
  224. { data: "completed", className: 'text-center' },
  225. { data: "pending", className: 'text-center' },
  226. {
  227. data: "id",
  228. className: "text-center",
  229. render: d => `<button class="btn btn-primary btn-sm" onclick="editBatch(${d})">Edit</button>`
  230. }
  231. ],
  232. columnDefs: [
  233. { targets: "_all", className: "text-center" }
  234. ]
  235. });
  236. // ✅ Load Departments with searchable dropdown
  237. $.ajax({
  238. url: "/election/api/dataentryadmin/getalldepartments",
  239. method: "GET",
  240. success: function (data) {
  241. let department = $("#department");
  242. department.empty().append('<option value="">-- Select Department --</option>');
  243. data.forEach(dept => {
  244. department.append(
  245. `<option value="${dept.dept_id}">${dept.dept_name}</option>`
  246. );
  247. });
  248. // ✅ Enable search inside dropdown
  249. department.select2({
  250. placeholder: "Select Department",
  251. allowClear: true,
  252. width: '100%'
  253. });
  254. }
  255. });
  256. });
  257. $("#department").on("change", function () {
  258. let deptId = $(this).val();
  259. let office = $("#officename");
  260. // Reset office dropdown
  261. office.empty().append('<option value="">-- Select Office Name --</option>');
  262. //office.select2('destroy'); // ✅ important
  263. if (deptId !== "") {
  264. $.ajax({
  265. url: "/election/api/dataentryadmin/getallofficenames",
  266. method: "GET",
  267. data: { deptId: deptId },
  268. success: function (data) {
  269. data.forEach(o => {
  270. office.append(
  271. `<option value="${o.id}">${o.office_full_address}</option>`
  272. );
  273. });
  274. // ✅ Enable searchable dropdown
  275. office.select2({
  276. placeholder: "Select Office Name",
  277. allowClear: true,
  278. width: '100%'
  279. });
  280. }
  281. });
  282. }
  283. });
  284. // ✅ Create Batch
  285. $("#createdBtn").click(function () {
  286. const $btn = $(this); // cache button
  287. let receivedate = $("#receivedate").val();
  288. let department = $("#department").val();
  289. let officename = $("#officename").val();
  290. let noofapplication = $("#noofapplication").val();
  291. let loginUserId = $("#loginUserId").val();
  292. if (!receivedate || !department || !officename || !noofapplication || noofapplication <= 0) {
  293. Swal.fire("Validation Error", "All fields are mandatory and must be valid.", "warning");
  294. return;
  295. }
  296. // ✅ Disable button immediately
  297. $btn.prop("disabled", true).text("Saving...");
  298. $.ajax({
  299. url: "/election/api/dataentryadmin_mob/savebatchdeatils",
  300. type: "POST",
  301. data: {
  302. receivedate,
  303. department,
  304. officename,
  305. noofapplication,
  306. userid: loginUserId
  307. },
  308. success: function (response) {
  309. Swal.fire({
  310. icon: "success",
  311. title: "Batch Created Successfully!",
  312. text: "Reference ID is: " + response
  313. }).then(() => location.reload());
  314. },
  315. error: function (xhr) {
  316. Swal.fire("Error", "Failed to save data: " + xhr.responseText, "error");
  317. // ❌ Re-enable button only if error occurs
  318. $btn.prop("disabled", false).text("Create");
  319. }
  320. });
  321. });
  322. // ✅ Load Edit Modal
  323. function editBatch(batchId) {
  324. $.ajax({
  325. url: "/election/api/dataentryadmin_mob/getbatchbyId",
  326. type: "GET",
  327. data: { id: batchId },
  328. success: function (data) {
  329. let officeFullName = [
  330. data.office_name,
  331. data.address1,
  332. data.address2
  333. ].filter(v => v && v.trim() !== "").join(" ");
  334. $("#edit_batch_id").val(data.id);
  335. $("#edit_receivedate").val(data.rec_date);
  336. $("#edit_department").val(data.dept_name);
  337. $("#edit_officename").val(officeFullName);
  338. // ✅ Set value + store counts for validation
  339. $("#edit_noofapplication")
  340. .val(data.noof_application)
  341. .data("oldCount", data.noof_application)
  342. .data("completed", data.completed);
  343. $("#editBatchModal").modal('show');
  344. },
  345. error: function () {
  346. Swal.fire("Error!", "Unable to load batch details", "error");
  347. }
  348. });
  349. }
  350. /*function editBatch(batchId) {
  351. $.ajax({
  352. url: "/election/api/dataentryadmin/getbatchbyId",
  353. type: "GET",
  354. data: { id: batchId },
  355. success: function (data) {
  356. $("#edit_batch_id").val(data.id);
  357. $("#edit_receivedate").val(data.rec_date);
  358. $("#edit_department").val(data.dept_name);
  359. $("#edit_officename").val(data.office_name);
  360. $("#edit_noofapplication").val(data.noof_application);
  361. // ✅ Store existing count for validation
  362. $("#edit_noofapplication").data("oldCount", data.noof_application);
  363. $("#editBatchModal").modal('show');
  364. },
  365. error: function () {
  366. Swal.fire("Error!", "Unable to load batch details", "error");
  367. }
  368. });
  369. }*/
  370. // ✅ Update Batch
  371. function updateBatch() {
  372. let id = $("#edit_batch_id").val();
  373. let userId = $("#loginUserId").val();
  374. let newCount = Number($("#edit_noofapplication").val());
  375. let completed = Number($("#edit_noofapplication").data("completed"));
  376. // Basic validation
  377. if (!newCount || newCount <= 0) {
  378. Swal.fire("Validation Error", "Enter a valid number of applications", "warning");
  379. return;
  380. }
  381. // ❌ Prevent reducing below completed count
  382. if (newCount < completed) {
  383. Swal.fire({
  384. icon: "warning",
  385. title: "Invalid Update",
  386. text: `Number of applications cannot be less than completed count (${completed})`,
  387. confirmButtonText: "OK"
  388. });
  389. return;
  390. }
  391. $.ajax({
  392. url: "/election/api/dataentryadmin_mob/updatebatch",
  393. type: "POST",
  394. data: {
  395. id,
  396. noofapplication: newCount,
  397. userId
  398. },
  399. success: function () {
  400. Swal.fire("Success", "Batch Updated Successfully", "success").then(() => {
  401. $("#editBatchModal").modal("hide");
  402. $('#batchDatatable').DataTable().ajax.reload(null, false);
  403. });
  404. },
  405. error: function () {
  406. Swal.fire("Error", "Failed to update batch", "error");
  407. }
  408. });
  409. }
  410. /*function updateBatch() {
  411. let id = $("#edit_batch_id").val();
  412. // let noof_application = $("#edit_noofapplication").val();
  413. let userId = $("#loginUserId").val();
  414. let newCount = Number($("#edit_noofapplication").val());
  415. let oldCount = Number($("#edit_noofapplication").data("oldCount"));
  416. if (!newCount || newCount <= 0) {
  417. Swal.fire("Validation Error", "Enter a valid number of applications", "warning");
  418. return;
  419. }
  420. $.ajax({
  421. url: "/election/api/dataentryadmin/updatebatch",
  422. type: "POST",
  423. data: {
  424. id,
  425. noofapplication: newCount,
  426. userId
  427. },
  428. success: function () {
  429. Swal.fire("Success", "Batch Updated Successfully", "success").then(() => {
  430. $("#editBatchModal").modal("hide");
  431. $('#batchDatatable').DataTable().ajax.reload(null, false);
  432. });
  433. },
  434. error: function () {
  435. Swal.fire("Error", "Failed to update batch", "error");
  436. }
  437. });
  438. }*/
  439. </script>
  440. </body>
  441. </html>