This portal only for GCC Officers. Based on there roles and Group ID they can view there module`s Like PGR, QR Public Asset Feedback, Makkalai Thedi Mayor,etc...
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.

1049 lines
46 KiB

​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
​
  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. .boxcard {
  7. height: 100px;
  8. border-radius: 20px;
  9. }
  10. .boxcard1 {
  11. height: 200px;
  12. border-radius: 20px;
  13. box-shadow: rgba(0, 0, 0, 0.5) 0px 3px 8px;
  14. }
  15. .required{
  16. color: red;
  17. }
  18. /* Mobile screens - targeting devices with a max width of 767px */
  19. @media (max-width: 767px)
  20. {
  21. #qaqcRequestForm label{
  22. margin-top: 10px;
  23. }
  24. }
  25. .card-box {
  26. border-radius: 20px;
  27. box-shadow: rgba(0, 0, 0, 0.5) 0px 3px 8px;
  28. }
  29. .bg-grey-inline-text {
  30. padding:2px 2px;
  31. background-color: #e6e6e6;
  32. border-radius: 4px;
  33. }
  34. #closedCard {
  35. transition: transform 0.2s ease; /* Smooth scaling transition */
  36. cursor: pointer; /* Default cursor change */
  37. }
  38. #closedCard:hover {
  39. transform: scale(1.05); /* Slightly scale up on hover */
  40. cursor: pointer; /* Change cursor to hand symbol */
  41. }
  42. #inProgressCard {
  43. transition: transform 0.2s ease; /* Smooth scaling transition */
  44. cursor: pointer; /* Default cursor change */
  45. }
  46. #inProgressCard:hover {
  47. transform: scale(1.05); /* Slightly scale up on hover */
  48. cursor: pointer; /* Change cursor to hand symbol */
  49. }
  50. #redressedCard {
  51. transition: transform 0.2s ease; /* Smooth scaling transition */
  52. cursor: pointer; /* Default cursor change */
  53. }
  54. #redressedCard:hover {
  55. transform: scale(1.05); /* Slightly scale up on hover */
  56. cursor: pointer; /* Change cursor to hand symbol */
  57. }
  58. #reopenedCard {
  59. transition: transform 0.2s ease; /* Smooth scaling transition */
  60. cursor: pointer; /* Default cursor change */
  61. }
  62. #reopenedCard:hover {
  63. transform: scale(1.05); /* Slightly scale up on hover */
  64. cursor: pointer; /* Change cursor to hand symbol */
  65. }
  66. #withdrawCard{
  67. transition: transform 0.2s ease; /* Smooth scaling transition */
  68. cursor: pointer; /* Default cursor change */
  69. }
  70. #withdrawCard:hover {
  71. transform: scale(1.05); /* Slightly scale up on hover */
  72. cursor: pointer; /* Change cursor to hand symbol */
  73. }
  74. #closedCard {
  75. transition: transform 0.2s ease; /* Smooth scaling transition */
  76. cursor: pointer; /* Default cursor change */
  77. }
  78. #closedCard:hover {
  79. transform: scale(1.05); /* Slightly scale up on hover */
  80. cursor: pointer; /* Change cursor to hand symbol */
  81. }
  82. </style>
  83. <body>
  84. <!--[if lt IE 8]>
  85. <p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
  86. <![endif]-->
  87. <div class="wrapper">
  88. <!-- header top menu Start -->
  89. <header th:replace="~{fragments/modules/base/header :: header}"></header>
  90. <!-- header top menu end -->
  91. <div class="page-wrap">
  92. <!--=============== Left Menu side Start ================-->
  93. <div th:replace="~{fragments/modules/base/menu :: menu}"></div>
  94. <!--=============== Left side End ================-->
  95. <div class="main-content">
  96. <div class="container-fluid">
  97. <div class="page-header mb-2">
  98. <div class="row align-items-end">
  99. <div class="col-lg-8">
  100. <div class="page-header-title">
  101. <i class="fas fa-tachometer-alt bg-blue"></i>
  102. <div class="d-inline">
  103. <h5>Dashboard QAQC</h5>
  104. <span>1913 QAQC Dashboard</span>
  105. </div>
  106. </div>
  107. </div>
  108. <div class="col-lg-4">
  109. <nav class="breadcrumb-container" aria-label="breadcrumb">
  110. <ol class="breadcrumb">
  111. <li class="breadcrumb-item"><a href="index"><i
  112. class="ik ik-home"></i></a></li>
  113. <li class="breadcrumb-item" aria-current="page">1913 QAQC</li>
  114. <li class="breadcrumb-item" aria-current="page">Admin QAQC</li>
  115. <li class="breadcrumb-item active" aria-current="page">Grievance Dashboard</li>
  116. </ol>
  117. </nav>
  118. </div>
  119. </div>
  120. </div>
  121. <!-- <h4 class="h4 text-right text-mute" style="font-size: 12px;">
  122. Auto refresh in <font id="refresh-countdown">00</font> seconds
  123. </h4> -->
  124. <div class="card mt-4">
  125. <div class="card-header">
  126. <h3>
  127. <img alt="No image" src="/gcc/assets/images/donut-chart.png"
  128. style="height: 23px; width: 23px;" class="mr-2"><b>Overall Grievance
  129. Dashboard</b>
  130. </h3>
  131. </div>
  132. <div class="card-body">
  133. <div class="row">
  134. <div class="col-sm-2 mb-2">
  135. <label for="startDate" style="font-size: medium; margin-bottom: 0px;">From Date:</label>
  136. <input type="date" id="startDate" class="form-control" onclick="this.showPicker()">
  137. </div>
  138. <div class="col-sm-2 mb-2">
  139. <label for="endDate" style="font-size: medium; margin-bottom: 0px;">To Date:</label>
  140. <input type="date" id="endDate" class="form-control" onclick="this.showPicker()">
  141. </div>
  142. <div class="col-sm-2 mb-2">
  143. <label for="regiondropdown" style="font-size: medium; margin-bottom: 0px;">Region:</label>
  144. <select id="regiondropdown" class="form-control">
  145. <option value="">Select</option>
  146. <option value="North Region">North Region</option>
  147. <option value="Central Region">Central Region</option>
  148. <option value="South Region">South Region</option>
  149. </select>
  150. </div>
  151. <div class="col-sm-2 mb-2">
  152. <label for="dropdown4" style="font-size: medium; margin-bottom: 0px;">Group:</label>
  153. <select id="dropdown4" class="form-control">
  154. <option value="">Select</option>
  155. <!-- <option value="">general</option> -->
  156. <!-- Add options here -->
  157. </select>
  158. </div>
  159. <div class="col-sm-2 mb-2">
  160. <label for="dropdown1" style="font-size: medium; margin-bottom: 0px;">Type:</label>
  161. <select id="dropdown1" class="form-control">
  162. <option value="">Select</option>
  163. <!-- <option value="Cleanliness in Parks">Cleanliness in Parks</option> -->
  164. </select>
  165. </div>
  166. <div class="col-sm-2 mb-2">
  167. <label for="dropdown3" style="font-size: medium; margin-bottom: 0px;">Mode:</label>
  168. <select id="dropdown3" class="form-control">
  169. <option value="">Select</option>
  170. <!-- <option value="">INTERNET</option> -->
  171. </select>
  172. </div>
  173. <div class="col-sm-2 mb-2">
  174. <label for="dropdown2" style="font-size: medium; margin-bottom: 0px;">zone:</label>
  175. <select id="dropdown2" class="form-control">
  176. <option value="">Select</option>
  177. </select>
  178. </div>
  179. </div>
  180. <div class="row mt-4">
  181. <div class="col-12 d-flex justify-content-center">
  182. <button type="submit" id="searchButton"
  183. class="btn btn-primary mx-2">Filter</button>
  184. <button class="btn btn-danger mx-2" onclick="resetDate()"
  185. name="reset" type="reset">Reset</button>
  186. </div>
  187. </div>
  188. </div>
  189. <div class="col-12">
  190. <div class="row mt-3">
  191. <!-- First Part: 2 cards vertically -->
  192. <div class="col-lg-4 col-md-4 col-sm-12">
  193. <div class="card card-box" id="inProgressCard">
  194. <p class="text-facebook mb-20 text-center mt-4" id="inProgressname" style="font-size: medium;"><i class="fas fa-spinner text-center" ></i>&nbsp;<b>In-progress</b></p>
  195. <h3 class="text-twitter fw-700 ml-5 text-center" id="inProgressCount"></h3>
  196. </div>
  197. <div class="card card-box" id="redressedCard">
  198. <p class="text-facebook mb-20 text-center mt-4"id="redressedname" style="font-size: medium;"><i class="fas fa-check-circle text-center" style=" color: green;"></i>&nbsp;<b>Action Taken Level 1</b></p>
  199. <h3 class="text-twitter fw-700 ml-5 text-center" id="redressedCount"></h3>
  200. </div>
  201. </div>
  202. <!-- Second Part: 1 card, height equal to both cards in the first part -->
  203. <div class="col-lg-4 col-md-4 col-sm-12 mt-3">
  204. <div class="card boxcard1">
  205. <div class="card-body">
  206. <p class="text-facebook mb-20 text-center mt-4" style="font-size: medium;"><i class="fas fa-clipboard-list text-center"></i>&nbsp;<b>Total Complaints</b></p>
  207. <h3 class="text-twitter fw-700 ml-5 text-center" id="totalComplaints"></h3>
  208. </div>
  209. </div>
  210. </div>
  211. <!-- Third Part: 2 cards vertically -->
  212. <div class="col-lg-4 col-md-4 col-sm-12">
  213. <div class="card card-box" id="reopenedCard">
  214. <p class="text-facebook mb-20 text-center mt-4" id="Reopenname" style="font-size: medium;"><i class="fas fa-exclamation-circle text-center" style=" color: orange;"></i>&nbsp;<b>Reopened</b></p>
  215. <h3 class="text-twitter fw-700 ml-5 text-center" id="reopenedCount"></h3>
  216. </div>
  217. <div class="card card-box" id="closedCard">
  218. <p class="text-facebook mb-20 text-center mt-4" id="Closename" style="font-size: medium;"><i class="fas fa-check-circle text-center" style=" color: green;"></i>&nbsp;<b>Action Taken Level 2</b></p>
  219. <h3 class="text-twitter fw-700 ml-5 text-center" id="closedCount"></h3>
  220. </div>
  221. </div>
  222. <div class="col-12 d-flex justify-content-center">
  223. <div class="col-lg-4 col-md-4 col-sm-12 ">
  224. <div class="card card-box" id="withdrawCard">
  225. <p class="text-facebook mb-20 text-center mt-4" id="withdrawname" style="font-size: medium;"><i class="fa fa-envelope text-center" style=" color: orange;"></i>&nbsp;<b>Withdraw</b></p>
  226. <h3 class="text-twitter fw-700 ml-5 text-center" id="withdrawCount"></h3>
  227. </div>
  228. </div>
  229. </div>
  230. </div>
  231. </div>
  232. <!-- agent wise yesterday performance counts card-->
  233. <div class="card-body">
  234. <div class="page-header-title" >
  235. <h5 style="margin: 0;font-weight: bold;">Yesterday Event - Agent Performance Dashboard</h5><hr>
  236. </div>
  237. <div class="row mt-2">
  238. <div class="col-xl-3 col-md-6 col-sm-12">
  239. <div class="card card-box">
  240. <p class="text-facebook mb-20 text-center mt-4"><b>Agent Assigned</b></p>
  241. <h3 class="text-twitter fw-700 ml-5 text-center" th:text="${previousday[0].TotalAgents}"></h3>
  242. </div>
  243. </div>
  244. <div class="col-xl-3 col-md-6 col-sm-12">
  245. <div class="card card-box">
  246. <p class="text-facebook mb-20 text-center mt-4"><b>Assigned Calls</b></p>
  247. <h3 class="text-twitter fw-700 ml-5 text-center" th:text="${previousday[0].TotalAssigned != null ? previousday[0].TotalAssigned : 0}"></h3>
  248. </div>
  249. </div>
  250. <div class="col-xl-3 col-md-6 col-sm-12">
  251. <div class="card card-box">
  252. <p class="text-facebook mb-20 text-center mt-4"><b>Finished</b></p>
  253. <h3 class="text-twitter fw-700 ml-5 text-center" th:text="${previousday[0].TotalCompleted != null ? previousday[0].TotalCompleted : 0}"></h3>
  254. </div>
  255. </div>
  256. <div class="col-xl-3 col-md-6 col-sm-12">
  257. <div class="card card-box">
  258. <p class="text-facebook mb-20 text-center mt-4"><b>Pending Calls</b></p>
  259. <h3 class="text-twitter fw-700 ml-5 text-center" th:text="${previousday[0].TotalPending != null ? previousday[0].TotalPending : 0}"></h3>
  260. </div>
  261. </div>
  262. </div>
  263. </div>
  264. <div class="col-md-16">
  265. <div class="card-body">
  266. <div class="page-header-title" >
  267. <h5 style="margin: 0;font-weight: bold;">Yesterday Event - Agents Wise Breakup</h5><hr>
  268. </div>
  269. <table id="YesterdayQaqctable" class="table table-striped table-bordered table-hover dataTable" role="grid">
  270. <thead class="thead-dark">
  271. <tr role="row">
  272. <th rowspan="2" class="text-center">S.No</th>
  273. <th rowspan="2" class="text-center">Agent</th>
  274. <th colspan="4" class="text-center">Performance</th>
  275. <th colspan="4" class="text-center">Call Results</th>
  276. </tr>
  277. <tr role="row">
  278. <th class="text-center">Assigned Calls</th>
  279. <th class="text-center">Finished</th>
  280. <th class="text-center">Pending Calls</th>
  281. <th class="text-center">Completion (%)</th>
  282. <th class="text-center">Completed</th>
  283. <th class="text-center">ReOpen</th>
  284. <th class="text-center">Followup</th>
  285. <th class="text-center">Others</th>
  286. </tr>
  287. </thead>
  288. <tbody>
  289. <!-- Loop through the agentcount data -->
  290. <tr th:each="row, iterStat : ${agentcount}">
  291. <td class="text-center" th:text="${iterStat.index + 1}"></td>
  292. <td class="text-center" th:text="${row.agent_name}"></td>
  293. <td class="text-center" th:text="${row.Assigned}"></td>
  294. <td class="text-center" th:text="${row.TotalCompleted}"></td>
  295. <td class="text-center" th:text="${row.Pending}"></td>
  296. <td class="text-center" th:text="${row.CompletionPercentage + '%'}"></td> <td class="text-center" th:text="${row.Completed_count}"></td>
  297. <td class="text-center" th:text="${row.Reopened_count}"></td>
  298. <td class="text-center" th:text="${row.Followup_count}"></td>
  299. <td class="text-center" th:text="${row.Other_count}"></td>
  300. </tr>
  301. </tbody>
  302. </table>
  303. </div>
  304. </div>
  305. </div>
  306. </div>
  307. </div>
  308. <footer th:replace="~{fragments/modules/base/footer :: footer}"></footer>
  309. </div>
  310. </div>
  311. <!-- Details Modal -->
  312. <div class="modal fade" id="detailsModal" tabindex="-1" role="dialog" aria-labelledby="detailsModalLabel" aria-hidden="true">
  313. <div class="modal-dialog modal-xl" role="document">
  314. <div class="modal-content">
  315. <div class="modal-header">
  316. <h5 class="modal-title" id="detailsModalLabel">Complaint Details</h5>
  317. <button type="button" class="close" data-dismiss="modal" aria-label="Close">
  318. <span aria-hidden="true">&times;</span>
  319. </button>
  320. </div>
  321. <div class="modal-body">
  322. <table id="detailsTable" class="table table-striped table-bordered table-hover dataTable" role="grid">
  323. <thead class="thead-dark">
  324. <tr role="row">
  325. <th class="text-center no-sort">S.No</th>
  326. <th class="text-center no-sort">Complaint Number</th>
  327. <th class="text-center">Complaint Type</th>
  328. <th class="text-center">Complaint Group</th>
  329. <th class="text-center">Mode</th>
  330. <th class="text-center">Department</th>
  331. <th class="text-center">Zone</th>
  332. <th class="text-center">Ward</th>
  333. <th class="text-center no-sort">Public Name</th>
  334. <th class="text-center no-sort">Address</th>
  335. <th class="text-center">Public Mobile no</th>
  336. <th class="text-center">Assign To</th>
  337. <th class="text-center">Official Contact Number</th>
  338. <th class="text-center">Current Status</th>
  339. <th class="text-center">Complaint Opened Date</th>
  340. <th class="text-center">Complaint Redressed Date</th>
  341. <th class="text-center">Complaint Closed Date</th>
  342. <th class="text-center">Complaint Reopen Date</th>
  343. <th class="text-center">Complaint Completed Date</th>
  344. </tr>
  345. </thead>
  346. <tbody>
  347. </tbody>
  348. </table>
  349. </div>
  350. </div>
  351. </div>
  352. </div>
  353. <div th:replace="~{fragments/modules/base/app_module_menu_box :: div}"></div>
  354. <script th:replace="~{fragments/modules/base/script :: script}"></script>
  355. <script src="node_modules/tempusdominus-bootstrap-4/build/js/tempusdominus-bootstrap-4.min.js"></script>
  356. <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
  357. <script type="text/javascript">
  358. $(document).ready(function() {
  359. var table = $('#YesterdayQaqctable').DataTable({
  360. dom: 'Bftip',
  361. columnDefs: [
  362. { targets: 'no-sort', orderable: false }
  363. ],
  364. lengthMenu: [
  365. [50, 100, 200, 500, -1],
  366. ['50 rows', '100 rows', '200 rows', 'Show all']
  367. ],
  368. scrollY: '50vh',
  369. fixedColumns: {
  370. left: 1,
  371. right: 1
  372. },
  373. buttons: [
  374. {
  375. extend: 'pageLength',
  376. className: 'btn btn-warning'
  377. },
  378. {
  379. title: 'Data export',
  380. extend: 'copyHtml5',
  381. text: 'Copy',
  382. className: 'btn btn-secondary',
  383. id: 'copyBtn'
  384. },
  385. {
  386. extend: 'excelHtml5',
  387. text: 'Excel',
  388. className: 'btn btn-secondary',
  389. id: 'excelBtn'
  390. },
  391. {
  392. extend: 'csvHtml5',
  393. text: 'CSV',
  394. className: 'btn btn-secondary',
  395. id: 'csvBtn'
  396. },
  397. {
  398. extend: 'pdfHtml5',
  399. text: 'PDF',
  400. className: 'btn btn-secondary',
  401. id: 'pdfBtn'
  402. }
  403. ],
  404. fixedHeader: true,
  405. autoWidth: true,
  406. responsive: true,
  407. searching: false,
  408. select: false,
  409. processing: false
  410. });
  411. // 🟢 Function to Fetch Data & Open Modal
  412. function openDetailsModal(pzone, columnType,pfromDate,ptodate,ptype,pmode,pgroup) {
  413. console.log("Fetching details for:", { pzone, columnType,pfromDate,ptodate,ptype,pmode,pgroup });
  414. // Show loading message in modal
  415. $('#detailsTable tbody').html(`<tr><td colspan="19" class="text-center text-danger">Loading...</td></tr>`);
  416. // Destroy any existing DataTable instance to avoid reinitialization issues
  417. if ($.fn.DataTable.isDataTable("#detailsTable")) {
  418. $('#detailsTable').DataTable().destroy();
  419. }
  420. // Clear table before fetching new data
  421. $('#detailsTable tbody').empty();
  422. const params = new URLSearchParams({
  423. startDate: pfromDate,
  424. endDate: ptodate,
  425. status: columnType,
  426. group: pgroup,
  427. type: ptype,
  428. mode: pmode,
  429. zone: pzone
  430. });
  431. $.ajax({
  432. type: "GET",
  433. url: `/gcc/api/callcenterqaqc/getfilterreport?${params.toString()}`, // Append query string to URL
  434. contentType: "application/json",
  435. success: function (response) {
  436. console.log("API Response:", response);
  437. if (response.status === "success") {
  438. console.log("Details Array:", response.details);
  439. // Ensure details is an array and has at least one entry
  440. if (Array.isArray(response.details) && response.details.length > 0) {
  441. let table = $('#detailsTable').DataTable({
  442. destroy: true,
  443. searching: true,
  444. autoWidth: true,
  445. paging: true,
  446. info: true,
  447. data: response.details,
  448. columns: [
  449. {
  450. data: null,
  451. render: (data, type, row, meta) => meta.row + 1,
  452. className: 'text-center'
  453. },
  454. { data: 'Complaint Number', defaultContent: '-', className: 'text-center' },
  455. { data: 'Complaint Type', defaultContent: '-', className: 'text-center' },
  456. { data: 'Complaint Group', defaultContent: '-', className: 'text-center' },
  457. { data: 'Complaint Mode', defaultContent: '-', className: 'text-center' },
  458. { data: 'Department', defaultContent: '-', className: 'text-center' },
  459. { data: 'Zone', defaultContent: '-', className: 'text-center' },
  460. { data: 'Ward', defaultContent: '-', className: 'text-center' },
  461. { data: 'Complaint Person Name', defaultContent: '-', className: 'text-center' },
  462. { data: 'Address', defaultContent: '-', className: 'text-center' },
  463. { data: 'Complaint Person Number', defaultContent: '-', className: 'text-center' },
  464. { data: 'Assign To', defaultContent: '-', className: 'text-center' },
  465. { data: 'Official Contact Number', defaultContent: '-', className: 'text-center',render: function (data, type, row) {
  466. return (data === null || data === "null") ? '-' : data;
  467. } },
  468. { data: 'Current Status', defaultContent: '-', className: 'text-center' },
  469. { data: 'Complaint Opened Date', defaultContent: '-', className: 'text-center' },
  470. { data: 'Complaint Redressed Date', defaultContent: '-', className: 'text-center',render: function (data, type, row) {
  471. return (data === null || data === "null") ? '-' : data;
  472. } },
  473. { data: 'Complaint Closed Date', defaultContent: '-', className: 'text-center',render: function (data, type, row) {
  474. return (data === null || data === "null") ? '-' : data;
  475. } },
  476. { data: 'Complaint Reopen Date', defaultContent: '-', className: 'text-center',render: function (data, type, row) {
  477. return (data === null || data === "null") ? '-' : data;
  478. } },
  479. { data: 'Complaint Completed Date', defaultContent: '-', className: 'text-center',render: function (data, type, row) {
  480. return (data === null || data === "null") ? '-' : data;
  481. } }
  482. ],
  483. dom: 'Bfrtip',
  484. buttons: [
  485. {
  486. extend: 'pageLength',
  487. className: 'btn btn-warning'
  488. },
  489. {
  490. title: 'Data export',
  491. extend: 'copyHtml5',
  492. text: 'Copy',
  493. className: 'btn btn-secondary',
  494. id: 'copyBtn'
  495. },
  496. {
  497. extend: 'excelHtml5',
  498. text: 'Excel',
  499. className: 'btn btn-secondary',
  500. id: 'excelBtn'
  501. },
  502. {
  503. extend: 'csvHtml5',
  504. text: 'CSV',
  505. className: 'btn btn-secondary',
  506. id: 'csvBtn'
  507. },
  508. {
  509. extend: 'pdfHtml5',
  510. text: 'PDF',
  511. className: 'btn btn-secondary',
  512. id: 'pdfBtn'
  513. }
  514. ],
  515. columnDefs: [
  516. { targets: 'no-sort', orderable: false }
  517. ],
  518. lengthMenu: [
  519. [50, 100, 200, 500, -1],
  520. ['50 rows', '100 rows', '200 rows', 'Show all']
  521. ],
  522. scrollY: '50vh',
  523. scrollX: true,
  524. responsive: false,
  525. searching: true
  526. });
  527. }
  528. $('#detailsModal').modal('show');
  529. }
  530. else if (response.status === "nodata") {
  531. Swal.fire({
  532. icon: 'warning',
  533. title: 'No Data',
  534. text: 'No data available for the selected criteria.'
  535. });
  536. }
  537. else if (response.status === "error") {
  538. $
  539. Swal.fire({
  540. icon: 'error',
  541. title: 'Error',
  542. text: response.message || 'Something went wrong!'
  543. });
  544. }
  545. else {
  546. Swal.fire({
  547. icon: 'error',
  548. title: 'Error',
  549. text: response.message || 'Something went wrong!'
  550. });
  551. }
  552. },
  553. error: function (error) {
  554. $('#pageLoader').hide();
  555. Swal.fire({
  556. icon: 'error',
  557. title: 'Error',
  558. text: response.message || 'Something went wrong!'
  559. });
  560. }
  561. });
  562. }
  563. // Get today's date
  564. const today = new Date();
  565. const year = today.getFullYear();
  566. const month = String(today.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed
  567. const day = String(today.getDate()).padStart(2, '0');
  568. // Calculate the first day of the current month
  569. const startOfMonth = `${year}-${month}-01`; // yyyy-MM-dd format
  570. const todayFormatted = `${year}-${month}-${day}`; // yyyy-MM-dd format
  571. const startDateField = document.getElementById('startDate');
  572. const endDateField = document.getElementById('endDate');
  573. // Event listener for To Date
  574. endDateField.addEventListener('change', function () {
  575. if (endDateField.value) {
  576. startDateField.max = endDateField.value; // Set max value for From Date
  577. } else {
  578. startDateField.removeAttribute('max'); // Remove max if To Date is cleared
  579. }
  580. // Validate From Date against updated To Date
  581. if (startDateField.value && new Date(startDateField.value) > new Date(endDateField.value)) {
  582. startDateField.value = ''; // Clear invalid From Date
  583. alert("From Date cannot be after To Date.");
  584. }
  585. });
  586. // Event listener for From Date
  587. startDateField.addEventListener('change', function () {
  588. if (startDateField.value) {
  589. endDateField.min = startDateField.value; // Set min value for To Date
  590. } else {
  591. endDateField.removeAttribute('min'); // Remove min if From Date is cleared
  592. }
  593. // Validate To Date against updated From Date
  594. if (endDateField.value && new Date(endDateField.value) < new Date(startDateField.value)) {
  595. endDateField.value = ''; // Clear invalid To Date
  596. alert("To Date cannot be before From Date.");
  597. }
  598. });
  599. // Set the default date values in the input fields
  600. if (startDateField && endDateField) {
  601. startDateField.value = startOfMonth; // yyyy-MM-dd format required for input[type="date"]
  602. endDateField.value = todayFormatted; // yyyy-MM-dd format required for input[type="date"]
  603. } else {
  604. console.error("Start date or end date input field not found!");
  605. }
  606. // Call the search logic directly to load default data on page load
  607. loadDashboardData(formatDateForAPI(startOfMonth), formatDateForAPI(todayFormatted));
  608. });
  609. // Helper function to convert yyyy-MM-dd to dd-MM-yyyy for API calls
  610. function formatDateForAPI(dateStr) {
  611. const [year, month, day] = dateStr.split('-');
  612. return `${day}-${month}-${year}`; // Convert to dd-MM-yyyy
  613. }
  614. function loadDashboardData(startDate, endDate) {
  615. // Show loading indicators
  616. call_loading('totalComplaints', 'start');
  617. call_loading('inProgressCount', 'start');
  618. call_loading('redressedCount', 'start');
  619. call_loading('reopenedCount', 'start');
  620. call_loading('closedCount', 'start');
  621. call_loading('withdrawCount', 'start');
  622. // Get dropdown values
  623. const startDateValue = document.getElementById('startDate').value;
  624. const endDateValue = document.getElementById('endDate').value;
  625. const dropdown1 = document.getElementById('dropdown1').value;
  626. const dropdown2 = document.getElementById('dropdown2').value;
  627. const dropdown3 = document.getElementById('dropdown3').value;
  628. const dropdown4 = document.getElementById('dropdown4').value;
  629. const regiondropdown=document.getElementById('regiondropdown').value;
  630. // Make API call to get dashboard data
  631. fetch(`/gcc/api/callcenterqaqc/dashboard?startDate=${startDate}&endDate=${endDate}&dropdown1=${dropdown1}&dropdown2=${dropdown2}&dropdown3=${dropdown3}&dropdown4=${dropdown4}&regiondropdown=${regiondropdown}`)
  632. .then(response => response.json())
  633. .then(data => {
  634. console.log(data);
  635. // Store data in sessionStorage
  636. sessionStorage.setItem('closename', 'closed');
  637. sessionStorage.setItem('closedcount', data["Closed"] || "0");
  638. sessionStorage.setItem('reopenname', 'reopened');
  639. sessionStorage.setItem('reopenedcount', data["Reopened"] || "0");
  640. sessionStorage.setItem('inProgressName', 'processing');
  641. sessionStorage.setItem('inProgressCount', data["In Progress"] || "0");
  642. sessionStorage.setItem('redressedName', 'redressed');
  643. sessionStorage.setItem('redressedCount', data["Redressed"] || "0");
  644. sessionStorage.setItem('withdrawname', 'withdraw');
  645. sessionStorage.setItem('withdrawCount', data["Withdraw"] || "0");
  646. sessionStorage.setItem('startDate', startDateValue);
  647. sessionStorage.setItem('endDate', endDateValue);
  648. sessionStorage.setItem('type', dropdown1);
  649. sessionStorage.setItem('zone', dropdown2);
  650. sessionStorage.setItem('mode', dropdown3);
  651. sessionStorage.setItem('group', dropdown4);
  652. sessionStorage.setItem('region', regiondropdown);
  653. sessionStorage.setItem('redirected', 'true'); // Set flag for redirection
  654. // Function to handle redirection based on count
  655. function handleCardClick(count, cardType, url) {
  656. if (parseInt(count) === 0) {
  657. Swal.fire({
  658. icon: 'info',
  659. title: 'No Data',
  660. text: `No ${cardType} records available.`,
  661. });
  662. } else {
  663. sessionStorage.setItem('cardType', cardType); // Set card type
  664. window.location.href = url;
  665. }
  666. }
  667. // Attach click events to each card
  668. document.getElementById('closedCard').addEventListener('click', function () {
  669. handleCardClick(sessionStorage.getItem('closedcount'), 'Closed', '/gcc/callcenterqaqc/admin/qaqcassigntaskagents');
  670. });
  671. document.getElementById('reopenedCard').addEventListener('click', function () {
  672. handleCardClick(sessionStorage.getItem('reopenedcount'), 'Reopened', '/gcc/callcenterqaqc/admin/qaqcassigntaskagents');
  673. });
  674. document.getElementById('inProgressCard').addEventListener('click', function () {
  675. handleCardClick(sessionStorage.getItem('inProgressCount'), 'In Progress', '/gcc/callcenterqaqc/admin/qaqcassigntaskagents');
  676. });
  677. document.getElementById('redressedCard').addEventListener('click', function () {
  678. handleCardClick(sessionStorage.getItem('redressedCount'), 'Redressed', '/gcc/callcenterqaqc/admin/qaqcassigntaskagents');
  679. });
  680. document.getElementById('withdrawCard').addEventListener('click', function () {
  681. handleCardClick(sessionStorage.getItem('withdrawCount'), 'withdraw', '/gcc/callcenterqaqc/admin/qaqcassigntaskagents');
  682. });
  683. // Update UI with fetched data
  684. document.getElementById('totalComplaints').textContent = data["Total Complaints"] || "0";
  685. document.getElementById('inProgressCount').textContent = data["In Progress"] || "0";
  686. document.getElementById('redressedCount').textContent = data["Redressed"] || "0";
  687. document.getElementById('reopenedCount').textContent = data["Reopened"] || "0";
  688. document.getElementById('closedCount').textContent = data["Closed"] || "0";
  689. document.getElementById('withdrawCount').textContent = data["Withdraw"] || "0";
  690. // Stop loading indicators
  691. call_loading('totalComplaints', 'stop');
  692. call_loading('inProgressCount', 'stop');
  693. call_loading('redressedCount', 'stop');
  694. call_loading('reopenedCount', 'stop');
  695. call_loading('closedCount', 'stop');
  696. call_loading('withdrawCount', 'stop');
  697. })
  698. .catch(error => {
  699. console.error('Error:', error);
  700. });
  701. }
  702. //Event listener for the search button to reload data based on selected filters
  703. document.getElementById('searchButton').addEventListener('click', function () {
  704. // Get values from input fields
  705. const startDateValue = document.getElementById('startDate').value; // yyyy-MM-dd format
  706. const endDateValue = document.getElementById('endDate').value; // yyyy-MM-dd format
  707. const table = $("#PendingDatatable").DataTable();
  708. // Function to format date as dd-MM-yyyy
  709. const formatDate = (dateStr) => {
  710. const [year, month, day] = dateStr.split('-'); // Split yyyy-MM-dd
  711. return `${day}-${month}-${year}`; // Rearrange to dd-MM-yyyy
  712. };
  713. // Convert to dd-MM-yyyy format
  714. const formattedStartDate = formatDate(startDateValue);
  715. const formattedEndDate = formatDate(endDateValue);
  716. // Validate dates
  717. const startDate = new Date(startDateValue); // Use original yyyy-MM-dd for comparison
  718. const endDate = new Date(endDateValue);
  719. if (startDate && endDate && startDate > endDate) {
  720. alert("Start Date should be earlier than End Date.");
  721. return;
  722. }
  723. // Call dashboard data loading logic with formatted date values
  724. loadDashboardData(formattedStartDate, formattedEndDate);
  725. });
  726. //api for complainttypes,group,zone,ward
  727. /* document.addEventListener("DOMContentLoaded", function () {
  728. const complaintTypeDropdown = document.getElementById('dropdown1');
  729. const complaintGroupDropdown = document.getElementById('dropdown4');
  730. const complaintModeDropdown = document.getElementById('dropdown3');
  731. const complaintZoneDropdown = document.getElementById('dropdown2');
  732. const regionName = document.getElementById('regiondropdown');
  733. // Load Complaint Groups
  734. fetch('/gcc/api/callcenterqaqc/getComplaintGroup')
  735. .then(response => response.json())
  736. .then(data => {
  737. // Clear existing options
  738. complaintGroupDropdown.innerHTML = `<option value="">Select</option>`;
  739. // Add options from the API response
  740. data.forEach(complaintGroupName => {
  741. complaintGroupDropdown.innerHTML += `<option value="${complaintGroupName}">${complaintGroupName}</option>`;
  742. });
  743. })
  744. .catch(error => {
  745. console.error('Error fetching complaint groups:', error);
  746. });
  747. // Event Listener for Complaint Group Change
  748. complaintGroupDropdown.addEventListener('change', function () {
  749. const selectedGroup = complaintGroupDropdown.value;
  750. if (selectedGroup) {
  751. // Fetch Complaint Types based on selected group
  752. fetch(`/gcc/api/callcenterqaqc/getComplaintTypesByGroup?group=${encodeURIComponent(selectedGroup)}`)
  753. .then(response => response.json())
  754. .then(data => {
  755. // Clear existing options
  756. complaintTypeDropdown.innerHTML = `<option value="">Select</option>`;
  757. // Add options from the API response
  758. data.forEach(complaintTypeName => {
  759. complaintTypeDropdown.innerHTML += `<option value="${complaintTypeName}">${complaintTypeName}</option>`;
  760. });
  761. })
  762. .catch(error => {
  763. console.error('Error fetching complaint types:', error);
  764. });
  765. } else {
  766. // Clear complaint type dropdown if no group is selected
  767. complaintTypeDropdown.innerHTML = `<option value="">Select</option>`;
  768. }
  769. });
  770. // Load all Modes
  771. fetch('/gcc/api/callcenterqaqc/getModes')
  772. .then(response => response.json())
  773. .then(data => {
  774. // Clear existing options
  775. complaintModeDropdown.innerHTML = `<option value="">Select</option>`;
  776. // Add options from the API response
  777. data.forEach(complaintMode => {
  778. complaintModeDropdown.innerHTML += `<option value="${complaintMode}">${complaintMode}</option>`;
  779. });
  780. })
  781. .catch(error => {
  782. console.error('Error fetching complaint groups:', error);
  783. });
  784. // Load all zones
  785. fetch('/gcc/api/callcenterqaqc/getZones')
  786. .then(response => response.json())
  787. .then(data => {
  788. // Clear existing options
  789. complaintZoneDropdown.innerHTML = `<option value="">Select</option>`;
  790. // Add options from the API response
  791. data.forEach(complaintZone => {
  792. complaintZoneDropdown.innerHTML += `<option value="${complaintZone}">${complaintZone}</option>`;
  793. });
  794. })
  795. .catch(error => {
  796. console.error('Error fetching complaint groups:', error);
  797. });
  798. }); */
  799. document.addEventListener("DOMContentLoaded", function () {
  800. const complaintTypeDropdown = document.getElementById('dropdown1');
  801. const complaintGroupDropdown = document.getElementById('dropdown4');
  802. const complaintModeDropdown = document.getElementById('dropdown3');
  803. const complaintZoneDropdown = document.getElementById('dropdown2');
  804. const regionDropdown = document.getElementById('regiondropdown');
  805. let allZones = []; // Store all zones globally
  806. // Load Complaint Groups
  807. fetch('/gcc/api/callcenterqaqc/getComplaintGroup')
  808. .then(response => response.json())
  809. .then(data => {
  810. complaintGroupDropdown.innerHTML = `<option value="">Select</option>`;
  811. data.forEach(complaintGroupName => {
  812. complaintGroupDropdown.innerHTML += `<option value="${complaintGroupName}">${complaintGroupName}</option>`;
  813. });
  814. })
  815. .catch(error => console.error('Error fetching complaint groups:', error));
  816. // Event Listener for Complaint Group Change
  817. complaintGroupDropdown.addEventListener('change', function () {
  818. const selectedGroup = complaintGroupDropdown.value;
  819. if (selectedGroup) {
  820. fetch(`/gcc/api/callcenterqaqc/getComplaintTypesByGroup?group=${encodeURIComponent(selectedGroup)}`)
  821. .then(response => response.json())
  822. .then(data => {
  823. complaintTypeDropdown.innerHTML = `<option value="">Select</option>`;
  824. data.forEach(complaintTypeName => {
  825. complaintTypeDropdown.innerHTML += `<option value="${complaintTypeName}">${complaintTypeName}</option>`;
  826. });
  827. })
  828. .catch(error => console.error('Error fetching complaint types:', error));
  829. } else {
  830. complaintTypeDropdown.innerHTML = `<option value="">Select</option>`;
  831. }
  832. });
  833. // Load all Modes
  834. fetch('/gcc/api/callcenterqaqc/getModes')
  835. .then(response => response.json())
  836. .then(data => {
  837. complaintModeDropdown.innerHTML = `<option value="">Select</option>`;
  838. data.forEach(complaintMode => {
  839. complaintModeDropdown.innerHTML += `<option value="${complaintMode}">${complaintMode}</option>`;
  840. });
  841. })
  842. .catch(error => console.error('Error fetching complaint modes:', error));
  843. // Load all zones and store them globally
  844. fetch('/gcc/api/callcenterqaqc/getZones')
  845. .then(response => response.json())
  846. .then(data => {
  847. allZones = data; // Store zones globally
  848. updateZoneDropdown(); // Populate zones initially
  849. })
  850. .catch(error => console.error('Error fetching complaint zones:', error));
  851. // Event Listener for Region Dropdown Change
  852. regionDropdown.addEventListener('change', updateZoneDropdown);
  853. // Function to update Zone Dropdown based on Region selection
  854. function updateZoneDropdown() {
  855. const selectedRegion = regionDropdown.value;
  856. complaintZoneDropdown.innerHTML = `<option value="">Select</option>`;
  857. let filteredZones = [];
  858. if (selectedRegion === "North Region") {
  859. filteredZones = allZones.filter(zone => zone >= "N01" && zone <= "N05");
  860. } else if (selectedRegion === "Central Region") {
  861. filteredZones = allZones.filter(zone => zone >= "N06" && zone <= "N10");
  862. } else if (selectedRegion === "South Region") {
  863. filteredZones = allZones.filter(zone => zone >= "N11" && zone <= "N15");
  864. } else {
  865. // Show all if no region is selected
  866. filteredZones = allZones;
  867. }
  868. filteredZones.forEach(zone => {
  869. complaintZoneDropdown.innerHTML += `<option value="${zone}">${zone}</option>`;
  870. });
  871. }
  872. });
  873. //Function to reset date fields
  874. function resetDate() {
  875. window.location.href = "/gcc/callcenterqaqc/admin/qaqcgrievancedashboard";
  876. }
  877. </script>
  878. <script type="text/javascript">
  879. </script>
  880. </body>
  881. </html>