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.

934 lines
34 KiB

2 years ago
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
  1. <!DOCTYPE html>
  2. <html lang="en" dir="">
  3. <html xmlns:th="http://www.thymeleaf.org">
  4. <head th:replace="~{fragments/modules/base/head :: head}"></head>
  5. <style>
  6. /* Base Layout and Styling */
  7. /* Base Layout and Styling */
  8. body {
  9. font-family: 'Arial', sans-serif;
  10. background-color: #f8f9fa;
  11. }
  12. /* Card Styling */
  13. .card-box {
  14. border-radius: 12px;
  15. box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  16. background-color: #ffffff;
  17. padding: 20px;
  18. transition: transform 0.3s ease-in-out;
  19. }
  20. .card-box:hover {
  21. transform: translateY(-5px);
  22. }
  23. /* Title Styling */
  24. h3 {
  25. font-size: 1.2rem;
  26. color: #444;
  27. }
  28. /* Styling for Overall Pendency and Stage Wise Sections */
  29. .charts {
  30. display: flex;
  31. flex-wrap: wrap;
  32. gap: 30px; /* Increased gap between charts */
  33. margin-top: 30px; /* Increased margin-top */
  34. }
  35. .chart {
  36. flex: 1;
  37. background: #ffffff; /* White background */
  38. padding: 20px;
  39. border-radius: 8px;
  40. border: 2px solid #1e90ff; /* Add a colored border */
  41. width: 100%;
  42. box-sizing: border-box;
  43. text-align: center;
  44. transition: all 0.3s ease-in-out;
  45. }
  46. .chart:hover {
  47. box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2);
  48. }
  49. .chart h3 {
  50. font-size: 1.2rem;
  51. color: #333;
  52. margin-bottom: 15px;
  53. }
  54. .chart canvas {
  55. display: block;
  56. max-width: 100%;
  57. height: auto;
  58. }
  59. /* Stats Cards */
  60. .stats {
  61. display: flex;
  62. flex-wrap: wrap;
  63. justify-content: center;
  64. gap: 30px; /* Increased gap between stats cards */
  65. margin-top: 30px; /* Increased margin-top */
  66. }
  67. .stat-card {
  68. background: #ffffff;
  69. border: 2px solid #1e90ff;
  70. padding: 20px;
  71. border-radius: 8px;
  72. text-align: center;
  73. flex: 1;
  74. margin: 10px; /* Reduced margin for cleaner look */
  75. }
  76. .stat-card:hover {
  77. transform: scale(1.05);
  78. box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2);
  79. }
  80. .stat-card h2 {
  81. margin: 0;
  82. font-size: 36px;
  83. color: #007bff;
  84. }
  85. .stat-card p {
  86. margin: 5px 0 0;
  87. font-size: 13px;
  88. color: #555;
  89. font-weight:bold;
  90. }
  91. /* Buttons */
  92. .btn-primary:hover {
  93. background-color: #0056b3;
  94. }
  95. .btn-warning:hover {
  96. background-color: #e0a800;
  97. }
  98. /* Container Styling */
  99. .container {
  100. max-width: 1200px;
  101. margin: 20px auto;
  102. padding: 20px;
  103. background: #fff;
  104. border-radius: 8px;
  105. box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  106. }
  107. /* Date Input Row */
  108. .row.mt-3.ml-2 {
  109. margin-top: 20px; /* Increased margin-top */
  110. }
  111. /* Responsive Design */
  112. @media (min-width: 768px) {
  113. .charts {
  114. flex-direction: row;
  115. }
  116. .charts .chart {
  117. width: calc(50% - 15px); /* Increased gap between charts */
  118. }
  119. .stats {
  120. flex-direction: row;
  121. }
  122. }
  123. @media (max-width: 576px) {
  124. .charts,
  125. .stats {
  126. flex-direction: column;
  127. }
  128. .stat-card {
  129. margin: 15px 0; /* Increased margin for better spacing */
  130. }
  131. }
  132. .file-history-list {
  133. margin-top: 10px;
  134. padding-left: 0;
  135. }
  136. .file-history-item {
  137. display: flex;
  138. padding: 5px 10px;
  139. font-family: Arial, sans-serif;
  140. align-items: flex-start;
  141. position: relative; /* For vertical line positioning */
  142. margin-bottom: 1px; /* Add space between items */
  143. }
  144. .file-history-item::before {
  145. content: '';
  146. position: absolute;
  147. top: 0;
  148. bottom: 0;
  149. left: 120px; /* Position of the vertical line */
  150. width: 1px;
  151. background-color: #ddd;
  152. }
  153. .file-history-date {
  154. margin-top: 10px;
  155. flex: 0 0 100px;
  156. font-weight: bold;
  157. font-size: 0.8rem;
  158. color: #333;
  159. text-align: center;
  160. white-space: nowrap; /* Prevent wrapping */
  161. }
  162. .file-history-content {
  163. flex: 5;
  164. padding-left: 20px; /* Adds space after the vertical line */
  165. display: flex;
  166. flex-direction: column;
  167. gap: 5px; /* Adds spacing between status and remarks */
  168. white-space: pre-wrap; /* Prevents wrapping */
  169. overflow: visible; /* Prevents content overflow */
  170. text-overflow: ellipsis; /* Adds ellipsis if content exceeds container width */
  171. }
  172. .file-history-status {
  173. font-size: 0.8rem;
  174. font-weight: bold;
  175. color: #555;
  176. white-space:pre-wrap; /* Prevent wrapping */
  177. overflow: visible;
  178. text-overflow: ellipsis;
  179. }
  180. .file-history-remarks {
  181. font-size: 0.8rem;
  182. color: #777;
  183. white-space: pre-wrap; /* Prevent wrapping */
  184. overflow: visible;
  185. text-overflow: ellipsis;
  186. }
  187. #EmpcodeDetailsModal .modal-body{
  188. max-height:80vh;
  189. overflow-y:auto;
  190. }
  191. </style>
  192. <body>
  193. <div class="wrapper">
  194. <header th:replace="~{fragments/modules/base/header :: header}"></header>
  195. <div class="page-wrap">
  196. <div th:replace="~{fragments/modules/base/menu :: menu}"></div>
  197. <div class="main-content">
  198. <div class="container-fluid">
  199. <div class="page-header mb-2">
  200. <div class="row align-items-end">
  201. <div class="col-lg-8">
  202. <div class="page-header-title">
  203. <i class="fa fa-list-alt bg-blue"></i>
  204. <div class="d-inline">
  205. <h5>Dashboard</h5>
  206. <span>Department Entries</span>
  207. </div>
  208. </div>
  209. </div>
  210. <div class="col-lg-4">
  211. <nav class="breadcrumb-container" aria-label="breadcrumb">
  212. <ol class="breadcrumb">
  213. <li class="breadcrumb-item"><a href="/gcc/index"><i class="ik ik-home"></i></a></li>
  214. <li class="breadcrumb-item">Department Entries</li>
  215. <li class="breadcrumb-item active" aria-current="page">Dashboard</li>
  216. </ol>
  217. </nav>
  218. </div>
  219. </div>
  220. </div>
  221. <div class="row mt-4">
  222. <div class="col-md-12">
  223. <div class="card">
  224. <div class="card-block">
  225. <h5 style="font-weight:bold;"><span th:text="${deptId}" id="deptId" style="display:none"></span></h5>
  226. <h5 style="font-weight:bold;"><span th:text="${deptname}" id="deptname"></span> Department</h5>
  227. <div class="d-flex justify-content-end align-items-center">
  228. <label for="EmpCode" style="font-weight: bold; margin-right: 10px;" class="mb-0">EmpCode:</label>
  229. <input type="text" id="EmpCode" name="EmpCode" class="form-control" style="width: auto; min-width: 150px; margin-right: 10px;">
  230. <button id="searchEmpButton" class="btn btn-primary">Search</button>
  231. </div>
  232. <div class="row mt-3 ml-2 ">
  233. <div class="col-md-3">
  234. <label for="startDate" class="form-label">From Date:</label>
  235. <input type="date" id="startDate" class="form-control" onclick="this.showPicker()">
  236. </div>
  237. <div class="col-md-3">
  238. <label for="endDate" class="form-label">To Date:</label>
  239. <input type="date" id="endDate" class="form-control" onclick="this.showPicker()">
  240. </div>
  241. <div class="col-12 d-flex justify-content-center mt-3">
  242. <button id="searchButton" class="btn btn-primary mx-2">Search</button>
  243. <input type="reset" class="btn btn-warning mx-2" value="Reset">
  244. </div>
  245. </div>
  246. <div id="stats" class="stats"></div>
  247. <div class="charts">
  248. <div class="chart">
  249. <h3>File Category - Overall</h3>
  250. <div id="overallPieChart" style="width: 100%; height: 400px;"></div>
  251. </div>
  252. <div class="chart">
  253. <h3>File Category Stages Wise</h3>
  254. <div id="stagesBarChart" style="width: 100%; height: 400px;"></div>
  255. </div>
  256. </div>
  257. </div>
  258. </div>
  259. </div>
  260. </div>
  261. </div>
  262. </div>
  263. <footer th:replace="~{fragments/modules/base/footer :: footer}"></footer>
  264. </div>
  265. </div>
  266. <!-- Modal -->
  267. <div class="modal fade" id="zoneDetailsModal" tabindex="-1"
  268. role="dialog" aria-labelledby="zoneDetailsModalLabel"
  269. aria-hidden="true" data-backdrop="static" data-keyboard="false">
  270. <div class="modal-dialog modal-lg" role="document">
  271. <div class="modal-content">
  272. <div id="zone-details-content"></div>
  273. </div>
  274. </div>
  275. </div>
  276. <div class="modal fade" id="EmpcodeDetailsModal" tabindex="-1"
  277. role="dialog" aria-labelledby="zoneDetailsModalLabel"
  278. aria-hidden="true" data-backdrop="static" data-keyboard="false">
  279. <div class="modal-dialog modal-xl" role="document">
  280. <div class="modal-content">
  281. <div id="emp-details-content">
  282. <div class="col-md-12 mt-4">
  283. <h5>File History</h5>
  284. <div id="fileHistoryContainer" class="file-history-list">
  285. File History will be dynamically loaded here
  286. </div>
  287. </div>
  288. </div>
  289. </div>
  290. </div>
  291. </div>
  292. <div th:replace="~{fragments/modules/base/app_module_menu_box :: div}"></div>
  293. <script th:replace="~{fragments/modules/base/script :: script}"></script>
  294. <script src="node_modules/tempusdominus-bootstrap-4/build/js/tempusdominus-bootstrap-4.min.js"></script>
  295. <!-- Bootstrap 5 JS -->
  296. <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
  297. <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
  298. <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
  299. <script src="/assets/node_modules/amcharts3/amcharts/amcharts.js"></script>
  300. <script src="/assets/node_modules/amcharts3/amcharts/serial.js"></script>
  301. <script src="/assets/node_modules/amcharts3/amcharts/pie.js"></script>
  302. <script src="/assets/node_modules/amcharts3/amcharts/themes/light.js"></script>
  303. <script>
  304. document.addEventListener('DOMContentLoaded', function () {
  305. // Function to fetch data from /dashboard endpoint
  306. $('#searchEmpButton').on('click', function () {
  307. const Empcode = document.getElementById('EmpCode').value.trim();
  308. if (!Empcode) {
  309. Swal.fire({
  310. icon: "warning",
  311. title: "Enter Employee Code",
  312. text: "Please enter an Employee Code before searching.",
  313. confirmButtonText: "OK",
  314. });
  315. return;
  316. }
  317. // First API call to fetch employee details
  318. $.ajax({
  319. url: `/fetchEmpDetails?Empcode=${Empcode}`,
  320. type: 'GET',
  321. success: function (response) {
  322. if (!response || response.length === 0) {
  323. Swal.fire({
  324. icon: "warning",
  325. title: "No Data Found",
  326. text: "No records found for the entered Employee Code.",
  327. confirmButtonText: "OK",
  328. });
  329. return;
  330. }
  331. const isGISEmployee = response.some(emp => emp.file_name === "GIS");
  332. // Second API call to check department validity (only if not GIS)
  333. $.ajax({
  334. url: '/gcc/api/department/newentry/employeedetails',
  335. type: 'GET',
  336. data: { empCode: Empcode },
  337. success: function (deptResponse) {
  338. if (deptResponse.list && deptResponse.list.length > 0) {
  339. let employeeDetails = deptResponse.list[0];
  340. const loggedInDeptId = $('#deptId').text().trim();
  341. if (employeeDetails.ID_DEPT !== loggedInDeptId) {
  342. Swal.fire({
  343. icon: "error",
  344. title: "Access Denied",
  345. text: "This employee does not belong to your department.",
  346. confirmButtonText: "OK",
  347. });
  348. } else {
  349. renderEmpDetailsModal(response);
  350. }
  351. } else {
  352. if (isGISEmployee) {
  353. renderEmpDetailsModal(response);
  354. } else {
  355. Swal.fire({
  356. icon: "warning",
  357. title: "No Data Found",
  358. text: "No details found for this employee number.",
  359. confirmButtonText: "OK",
  360. });
  361. }
  362. }
  363. },
  364. error: function () {
  365. Swal.fire({
  366. icon: "error",
  367. title: "Error",
  368. text: "An error occurred while fetching department details.",
  369. confirmButtonText: "OK",
  370. });
  371. }
  372. });
  373. },
  374. error: function (xhr) {
  375. console.error("Error fetching employee details:", xhr.status, xhr.responseText);
  376. }
  377. });
  378. });
  379. function renderEmpDetailsModal(data) {
  380. const Empcode = document.getElementById('EmpCode').value.trim();
  381. let modalContent = `
  382. <div class="modal-header">
  383. <h5 class="modal-title">Employee Details for ${Empcode}</h5>
  384. <button type="button" class="close" data-dismiss="modal" aria-label="Close">
  385. <span aria-hidden="true">&times;</span>
  386. </button>
  387. </div>
  388. <div class="modal-body">
  389. <div class="table-responsive">
  390. <table id="DashboardDatatable" class="table table-striped table-bordered table-hover dataTable">
  391. <thead class="thead-dark">
  392. <tr>
  393. <th class="text-center">S.NO</th>
  394. <th class="text-center">Department Name</th>
  395. <th class="text-center">File Name</th>
  396. <th class="text-center">File Status</th>
  397. <th class="text-center">History</th>
  398. </tr>
  399. </thead>
  400. <tbody>
  401. ${data.map((item, index) => `
  402. <tr data-temp-id="${item.temp_id}">
  403. <td>${index + 1}</td>
  404. <td>${item.dept_name}</td>
  405. <td>${item.file_name}</td>
  406. <td>${item.file_status}</td>
  407. <td class="file-history-column" id="history-${item.temp_id}">Loading...</td>
  408. </tr>
  409. `).join('')}
  410. </tbody>
  411. </table>
  412. </div>
  413. </div>
  414. `;
  415. document.getElementById('emp-details-content').innerHTML = modalContent;
  416. let fetchPromises = data.map(item => fetchDetailsByTempId(item.temp_id));
  417. Promise.all(fetchPromises).then(() => {
  418. $('#EmpcodeDetailsModal').modal({
  419. backdrop: 'static',
  420. keyboard: false
  421. });
  422. // **Initialize DataTable AFTER Data is Loaded**
  423. setTimeout(() => {
  424. let table = $('#DashboardDatatable').DataTable({
  425. dom: 'Bftip',
  426. columnDefs: [{ targets: 'no-sort', orderable: false }],
  427. lengthMenu: [
  428. [50, 100, 200, 500, -1],
  429. ['50 rows', '100 rows', '200 rows', '500 rows', 'Show all']
  430. ],
  431. scrollY: '50vh',
  432. buttons: [
  433. { extend: 'pageLength', className: 'btn btn-warning' },
  434. {
  435. extend: 'copyHtml5',
  436. text: 'Copy',
  437. className: 'btn btn-secondary',
  438. exportOptions: { columns: ':visible', modifier: { page: 'all' } }
  439. },
  440. {
  441. extend: 'excelHtml5',
  442. text: 'Excel',
  443. className: 'btn btn-secondary',
  444. customize: function (xlsx) {
  445. let sheet = xlsx.xl.worksheets['sheet1.xml'];
  446. $('row c[r]', sheet).attr('s', '55'); // Apply word-wrap formatting
  447. }
  448. },
  449. {
  450. extend: 'csvHtml5',
  451. text: 'CSV',
  452. className: 'btn btn-secondary',
  453. exportOptions: { columns: ':visible' }
  454. },
  455. {
  456. extend: 'pdfHtml5',
  457. text: 'PDF',
  458. className: 'btn btn-secondary',
  459. orientation: 'landscape',
  460. pageSize: 'A4',
  461. customize: function (doc) {
  462. doc.styles.tableBodyEven.alignment = 'left';
  463. doc.styles.tableBodyOdd.alignment = 'left';
  464. doc.styles.tableHeader.alignment = 'center';
  465. doc.defaultStyle.fontSize = 9;
  466. doc.styles.tableHeader.fontSize = 10;
  467. doc.content[1].table.widths = Array(doc.content[1].table.body[0].length + 1).join('*').split('');
  468. }
  469. }
  470. ],
  471. responsive: false,
  472. processing: false
  473. });
  474. // ✅ Adjust column width after table is fully initialized
  475. }, 200);
  476. });
  477. }
  478. // **Ensure Header Aligns Properly When Modal is Opened**
  479. // **Fetch History & Update Table**
  480. function fetchDetailsByTempId(tempId) {
  481. return new Promise((resolve, reject) => {
  482. $.ajax({
  483. url: `/fetchTempDetails?tempId=${tempId}`,
  484. type: 'GET',
  485. success: function (response) {
  486. let historyContainer = $(`#history-${tempId}`);
  487. if (response.length > 0) {
  488. let historyHtml = response.map(item => `
  489. <div class="file-history-item">
  490. <div class="file-history-date">${formatDateTime(item.file_moved_date)}</div>
  491. <div class="file-history-content">
  492. <div class="file-history-status">${item.file_status}</div>
  493. <div class="file-history-remarks">Comments/Remarks: ${item.remarks || 'N/A'}</div>
  494. </div>
  495. </div>
  496. `).join('');
  497. historyContainer.html(historyHtml);
  498. $('#EmpcodeDetailsModal').modal({
  499. backdrop: 'static',
  500. keyboard: false
  501. });
  502. $('#EmpcodeDetailsModal').modal('show');
  503. $('.close').click(function () {
  504. $('#EmpcodeDetailsModal').modal('hide');
  505. });
  506. } else {
  507. historyContainer.html('<p>No file history available.</p>');
  508. $('#EmpcodeDetailsModal').modal({
  509. backdrop: 'static',
  510. keyboard: false
  511. });
  512. $('#EmpcodeDetailsModal').modal('show');
  513. $('.close').click(function () {
  514. $('#EmpcodeDetailsModal').modal('hide');
  515. });
  516. }
  517. resolve();
  518. },
  519. error: function () {
  520. $(`#history-${tempId}`).html('<p>Failed to load file history.</p>');
  521. $('#EmpcodeDetailsModal').modal({
  522. backdrop: 'static',
  523. keyboard: false
  524. });
  525. $('#EmpcodeDetailsModal').modal('show');
  526. $('.close').click(function () {
  527. $('#EmpcodeDetailsModal').modal('hide');
  528. });
  529. resolve();
  530. }
  531. });
  532. });
  533. }
  534. // **Helper Function to Format Date**
  535. function formatDateTime(dateString) {
  536. const options = { day: '2-digit', month: '2-digit', year: 'numeric' };
  537. return new Date(dateString).toLocaleDateString('en-GB', options);
  538. }
  539. function loadDashboardData() {
  540. const deptId = $('#deptId').text().trim();
  541. console.log(deptId);
  542. $.ajax({
  543. url: `/deparmentdashboard?deptId=${encodeURIComponent(deptId)}`,
  544. type: 'GET',
  545. contentType: 'application/json',
  546. success: function (data) {
  547. const statsDiv = document.getElementById('stats');
  548. statsDiv.innerHTML = ''; // Clear previous stats
  549. data.forEach(item => {
  550. const statCard = document.createElement('div');
  551. statCard.className = 'stat-card';
  552. statCard.innerHTML = `
  553. <h2>${item.category_count}</h2>
  554. <p>${item.file_name}</p>
  555. `;
  556. statsDiv.appendChild(statCard);
  557. });
  558. // Call renderCharts after data is loaded
  559. renderCharts();
  560. },
  561. error: function (xhr) {
  562. console.error('Error fetching dashboard data:', xhr.status, xhr.responseText);
  563. }
  564. });
  565. }
  566. // Function to handle search button click
  567. document.getElementById('searchButton').addEventListener('click', function () {
  568. const startDate = document.getElementById('startDate').value;
  569. const endDate = document.getElementById('endDate').value;
  570. const deptId = $('#deptId').text().trim();
  571. if (!startDate || !endDate) {
  572. Swal.fire({
  573. icon: "warning",
  574. title: "Incomplete Search",
  575. text: "Please select the Date Before searching",
  576. confirmButtonText: "OK",
  577. });
  578. } else {
  579. $.ajax({
  580. url: `/dashboardsearch?startdate=${startDate}&enddate=${endDate}&deptId=${encodeURIComponent(deptId)}`,
  581. type: 'GET',
  582. success: function (data) {
  583. const statsDiv = document.getElementById('stats');
  584. statsDiv.innerHTML = data.map(item => `
  585. <div class='stat-card'>
  586. <h2>${item.category_count}</h2>
  587. <p>${item.file_name}</p>
  588. </div>
  589. `).join('');
  590. // Re-render charts after search results load
  591. renderCharts(startDate, endDate);
  592. },
  593. error: function (xhr) {
  594. console.error('Error fetching search data:', xhr.status, xhr.responseText);
  595. }
  596. });
  597. }
  598. });
  599. // Function to validate and set min-date for endDate
  600. function validateEndDate() {
  601. const startDate = document.getElementById('startDate').value;
  602. const endDateInput = document.getElementById('endDate');
  603. if (startDate) {
  604. const startDateObj = new Date(startDate);
  605. const minEndDateISO = startDateObj.toISOString().split('T')[0];
  606. endDateInput.setAttribute('min', minEndDateISO);
  607. // Clear endDate if it's less than startDate
  608. if (endDateInput.value && new Date(endDateInput.value) < startDateObj) {
  609. endDateInput.value = '';
  610. }
  611. }
  612. }
  613. document.getElementById('startDate').addEventListener('change', validateEndDate);
  614. function renderCharts(startDate = null, endDate = null) {
  615. const deptId = $('#deptId').text().trim();
  616. // Dispose existing amCharts instances
  617. disposeExistingCharts();
  618. function disposeExistingCharts() {
  619. if (window.chart1) {
  620. window.chart1.clear();
  621. window.chart1 = null;
  622. }
  623. if (window.chart2) {
  624. window.chart2.clear();
  625. window.chart2 = null;
  626. }
  627. }
  628. // Render pie chart
  629. const fixedColors = {
  630. "Retirement": "#6A0572", // Deep Purple
  631. "Family Pension": "#2C3E50", // Dark Blue-Gray
  632. "Pendency": "#A569BD", // Soft Lavender
  633. "GIS": "#17A589", // Teal Green
  634. "Provisional Retirement": "#D35400", // Warm Orange
  635. "Contributory Pension Scheme": "#5D6D7E" // Muted Gray-Blue
  636. };
  637. $.ajax({
  638. url: `/categoryCounts`,
  639. type: 'GET',
  640. data: { deptId, startDate, endDate },
  641. dataType: 'json',
  642. success: function (data) {
  643. const chartData = data.map((item, index) => ({
  644. category: item.file_name,
  645. value: item.category_count,
  646. color: fixedColors[item.file_name], // Assign colors cyclically
  647. id: item.id
  648. }));
  649. window.chart1 = AmCharts.makeChart("overallPieChart", {
  650. type: "pie",
  651. theme: "dark",
  652. dataProvider: chartData,
  653. valueField: "value",
  654. titleField: "category",
  655. colorField: "color",
  656. radius: "40%",
  657. innerRadius: "50%",
  658. labelText: "[[[[title]]]] - [[[[value]]]]",
  659. fontSize: 14,
  660. labelsEnabled: true,
  661. pullOutRadius: 0,
  662. gradientRatio: [-0.4, -0.4, -0.4, -0.4, -0.4, -0.4, 0, 0.1, 0.2, 0.1, 0, -0.2, -0.5],
  663. export: {
  664. enabled: true,
  665. },
  666. responsive: {
  667. enabled: true,
  668. },
  669. legend: {
  670. position: "bottom",
  671. markerType: "circle",
  672. valueText: "[[[[value]]]]",
  673. switchable: false,
  674. markerSize: 12,
  675. fontSize: 12
  676. },
  677. balloon: {
  678. fixedPosition: true
  679. },
  680. listeners: [
  681. {
  682. event: "clickSlice",
  683. method: function (event) {
  684. const FileId = event.dataItem.dataContext.id;
  685. const FileNumber = event.dataItem.dataContext.category;
  686. fetchempno(FileId, FileNumber);
  687. }
  688. }
  689. ]
  690. });
  691. },
  692. error: function (xhr, status, error) {
  693. console.error("AJAX Request Failed:", status, error);
  694. console.error("Response Text:", xhr.responseText);
  695. }
  696. });
  697. function fetchempno(FileId, FileNumber) {
  698. $.ajax({
  699. url: `/getEmpNoByFileName?file_id=${FileId}`,
  700. type: 'GET',
  701. success: function (response) {
  702. renderEmpNoModal(FileNumber, response);
  703. },
  704. error: function (xhr) {
  705. console.error("Error fetching region details:", xhr.status, xhr.responseText);
  706. }
  707. });
  708. }
  709. function renderEmpNoModal(FileNumber, empNos) {
  710. console.log(empNos);
  711. const modalContent = `
  712. <div class="modal-header">
  713. <h5 class="modal-title">Employee Numbers for ${FileNumber}</h5>
  714. <button type="button" class="close" data-dismiss="modal" aria-label="Close">
  715. <span aria-hidden="true">&times;</span>
  716. </button>
  717. </div>
  718. <div class="modal-body">
  719. <table class="table table-bordered">
  720. <thead>
  721. <tr><th>Employee Number</th></tr>
  722. </thead>
  723. <tbody>
  724. ${empNos.map(empNo => `<tr><td>${empNo.emp_no}</td></tr>`).join('')}
  725. </tbody>
  726. </table>
  727. </div>
  728. `;
  729. document.getElementById('zone-details-content').innerHTML = modalContent;
  730. // $('#zoneDetailsModal').modal('show');
  731. $('.close').click(function () {
  732. $('#zoneDetailsModal').modal('hide');
  733. });
  734. }
  735. function getRandomColor() {
  736. const letters = '0123456789ABCDEF';
  737. let color = '#';
  738. for (let i = 0; i < 6; i++) {
  739. color += letters[Math.floor(Math.random() * 16)];
  740. }
  741. return color;
  742. }
  743. // Render bar chart
  744. $.ajax({
  745. url: `/stageWiseCounts`,
  746. type: 'GET',
  747. data: { deptId, startDate, endDate },
  748. dataType: 'json',
  749. success: function (data) {
  750. const colorMapping = {
  751. "Audit Pending": "#FF5733",
  752. "Department Pending": "#FFC300",
  753. "Pension Pending": "#28B463",
  754. "Completed": "#3498DB"
  755. };
  756. const chartData = data.map(item => ({
  757. category: item.category,
  758. value: item.category_count,
  759. color: colorMapping[item.category] || '#D3D3D3'
  760. }));
  761. window.chart2 = AmCharts.makeChart("stagesBarChart", {
  762. type: "serial",
  763. theme: "light",
  764. dataProvider: chartData,
  765. depth3D: 2,
  766. angle: 10,
  767. valueAxes: [{
  768. axisAlpha: 0,
  769. gridAlpha: 0,
  770. labelsEnabled: false,
  771. dashLength: 0
  772. }],
  773. startDuration: 1,
  774. startEffect: "easeInSine",
  775. graphs: [{
  776. balloonText: "[[[[category]]]]: [[[[value]]]]",
  777. fillAlphas: 0.8,
  778. lineAlpha: 0.3,
  779. topRadius: 1,
  780. type: "column",
  781. valueField: "value",
  782. fillColorsField: "color",
  783. columnWidth: 0.5,
  784. labelText: "[[[[value]]]]",
  785. labelPosition: "right",
  786. fontSize: 14,
  787. color: "#000000"
  788. }],
  789. categoryField: "category",
  790. categoryAxis: {
  791. gridPosition: "start",
  792. gridAlpha: 0,
  793. autoWrap: false,
  794. axisAlpha: 0,
  795. fontSize: 14, // Increases the category label size
  796. // Makes category labels bold
  797. labelRotation: 0
  798. },
  799. rotate: true,
  800. export: {
  801. enabled: true,
  802. position: "bottom-right"
  803. }
  804. });
  805. console.log("Stages Bar Chart Data:", chartData);
  806. },
  807. error: function (xhr, status, error) {
  808. console.error("AJAX Request Failed:", status, error);
  809. }
  810. });
  811. }
  812. // Initial data load
  813. loadDashboardData();
  814. document.querySelector("input[type='reset']").addEventListener('click', function () {
  815. window.location.href = "/gcc/department/dashboard";
  816. });
  817. })
  818. </script>
  819. </body>
  820. </html>