No commits in common. '3281fd4055295a0770d3bbe5818cb17c77d6284d' and '31300a03703348f520ac337a16cd6a79f2a76c96' have entirely different histories.
3281fd4055
...
31300a0370
34 changed files with 2449 additions and 1127 deletions
-
BIN.mvn/wrapper/maven-wrapper.jar
-
2.mvn/wrapper/maven-wrapper.properties
-
3src/main/java/com/feedback/it_asset/ItAssetApplication.java
-
118src/main/java/com/feedback/it_asset/component/UserSessionInterceptor.java
-
395src/main/java/com/feedback/it_asset/controller/APIController.java
-
2src/main/java/com/feedback/it_asset/controller/AssetController.java
-
80src/main/java/com/feedback/it_asset/controller/FeedbackController.java
-
77src/main/java/com/feedback/it_asset/controller/MainController.java
-
18src/main/java/com/feedback/it_asset/dto/FeedbackCountResponse.java
-
6src/main/java/com/feedback/it_asset/dto/ItAssetDashboardDto.java
-
34src/main/java/com/feedback/it_asset/dto/MonthWiseCountsDTO.java
-
4src/main/java/com/feedback/it_asset/entity/AssetCategory.java
-
8src/main/java/com/feedback/it_asset/entity/AssetCategoryQuestions.java
-
10src/main/java/com/feedback/it_asset/entity/GccAssetDetails.java
-
4src/main/java/com/feedback/it_asset/entity/GccFeedbackData.java
-
40src/main/java/com/feedback/it_asset/entity/Role.java
-
154src/main/java/com/feedback/it_asset/entity/User.java
-
57src/main/java/com/feedback/it_asset/entity/UserRole.java
-
6src/main/java/com/feedback/it_asset/repository/GccAssetDetailsRep.java
-
50src/main/java/com/feedback/it_asset/repository/GccFeedbackDataRep.java
-
13src/main/java/com/feedback/it_asset/repository/GccFeedbackRep.java
-
14src/main/java/com/feedback/it_asset/repository/UserRepository.java
-
78src/main/java/com/feedback/it_asset/service/AssetDetailsService.java
-
77src/main/java/com/feedback/it_asset/service/GccAssetService.java
-
3src/main/resources/application.properties
-
452src/main/resources/templates/closedchart.html
-
370src/main/resources/templates/dashboard.html
-
56src/main/resources/templates/gcc-asset-list.html
-
21src/main/resources/templates/gcc-complaint.html
-
409src/main/resources/templates/old-dashboard.html
-
2src/main/resources/templates/pending-complaint.html
-
455src/main/resources/templates/pendingchart.html
-
62src/main/resources/templates/testdashboard.html
-
452src/main/resources/templates/totalchart.html
@ -0,0 +1,2 @@ |
|||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip |
|||
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar |
|||
@ -1,59 +1,59 @@ |
|||
package com.feedback.it_asset.component; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Component; |
|||
import org.springframework.web.servlet.HandlerInterceptor; |
|||
|
|||
import com.feedback.it_asset.AppConfig; |
|||
import com.feedback.it_asset.UserSession; |
|||
import jakarta.servlet.http.HttpServletRequest; |
|||
import jakarta.servlet.http.HttpServletResponse; |
|||
|
|||
@Component |
|||
public class UserSessionInterceptor implements HandlerInterceptor { |
|||
|
|||
@Autowired |
|||
private UserSession userSession; |
|||
@Autowired |
|||
private AppConfig appConfig; |
|||
|
|||
private static final List<String> EXCLUDED_URLS = Arrays.asList("/login", "/", "/api"); |
|||
@Override |
|||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { |
|||
// Get the current request URL |
|||
String requestUrl = request.getRequestURI(); |
|||
|
|||
// Exclude static resources from the check |
|||
if (requestUrl.startsWith("/assets/") || requestUrl.startsWith("/css/") || requestUrl.startsWith("/js/") || requestUrl.startsWith("/images/") || requestUrl.startsWith("/api/")) { |
|||
return true; // Allow the request to proceed without checking the login status |
|||
} |
|||
|
|||
// Exclude the login page from the check |
|||
// Exclude specific URLs from the check |
|||
if (EXCLUDED_URLS.contains(requestUrl)) { |
|||
return true; // Allow the request to proceed without checking the login status |
|||
} |
|||
// Check if the user is logged in |
|||
// If logged in, add the userSession to the model |
|||
// Return true to allow the request to proceed |
|||
//if (isLoggedIn()) { |
|||
if(userSession.getUserId() != null && userSession.getUserType() != null) { |
|||
request.setAttribute("userSession", userSession); |
|||
} else { |
|||
request.setAttribute("title", "Login"); |
|||
request.setAttribute("baseURL", appConfig.getBaseUrl()); |
|||
response.sendRedirect("/login"); |
|||
return false; // Stop further processing of the request |
|||
} |
|||
return true; // Allow the request to proceed |
|||
} |
|||
|
|||
private boolean isLoggedIn() { |
|||
// Implement your login check logic here |
|||
// For example, check if the userSession contains the necessary information |
|||
return userSession.getUserId() != null && userSession.getUserType() != null; |
|||
} |
|||
} |
|||
//package com.feedback.it_asset.component; |
|||
// |
|||
//import java.util.Arrays; |
|||
//import java.util.List; |
|||
// |
|||
//import org.springframework.beans.factory.annotation.Autowired; |
|||
//import org.springframework.stereotype.Component; |
|||
//import org.springframework.web.servlet.HandlerInterceptor; |
|||
// |
|||
//import com.feedback.it_asset.AppConfig; |
|||
//import com.feedback.it_asset.UserSession; |
|||
//import jakarta.servlet.http.HttpServletRequest; |
|||
//import jakarta.servlet.http.HttpServletResponse; |
|||
// |
|||
//@Component |
|||
//public class UserSessionInterceptor implements HandlerInterceptor { |
|||
// |
|||
// @Autowired |
|||
// private UserSession userSession; |
|||
// @Autowired |
|||
// private AppConfig appConfig; |
|||
// |
|||
// private static final List<String> EXCLUDED_URLS = Arrays.asList("/login", "/", "/api"); |
|||
// @Override |
|||
// public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { |
|||
// // Get the current request URL |
|||
// String requestUrl = request.getRequestURI(); |
|||
// |
|||
// // Exclude static resources from the check |
|||
// if (requestUrl.startsWith("/assets/") || requestUrl.startsWith("/css/") || requestUrl.startsWith("/js/") || requestUrl.startsWith("/images/") || requestUrl.startsWith("/api/")) { |
|||
// return true; // Allow the request to proceed without checking the login status |
|||
// } |
|||
// |
|||
// // Exclude the login page from the check |
|||
// // Exclude specific URLs from the check |
|||
// if (EXCLUDED_URLS.contains(requestUrl)) { |
|||
// return true; // Allow the request to proceed without checking the login status |
|||
// } |
|||
// // Check if the user is logged in |
|||
// // If logged in, add the userSession to the model |
|||
// // Return true to allow the request to proceed |
|||
// //if (isLoggedIn()) { |
|||
// if(userSession.getUserId() != null && userSession.getUserType() != null) { |
|||
// request.setAttribute("userSession", userSession); |
|||
// } else { |
|||
// request.setAttribute("title", "Login"); |
|||
// request.setAttribute("baseURL", appConfig.getBaseUrl()); |
|||
// response.sendRedirect("/login"); |
|||
// return false; // Stop further processing of the request |
|||
// } |
|||
// return true; // Allow the request to proceed |
|||
// } |
|||
// |
|||
// private boolean isLoggedIn() { |
|||
// // Implement your login check logic here |
|||
// // For example, check if the userSession contains the necessary information |
|||
// return userSession.getUserId() != null && userSession.getUserType() != null; |
|||
// } |
|||
//} |
|||
@ -0,0 +1,18 @@ |
|||
package com.feedback.it_asset.dto; |
|||
|
|||
public class FeedbackCountResponse { |
|||
|
|||
private long[] counts; |
|||
|
|||
public long[] getCounts() { |
|||
return counts; |
|||
} |
|||
|
|||
public void setCounts(long[] counts) { |
|||
this.counts = counts; |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,6 @@ |
|||
package com.feedback.it_asset.dto; |
|||
|
|||
public class ItAssetDashboardDto { |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,34 @@ |
|||
package com.feedback.it_asset.dto; |
|||
public class MonthWiseCountsDTO { |
|||
private long onlyYesCount; |
|||
private long onlyNoCount; |
|||
|
|||
// Constructors, getters, setters, etc. |
|||
|
|||
public MonthWiseCountsDTO() { |
|||
// default constructor |
|||
} |
|||
|
|||
public MonthWiseCountsDTO(long onlyYesCount, long onlyNoCount) { |
|||
this.onlyYesCount = onlyYesCount; |
|||
this.onlyNoCount = onlyNoCount; |
|||
} |
|||
|
|||
public long getOnlyYesCount() { |
|||
return onlyYesCount; |
|||
} |
|||
|
|||
public void setOnlyYesCount(long onlyYesCount) { |
|||
this.onlyYesCount = onlyYesCount; |
|||
} |
|||
|
|||
public long getOnlyNoCount() { |
|||
return onlyNoCount; |
|||
} |
|||
|
|||
public void setOnlyNoCount(long onlyNoCount) { |
|||
this.onlyNoCount = onlyNoCount; |
|||
} |
|||
} |
|||
|
|||
|
|||
@ -0,0 +1,40 @@ |
|||
package com.feedback.it_asset.entity; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
|||
|
|||
import jakarta.persistence.Column; |
|||
import jakarta.persistence.Entity; |
|||
import jakarta.persistence.GeneratedValue; |
|||
import jakarta.persistence.GenerationType; |
|||
import jakarta.persistence.Id; |
|||
import jakarta.persistence.Table; |
|||
|
|||
@Entity |
|||
@JsonIgnoreProperties({ "hibernateLazyInitializer", "handler"}) |
|||
@Table(name = "roles") |
|||
public class Role { |
|||
@Id |
|||
@Column(name = "role_id") |
|||
@GeneratedValue(strategy = GenerationType.IDENTITY) |
|||
private Integer id; |
|||
|
|||
private String name; |
|||
public Integer getId() { |
|||
return id; |
|||
} |
|||
|
|||
public Role() { |
|||
} |
|||
|
|||
public void setId(Integer id) { |
|||
this.id = id; |
|||
} |
|||
|
|||
public String getName() { |
|||
return name; |
|||
} |
|||
|
|||
public void setName(String name) { |
|||
this.name = name; |
|||
} |
|||
} |
|||
@ -1,43 +1,133 @@ |
|||
package com.feedback.it_asset.entity; |
|||
|
|||
import java.util.HashSet; |
|||
import java.util.Set; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
|||
|
|||
import jakarta.persistence.CascadeType; |
|||
import jakarta.persistence.Column; |
|||
import jakarta.persistence.Entity; |
|||
import jakarta.persistence.GeneratedValue; |
|||
import jakarta.persistence.GenerationType; |
|||
import jakarta.persistence.FetchType; |
|||
import jakarta.persistence.Id; |
|||
import jakarta.persistence.JoinColumn; |
|||
import jakarta.persistence.JoinTable; |
|||
import jakarta.persistence.ManyToMany; |
|||
import jakarta.persistence.Table; |
|||
|
|||
@Entity |
|||
@JsonIgnoreProperties({ "hibernateLazyInitializer", "handler"}) |
|||
@Table(name = "users") |
|||
public class User { |
|||
|
|||
@Id |
|||
@GeneratedValue(strategy = GenerationType.IDENTITY) |
|||
private int id; |
|||
private String username; |
|||
private String password; |
|||
private String usertype; |
|||
public int getId() { |
|||
return id; |
|||
} |
|||
public void setId(int id) { |
|||
this.id = id; |
|||
} |
|||
public String getUsername() { |
|||
return username; |
|||
} |
|||
public void setUsername(String username) { |
|||
this.username = username; |
|||
} |
|||
public String getPassword() { |
|||
return password; |
|||
} |
|||
public void setPassword(String password) { |
|||
this.password = password; |
|||
} |
|||
public String getUsertype() { |
|||
return usertype; |
|||
} |
|||
public void setUsertype(String usertype) { |
|||
this.usertype = usertype; |
|||
} |
|||
@Column(name = "user_id") |
|||
private Long id; |
|||
@Column(name = "first_name") |
|||
private String firstName; |
|||
@Column(name = "last_name") |
|||
private String lastName; |
|||
@Column(name = "display_name") |
|||
private String displayName; |
|||
@Column(name = "uname") |
|||
private String userameTxt; |
|||
@Column(name = "pword") |
|||
private String passwordTxt; |
|||
|
|||
@Column(name = "isdelete",nullable = false, columnDefinition = "Boolean default false") |
|||
private Boolean isDelete; |
|||
@Column(name = "isactive",nullable = false, columnDefinition = "Boolean default true") |
|||
private Boolean isActive; |
|||
@Column(name = "cdate",nullable = false, columnDefinition = "DATETIME DEFAULT CURRENT_TIMESTAMP") |
|||
private String cDate; |
|||
|
|||
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) |
|||
@JoinTable( |
|||
name = "users_roles", |
|||
joinColumns = @JoinColumn(name = "user_id"), |
|||
inverseJoinColumns = @JoinColumn(name = "role_id") |
|||
) |
|||
private Set<Role> roles = new HashSet<>(); |
|||
|
|||
public User() { |
|||
} |
|||
|
|||
public Long getId() { |
|||
return id; |
|||
} |
|||
|
|||
public void setId(Long id) { |
|||
this.id = id; |
|||
} |
|||
|
|||
public String getFirstName() { |
|||
return firstName; |
|||
} |
|||
|
|||
public void setFirstName(String firstName) { |
|||
this.firstName = firstName; |
|||
} |
|||
|
|||
public String getLastName() { |
|||
return lastName; |
|||
} |
|||
|
|||
public void setLastName(String lastName) { |
|||
this.lastName = lastName; |
|||
} |
|||
|
|||
public String getDisplayName() { |
|||
return displayName; |
|||
} |
|||
|
|||
public void setDisplayName(String displayName) { |
|||
this.displayName = displayName; |
|||
} |
|||
|
|||
public String getUserameTxt() { |
|||
return userameTxt; |
|||
} |
|||
|
|||
public void setUserameTxt(String userameTxt) { |
|||
this.userameTxt = userameTxt; |
|||
} |
|||
|
|||
public String getPasswordTxt() { |
|||
return passwordTxt; |
|||
} |
|||
|
|||
public void setPasswordTxt(String passwordTxt) { |
|||
this.passwordTxt = passwordTxt; |
|||
} |
|||
|
|||
public Boolean getDelete() { |
|||
return isDelete; |
|||
} |
|||
|
|||
public void setDelete(Boolean delete) { |
|||
isDelete = delete; |
|||
} |
|||
|
|||
public Boolean getActive() { |
|||
return isActive; |
|||
} |
|||
|
|||
public void setActive(Boolean active) { |
|||
isActive = active; |
|||
} |
|||
|
|||
public String getcDate() { |
|||
return cDate; |
|||
} |
|||
|
|||
public void setcDate(String cDate) { |
|||
this.cDate = cDate; |
|||
} |
|||
|
|||
public Set<Role> getRoles() { |
|||
return roles; |
|||
} |
|||
|
|||
public void setRoles(Set<Role> roles) { |
|||
this.roles = roles; |
|||
} |
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
package com.feedback.it_asset.entity; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
|||
|
|||
import jakarta.persistence.Entity; |
|||
import jakarta.persistence.GeneratedValue; |
|||
import jakarta.persistence.GenerationType; |
|||
import jakarta.persistence.Id; |
|||
import jakarta.persistence.JoinColumn; |
|||
import jakarta.persistence.ManyToOne; |
|||
import jakarta.persistence.Table; |
|||
|
|||
@Entity |
|||
@JsonIgnoreProperties({ "hibernateLazyInitializer", "handler"}) |
|||
@Table(name = "users_roles") |
|||
public class UserRole { |
|||
@Id |
|||
@GeneratedValue(strategy = GenerationType.IDENTITY) |
|||
private Long id; |
|||
|
|||
@ManyToOne |
|||
@JoinColumn(name = "user_id", referencedColumnName = "user_id") |
|||
private User user; |
|||
|
|||
@ManyToOne |
|||
@JoinColumn(name = "role_id", referencedColumnName = "role_id") |
|||
private Role role; |
|||
|
|||
// constructor, getters, and setters |
|||
|
|||
public UserRole() { |
|||
} |
|||
|
|||
public Long getId() { |
|||
return id; |
|||
} |
|||
|
|||
public void setId(Long id) { |
|||
this.id = id; |
|||
} |
|||
|
|||
public User getUser() { |
|||
return user; |
|||
} |
|||
|
|||
public void setUser(User user) { |
|||
this.user = user; |
|||
} |
|||
|
|||
public Role getRole() { |
|||
return role; |
|||
} |
|||
|
|||
public void setRole(Role role) { |
|||
this.role = role; |
|||
} |
|||
} |
|||
@ -1,78 +0,0 @@ |
|||
package com.feedback.it_asset.service; |
|||
|
|||
import java.sql.Connection; |
|||
import java.sql.DriverManager; |
|||
import java.sql.PreparedStatement; |
|||
import java.sql.SQLException; |
|||
|
|||
import org.springframework.stereotype.Service; |
|||
|
|||
|
|||
@Service |
|||
public class AssetDetailsService { |
|||
|
|||
|
|||
private static final String SOURCE_JDBC_URL = "jdbc:mysql://localhost:3306/gcc_asset_details"; |
|||
private static final String DESTINATION_JDBC_URL = "jdbc:mysql://localhost:3306/it_assets"; |
|||
private static final String SOURCE_USERNAME = "root"; |
|||
private static final String SOURCE_PASSWORD = "root"; |
|||
private static final String DESTINATION_USERNAME = "root"; |
|||
private static final String DESTINATION_PASSWORD = "root"; |
|||
|
|||
public void migrateData() { |
|||
try { |
|||
// Load the JDBC driver |
|||
Class.forName("com.mysql.cj.jdbc.Driver"); |
|||
|
|||
// Establish connections for source and destination databases |
|||
try ( |
|||
Connection sourceConnection = DriverManager.getConnection(SOURCE_JDBC_URL, SOURCE_USERNAME, SOURCE_PASSWORD); |
|||
Connection destinationConnection = DriverManager.getConnection(DESTINATION_JDBC_URL, DESTINATION_USERNAME, DESTINATION_PASSWORD) |
|||
) { |
|||
// SQL query to fetch data from the source schema |
|||
String sqlQuery = "SELECT ta.ASSET_ID, ta.ASSET_NO, td.DEPT_NAME, tl.LOC_NAME, tsu.SEC_USER_NAME " + |
|||
"FROM tbl_asset ta " + |
|||
"JOIN tbl_mas_dept td ON ta.DEPT_ID = td.DEPT_ID " + |
|||
"JOIN tbl_mas_loc tl ON ta.LOC_ID = tl.LOC_ID " + |
|||
"JOIN tbl_mas_sec_user tsu ON ta.SECUSER_ID = tsu.SEC_USER_ID "; |
|||
|
|||
|
|||
// Create a prepared statement for the source database |
|||
try (PreparedStatement preparedStatementSource = sourceConnection.prepareStatement(sqlQuery)) { |
|||
|
|||
// Execute the query in the source database |
|||
try (var resultSet = preparedStatementSource.executeQuery()) { |
|||
// SQL query to insert data into the destination schema for asset_data |
|||
String insertAssetDataQuery = "INSERT INTO gcc_asset_details (asset_id, asset_code, department_name, position, assign_person) VALUES (?, ?, ?, ?, ?)"; |
|||
|
|||
// SQL query to insert data into the destination schema for asset_category |
|||
// String insertAssetCategoryQuery = "INSERT INTO asset_category (category_name) VALUES (?)"; |
|||
|
|||
// Create prepared statements for the destination database |
|||
try (PreparedStatement preparedStatementDestinationAssetData = destinationConnection.prepareStatement(insertAssetDataQuery)) { |
|||
|
|||
// Process the result set and insert data into the destination schema |
|||
while (resultSet.next()) { |
|||
// Insert data into asset_data table |
|||
preparedStatementDestinationAssetData.setString(1, resultSet.getString("ASSET_ID")); |
|||
preparedStatementDestinationAssetData.setString(2, resultSet.getString("ASSET_NO")); |
|||
preparedStatementDestinationAssetData.setString(3, resultSet.getString("DEPT_NAME")); |
|||
preparedStatementDestinationAssetData.setString(4, resultSet.getString("LOC_NAME")); |
|||
preparedStatementDestinationAssetData.setString(5, resultSet.getString("SEC_USER_NAME")); |
|||
int rowsAffectedAssetData = preparedStatementDestinationAssetData.executeUpdate(); |
|||
System.out.println("Rows affected for asset_data: " + rowsAffectedAssetData); |
|||
|
|||
// Insert data into asset_category table |
|||
// preparedStatementDestinationAssetCategory.setString(1, resultSet.getString("category_name")); |
|||
// int rowsAffectedAssetCategory = preparedStatementDestinationAssetCategory.executeUpdate(); |
|||
// System.out.println("Rows affected for asset_category: " + rowsAffectedAssetCategory); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} catch (ClassNotFoundException | SQLException e) { |
|||
e.printStackTrace(); // Handle the exception appropriately |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,452 @@ |
|||
<!doctype html> |
|||
<html xmlns:th="http://www.thymeleaf.org"> |
|||
<head th:replace="fragments/head :: head"></head> |
|||
|
|||
<body> |
|||
<!-- Page Container --> |
|||
<div id="page-container" class="sidebar-o sidebar-dark enable-page-overlay side-scroll page-header-fixed page-header-dark"> |
|||
<!-- Side Overlay aside (right)--> |
|||
<aside th:replace="fragments/aside-right :: aside"></aside> |
|||
<!-- END Side Overlay (right)--> |
|||
|
|||
<!-- Sidebar Nav--> |
|||
<nav th:replace="fragments/nav :: nav"></nav> |
|||
<!-- END Sidebar --> |
|||
|
|||
<!-- Header --> |
|||
<header th:replace="fragments/header :: header"></header> |
|||
<!-- END Header --> |
|||
|
|||
<!-- Main Container --> |
|||
<main id="main-container"> |
|||
<!-- Hero --> |
|||
<div class=""> |
|||
<div class="content content-full"> |
|||
<div class="d-flex flex-column flex-sm-row justify-content-sm-between align-items-sm-center"> |
|||
<h3 class="flex-grow-1 fs-5 fw-semibold my-2 my-sm-3">Welcome</h3> |
|||
<nav class="flex-shrink-0 my-2 my-sm-0 ms-sm-3" aria-label="breadcrumb"> |
|||
<ol class="breadcrumb"> |
|||
<li class="breadcrumb-item">Home</li> |
|||
<li class="breadcrumb-item active" aria-current="page">Dashboard</li> |
|||
</ol> |
|||
</nav> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END Hero --> |
|||
|
|||
<!-- Page Content --> |
|||
<div class="content"> |
|||
<!-- Overview --> |
|||
<div class="row items-push"> |
|||
<div class="col-sm-6 col-xl-3"> |
|||
<div class="block block-rounded text-center d-flex flex-column h-100 mb-0"> |
|||
<div class="block-content block-content-full flex-grow-1"> |
|||
<div class="item rounded-3 bg-body mx-auto my-3"> |
|||
<i class="fa fa-qrcode fa-lg text-primary"></i> |
|||
</div> |
|||
<div class="fs-2 fw-bold text-success" th:utext="${totalAssets}">000</div> |
|||
<div class="text-muted mb-1 fs-5">Total Asset</div> |
|||
|
|||
</div> |
|||
<div class="block-content block-content-full block-content-sm bg-body-light fs-sm"> |
|||
<a class="fw-medium" href="/gcc-asset-list"> |
|||
View all Assets |
|||
<i class="fa fa-arrow-right ms-1 opacity-25"></i> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-sm-6 col-xl-3"> |
|||
<div class="block block-rounded text-center d-flex flex-column h-100 mb-0"> |
|||
<div class="block-content block-content-full flex-grow-1"> |
|||
<div class="item rounded-3 bg-body mx-auto my-3"> |
|||
<i class="fa fa-comments fa-lg text-primary"></i> |
|||
</div> |
|||
<div class="fs-2 fw-bold text-info" th:utext="${totalFeedbacks}">000</div> |
|||
<div class="text-muted mb-1 fs-5">Total Complaints</div> |
|||
|
|||
</div> |
|||
<div class="block-content block-content-full block-content-sm bg-body-light fs-sm"> |
|||
<a class="fw-medium" href="/complaint-list"> |
|||
View all Complaints |
|||
<i class="fa fa-arrow-right ms-1 opacity-25"></i> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-sm-6 col-xl-3"> |
|||
<div class="block block-rounded text-center d-flex flex-column h-100 mb-0"> |
|||
<div class="block-content block-content-full flex-grow-1"> |
|||
<div class="item rounded-3 bg-body mx-auto my-3"> |
|||
<i class="fa fa-thumbs-up fa-lg text-primary"></i> |
|||
</div> |
|||
<div class="fs-2 fw-bold text-success" th:utext="${totalYesFeedbacks}">000</div> |
|||
<div class="text-muted mb-1 fs-5">Total closed Complaints</div> |
|||
|
|||
</div> |
|||
<div class="block-content block-content-full block-content-sm bg-body-light fs-sm"> |
|||
<a class="fw-medium" href="/closed-complaint"> |
|||
View all Closed Complaints |
|||
<i class="fa fa-arrow-right ms-1 opacity-25"></i> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-sm-6 col-xl-3"> |
|||
<div class="block block-rounded text-center d-flex flex-column h-100 mb-0"> |
|||
<div class="block-content block-content-full"> |
|||
<div class="item rounded-3 bg-body mx-auto my-3"> |
|||
<i class="fa fa-thumbs-down fa-lg text-primary"></i> |
|||
</div> |
|||
<div class="fs-2 fw-bold text-warning" th:utext="${totalNoFeedbacks}">000</div> |
|||
<div class="text-muted mb-1 fs-5">Total Pending Complaints</div> |
|||
|
|||
</div> |
|||
<div class="block-content block-content-full block-content-sm bg-body-light fs-sm"> |
|||
<a class="fw-medium" href="/pending-complaint"> |
|||
View all Pending Complaint |
|||
<i class="fa fa-arrow-right ms-1 opacity-25"></i> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END Overview --> |
|||
|
|||
<!-- Store Growth --> |
|||
|
|||
<div class="row"> |
|||
<div class="col-12 col-md-6 col-xl-6"> |
|||
<div class="p-md-2 p-lg-3 w-100" style="height: 400px;"> |
|||
<!-- Chart 1 Container --> |
|||
<canvas id="myChart1"></canvas> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="col-12 col-md-6 col-xl-6"> |
|||
<div class="p-md-2 p-lg-3 w-100" style="height: 500px;"> |
|||
<!-- Chart 2 Container --> |
|||
<canvas id="myChart"></canvas> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
<!-- END Store Growth --> |
|||
|
|||
<!-- Latest Orders + Stats --> |
|||
|
|||
<!-- END Latest Orders + Stats --> |
|||
</div> |
|||
<!-- END Page Content --> |
|||
</main> |
|||
<!-- END Main Container --> |
|||
|
|||
<!-- Footer --> |
|||
<footer th:replace="fragments/footer :: footer"></footer> |
|||
<!-- END Footer --> |
|||
</div> |
|||
<!-- END Page Container --> |
|||
|
|||
<!-- Scripts --> |
|||
<!-- Include jQuery --> |
|||
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script> |
|||
<!-- Your existing script tag follows --> |
|||
<script th:replace="fragments/script :: script"></script> |
|||
<!-- Page JS Plugins --> |
|||
<script src="assets/js/plugins/chart.js/chart.umd.js"></script> |
|||
<!-- Include Date Range Picker --> |
|||
<script type="text/javascript" src="assets/js/plugins/bootstrap-daterangepicker/daterangepicker.js"></script> |
|||
<link rel="stylesheet" type="text/css" href="assets/js/plugins/bootstrap-daterangepicker/daterangepicker.css" /> |
|||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> |
|||
|
|||
<script> |
|||
var dash = {}; |
|||
|
|||
function convert() { |
|||
// Ensure proper initialization logic for feedbackAnalysisData |
|||
dash.feedbackAnalysisData = /*[[${dashboard}]]*/ {}; |
|||
} |
|||
|
|||
convert(); |
|||
|
|||
|
|||
var pageDashboard = { |
|||
chartBars: undefined, |
|||
chartLinesBarsData: { |
|||
datasets: [ |
|||
{ data: [] }, // Assuming totalYesFeedbacks is an array |
|||
{ data: [] }, |
|||
{data:[] } // Assuming totalNoFeedbacks is an array |
|||
] |
|||
}, |
|||
|
|||
initChart: function (feedbackAnalysis) { |
|||
// Set Global Chart.js configuration |
|||
Chart.defaults.color = '#818d96'; |
|||
Chart.defaults.scale.grid.color = 'transparent'; |
|||
Chart.defaults.scale.grid.zeroLineColor = 'transparent'; |
|||
Chart.defaults.scale.beginAtZero = true; |
|||
Chart.defaults.elements.line.borderWidth = 1; |
|||
Chart.defaults.plugins.legend.labels.boxWidth = 12; |
|||
|
|||
// Get Chart Container |
|||
let chartBarsCon = document.getElementById('myChart'); |
|||
|
|||
var data = { |
|||
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], |
|||
datasets: [ |
|||
{ |
|||
label: 'Pending Complaint', |
|||
data: [], |
|||
fill: true, |
|||
backgroundColor: '#e74c3c', |
|||
borderColor: 'transparent', |
|||
pointBackgroundColor: '#c2d7ab', |
|||
pointBorderColor: '#fff', |
|||
pointHoverBackgroundColor: '#c0392b', |
|||
pointHoverBorderColor: '#c2d7ab', |
|||
}, |
|||
|
|||
] |
|||
}; |
|||
|
|||
|
|||
var options = { |
|||
responsive: true, |
|||
scales: { |
|||
x: { beginAtZero: true }, |
|||
y: { beginAtZero: true } |
|||
}, |
|||
plugins: { |
|||
datalabels: { |
|||
anchor: 'end', |
|||
align: 'end', |
|||
color: 'black', |
|||
formatter: function (value, context) { |
|||
// Display the value only if it's greater than 0 |
|||
return value > 0 ? value : ''; |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
// Create the chart |
|||
this.chartBars = new Chart(chartBarsCon, { |
|||
type: 'bar', |
|||
data: data, |
|||
options: options |
|||
}); |
|||
}, |
|||
updateChartLinesBarsData: function (newData) { |
|||
// Ensure the chart is initialized before updating |
|||
if (this.chartBars) { |
|||
// Assuming labels for the chart are ['Jan', 'Feb', 'Mar', ..., 'Dec'] |
|||
var labels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; |
|||
|
|||
// Initialize arrays with values from dataArray |
|||
var totalFeedbacksData = Array.from({ length: labels.length }, (_, index) => { |
|||
return newData.reduce((sum, item) => { |
|||
const key = Object.keys(item)[0]; |
|||
const dataArray = item[key]; |
|||
// console.log(totalFeedbacksData[${index}]: ${dataArray[index]}); |
|||
return sum + dataArray[index]; |
|||
}, 0); |
|||
}); |
|||
|
|||
var totalYesFeedbacksData = Array.from({ length: labels.length }, (_, index) => { |
|||
return newData.reduce((sum, item) => { |
|||
const key = Object.keys(item)[0]; |
|||
const dataArray = item[key]; |
|||
// console.log(totalYesFeedbacksData[${index}]: ${dataArray[index]}); |
|||
return dataArray[index]; |
|||
}, 0); |
|||
}); |
|||
|
|||
// Subtract totalYesFeedbacksData from totalFeedbacksData |
|||
var totalNoFeedbacksData = totalFeedbacksData.map((value, index) => value - totalYesFeedbacksData[index]); |
|||
|
|||
// Update the chart data |
|||
// this.chartBars.data.datasets[0].data = totalFeedbacksData; |
|||
this.chartBars.data.datasets[0].data = totalYesFeedbacksData; |
|||
//this.chartBars.data.datasets[0].data = totalNoFeedbacksData; |
|||
|
|||
// Log the updated chart data |
|||
// console.log('Updated chart data (totalFeedbacksData):', this.chartBars.data.datasets[0].data); |
|||
//console.log('Updated chart data (totalYesFeedbacksData):', this.chartBars.data.datasets[1].data); |
|||
//console.log('Updated chart data (totalNoFeedbacksData):', this.chartBars.data.datasets[2].data); |
|||
|
|||
// Update the chart |
|||
this.chartBars.update(); |
|||
} else { |
|||
console.error('Chart is not initialized. Unable to update data.'); |
|||
} |
|||
}, |
|||
|
|||
|
|||
|
|||
getAndPushData: function (cdate) { |
|||
// Ensure convert() is called before accessing dash.feedbackAnalysisData |
|||
convert(); |
|||
|
|||
var self = this; |
|||
|
|||
$.ajax({ |
|||
url: 'api/cou/' + cdate, |
|||
method: 'GET', |
|||
dataType: 'json', |
|||
success: function (response) { |
|||
console.log('Data fetched successfully:', response); |
|||
self.updateChartLinesBarsData(response); |
|||
}, |
|||
error: function (xhr, status, error) { |
|||
console.error('Error:', error); |
|||
} |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
// Call the initChart function with the feedbackAnalysis data |
|||
pageDashboard.initChart(dash.feedbackAnalysisData || {}); |
|||
|
|||
// Call the getAndPushData method to fetch and update chart data |
|||
pageDashboard.getAndPushData(); |
|||
|
|||
pageDashboard.getAndPushData(); |
|||
var pageDashboard = { |
|||
chartPie: undefined, |
|||
chartPieData: { |
|||
labels: ['Total Complaints', 'Closed Complaint', 'Pending Complaint'], |
|||
datasets: [ |
|||
{ |
|||
data: [], |
|||
backgroundColor: ['#3498db', '#e74c3c', '#cc6633'], |
|||
hoverBackgroundColor: ['#2980b9', '#c0392b', '#A35128'] |
|||
} |
|||
] |
|||
}, |
|||
|
|||
initChart: function () { |
|||
// Get Chart Container |
|||
let chartPieCon = document.getElementById('myChart1'); |
|||
|
|||
var options = { |
|||
responsive: true, |
|||
plugins: { |
|||
datalabels: { |
|||
color: 'black', |
|||
formatter: function (value) { |
|||
// Display the value only if it's greater than 0 |
|||
return value > 0 ? value : ''; |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
// Create the chart |
|||
this.chartPie = new Chart(chartPieCon, { |
|||
type: 'pie', |
|||
data: this.chartPieData, |
|||
options: options |
|||
}); |
|||
|
|||
// Add click event listener to the chart container |
|||
chartPieCon.onclick = function (event) { |
|||
var elements = pageDashboard.chartPie.getElementsAtEventForMode(event, 'point', pageDashboard.chartPie.options); |
|||
|
|||
if (elements && elements.length > 0) { |
|||
var clickedIndex = elements[0].index; |
|||
console.log('Clicked Index:', clickedIndex); |
|||
console.log('Elements:', elements); |
|||
console.log('Labels:', pageDashboard.chartPieData.labels); |
|||
|
|||
} else { |
|||
console.error('No elements found at the click event.'); |
|||
} |
|||
if (clickedIndex >= 0 && clickedIndex < pageDashboard.chartPieData.labels.length) { |
|||
var clickedLabel = pageDashboard.chartPieData.labels[clickedIndex]; |
|||
|
|||
// Log the clicked label for debugging |
|||
console.log('Clicked Label:', clickedLabel); |
|||
|
|||
// Navigate based on the clicked label |
|||
switch (clickedLabel) { |
|||
case 'Total Complaints': |
|||
console.log('Navigating to pendingchart.html'); |
|||
window.location.href = 'pendingchart.html'; |
|||
break; |
|||
case 'Pending Complaint': |
|||
console.log('Navigating to nofeedbacks.html'); |
|||
window.location.href = 'closedchart.html'; |
|||
break; |
|||
case 'Closed Complaint': |
|||
console.log('Navigating to yesfeedbacks.html'); |
|||
window.location.href = 'totalchart.html'; |
|||
break; |
|||
// Add more cases for other labels if needed |
|||
default: |
|||
console.log('No action defined for clicked label:', clickedLabel); |
|||
} |
|||
} else { |
|||
console.error('Invalid clicked index:', clickedIndex); |
|||
} |
|||
|
|||
}; |
|||
}, |
|||
|
|||
updateChartPieData: function (data) { |
|||
if (this.chartPie) { |
|||
var totalFeedbacks = data.totalFeedbacks || 0; |
|||
var totalYesFeedbacks = data.totalYesFeedbacks || 0; |
|||
var totalNoFeedbacks = data.totalNoFeedbacks || 0; |
|||
|
|||
// Update the chart data |
|||
this.chartPieData.datasets[0].data = [totalFeedbacks, totalYesFeedbacks, totalNoFeedbacks]; |
|||
|
|||
// Update the chart |
|||
this.chartPie.update(); |
|||
} else { |
|||
console.error('Chart is not initialized. Unable to update data.'); |
|||
} |
|||
}, |
|||
|
|||
getAndPushData: function () { |
|||
// Assume you have a function named 'convert' |
|||
convert(); |
|||
var self = this; |
|||
|
|||
// Fetch data from the actual API |
|||
$.ajax({ |
|||
url: 'http://localhost:8071/api/dashboard-summary', |
|||
method: 'GET', |
|||
dataType: 'json', |
|||
success: function (response) { |
|||
console.log('Data fetched successfully:', response); |
|||
|
|||
// Call the function to process the API response |
|||
self.updateChartPieData(response); |
|||
}, |
|||
error: function (xhr, status, error) { |
|||
console.error('Error:', error); |
|||
} |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
// Call the initChart function |
|||
pageDashboard.initChart(); |
|||
|
|||
// Call the getAndPushData method to fetch and update chart data |
|||
pageDashboard.getAndPushData(); |
|||
|
|||
|
|||
|
|||
|
|||
</script> |
|||
</body> |
|||
</html> |
|||
@ -1,409 +0,0 @@ |
|||
<!doctype html> |
|||
<html xmlns:th="http://www.thymeleaf.org"> |
|||
<head th:replace="fragments/head :: head"></head> |
|||
|
|||
<body> |
|||
<!-- Page Container --> |
|||
<div id="page-container" class="sidebar-o sidebar-dark enable-page-overlay side-scroll page-header-fixed page-header-dark"> |
|||
<!-- Side Overlay aside (right)--> |
|||
<aside th:replace="fragments/aside-right :: aside"></aside> |
|||
<!-- END Side Overlay (right)--> |
|||
|
|||
<!-- Sidebar Nav--> |
|||
<nav th:replace="fragments/nav :: nav"></nav> |
|||
<!-- END Sidebar --> |
|||
|
|||
<!-- Header --> |
|||
<header th:replace="fragments/header :: header"></header> |
|||
<!-- END Header --> |
|||
|
|||
<!-- Main Container --> |
|||
<main id="main-container"> |
|||
<!-- Hero --> |
|||
<div class=""> |
|||
<div class="content content-full"> |
|||
<div class="d-flex flex-column flex-sm-row justify-content-sm-between align-items-sm-center"> |
|||
<h3 class="flex-grow-1 fs-5 fw-semibold my-2 my-sm-3">Welcome</h3> |
|||
<nav class="flex-shrink-0 my-2 my-sm-0 ms-sm-3" aria-label="breadcrumb"> |
|||
<ol class="breadcrumb"> |
|||
<li class="breadcrumb-item">Home</li> |
|||
<li class="breadcrumb-item active" aria-current="page">Dashboard</li> |
|||
</ol> |
|||
</nav> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END Hero --> |
|||
|
|||
<!-- Page Content --> |
|||
<div class="content"> |
|||
<!-- Overview --> |
|||
<div class="row items-push"> |
|||
<div class="col-sm-6 col-xl-3"> |
|||
<div class="block block-rounded text-center d-flex flex-column h-100 mb-0"> |
|||
<div class="block-content block-content-full flex-grow-1"> |
|||
<div class="item rounded-3 bg-body mx-auto my-3"> |
|||
<i class="fa fa-qrcode fa-lg text-primary"></i> |
|||
</div> |
|||
<div class="fs-2 fw-bold text-success" th:utext="${totalAssets}">000</div> |
|||
<div class="text-muted mb-1 fs-5">Total Asset</div> |
|||
|
|||
</div> |
|||
<div class="block-content block-content-full block-content-sm bg-body-light fs-sm"> |
|||
<a class="fw-medium" href="/gcc-asset-list"> |
|||
View all Assets |
|||
<i class="fa fa-arrow-right ms-1 opacity-25"></i> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-sm-6 col-xl-3"> |
|||
<div class="block block-rounded text-center d-flex flex-column h-100 mb-0"> |
|||
<div class="block-content block-content-full flex-grow-1"> |
|||
<div class="item rounded-3 bg-body mx-auto my-3"> |
|||
<i class="fa fa-comments fa-lg text-primary"></i> |
|||
</div> |
|||
<div class="fs-2 fw-bold text-info" th:utext="${totalFeedbacks}">000</div> |
|||
<div class="text-muted mb-1 fs-5">Total Complaints</div> |
|||
|
|||
</div> |
|||
<div class="block-content block-content-full block-content-sm bg-body-light fs-sm"> |
|||
<a class="fw-medium" href="/complaint-list"> |
|||
View all Complaints |
|||
<i class="fa fa-arrow-right ms-1 opacity-25"></i> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-sm-6 col-xl-3"> |
|||
<div class="block block-rounded text-center d-flex flex-column h-100 mb-0"> |
|||
<div class="block-content block-content-full flex-grow-1"> |
|||
<div class="item rounded-3 bg-body mx-auto my-3"> |
|||
<i class="fa fa-thumbs-up fa-lg text-primary"></i> |
|||
</div> |
|||
<div class="fs-2 fw-bold text-success" th:utext="${totalYesFeedbacks}">000</div> |
|||
<div class="text-muted mb-1 fs-5">Total closed Complaints</div> |
|||
|
|||
</div> |
|||
<div class="block-content block-content-full block-content-sm bg-body-light fs-sm"> |
|||
<a class="fw-medium" href="/closed-complaint"> |
|||
View all Closed Complaints |
|||
<i class="fa fa-arrow-right ms-1 opacity-25"></i> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-sm-6 col-xl-3"> |
|||
<div class="block block-rounded text-center d-flex flex-column h-100 mb-0"> |
|||
<div class="block-content block-content-full"> |
|||
<div class="item rounded-3 bg-body mx-auto my-3"> |
|||
<i class="fa fa-thumbs-down fa-lg text-primary"></i> |
|||
</div> |
|||
<div class="fs-2 fw-bold text-warning" th:utext="${totalNoFeedbacks}">000</div> |
|||
<div class="text-muted mb-1 fs-5">Total Pending Complaints</div> |
|||
|
|||
</div> |
|||
<div class="block-content block-content-full block-content-sm bg-body-light fs-sm"> |
|||
<a class="fw-medium" href="/pending-complaint"> |
|||
View all Pending Complaint |
|||
<i class="fa fa-arrow-right ms-1 opacity-25"></i> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END Overview --> |
|||
|
|||
<!-- Store Growth --> |
|||
<div class="block block-rounded"> |
|||
<div class="block-header block-header-default"> |
|||
<h3 class="block-title"> |
|||
Monthly Summary |
|||
</h3> |
|||
<div class="block-options"> |
|||
<button type="button" class="btn-block-option" data-toggle="block-option" data-action="state_toggle" data-action-mode="demo"> |
|||
<i class="si si-refresh"></i> |
|||
</button> |
|||
<button type="button" class="btn-block-option"> |
|||
<i class="si si-wrench"></i> |
|||
</button> |
|||
<button type="button" class="btn-block-option" id="reportrange"> |
|||
<span></span> |
|||
</button> |
|||
|
|||
</div> |
|||
</div> |
|||
<div class="block-content block-content-full"> |
|||
<div class="row"> |
|||
<div class="col-md-5 col-xl-4 d-md-flex align-items-md-center"> |
|||
<div class="p-md-2 p-lg-3"> |
|||
<div class="py-3"> |
|||
<div class="fs-1 fw-bold" th:utext="${totalFeedbacks}">000</div> |
|||
<div class="fw-semibold text-info">Total Complaints</div> |
|||
|
|||
</div> |
|||
<div class="py-3"> |
|||
<div class="fs-1 fw-bold" th:utext="${totalYesFeedbacks}">000</div> |
|||
<div class="fw-semibold text-success">Closed Complaints</div> |
|||
|
|||
</div> |
|||
<div class="py-3"> |
|||
<div class="fs-1 fw-bold" th:utext="${totalNoFeedbacks}">000</div> |
|||
<div class="fw-semibold text-warning">Pending Complaints</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-md-7 col-xl-8 d-md-flex align-items-md-center"> |
|||
<div class="p-md-2 p-lg-3 w-100" style="height: 450px;"> |
|||
<!-- Bars Chart Container --> |
|||
<!-- Chart.js Chart is initialized in js/pages/be_pages_dashboard.min.js which was auto compiled from _js/pages/be_pages_dashboard.js --> |
|||
<!-- For more info and examples you can check out http://www.chartjs.org/docs/ --> |
|||
<canvas id="js-chartjs-analytics-bars"></canvas> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END Store Growth --> |
|||
|
|||
<!-- Latest Orders + Stats --> |
|||
|
|||
<!-- END Latest Orders + Stats --> |
|||
</div> |
|||
<!-- END Page Content --> |
|||
</main> |
|||
<!-- END Main Container --> |
|||
|
|||
<!-- Footer --> |
|||
<footer th:replace="fragments/footer :: footer"></footer> |
|||
<!-- END Footer --> |
|||
</div> |
|||
<!-- END Page Container --> |
|||
|
|||
<!-- Scripts --> |
|||
<script th:replace="fragments/script :: script"></script> |
|||
<!-- Page JS Plugins --> |
|||
<script src="assets/js/plugins/chart.js/chart.umd.js"></script> |
|||
<!-- Include Date Range Picker --> |
|||
<script type="text/javascript" src="assets/js/plugins/bootstrap-daterangepicker/daterangepicker.js"></script> |
|||
<link rel="stylesheet" type="text/css" href="assets/js/plugins/bootstrap-daterangepicker/daterangepicker.css" /> |
|||
<script> |
|||
var dash; |
|||
function convert(){ |
|||
dash=/*[[${dashboard}]]*/{}; |
|||
} |
|||
convert(); |
|||
alert("hi board"); |
|||
console.log(dash); |
|||
// Chart.js Charts, for more examples you can check out http://www.chartjs.org/docs |
|||
class pageDashboard { |
|||
/* |
|||
* Init Charts |
|||
* |
|||
*/ |
|||
static initChartsBars() { |
|||
// Set Global Chart.js configuration |
|||
Chart.defaults.color = '#818d96'; |
|||
Chart.defaults.scale.grid.color = 'transparent'; |
|||
Chart.defaults.scale.grid.zeroLineColor = 'transparent'; |
|||
Chart.defaults.scale.beginAtZero = true; |
|||
Chart.defaults.elements.line.borderWidth = 1; |
|||
Chart.defaults.plugins.legend.labels.boxWidth = 12; |
|||
|
|||
// Get Chart Containers |
|||
let chartBarsCon = document.getElementById('js-chartjs-analytics-bars'); |
|||
|
|||
// Set Chart and Chart Data variables |
|||
let chartBars, chartLinesBarsData; |
|||
|
|||
// Bars Chart Data |
|||
chartLinesBarsData = { |
|||
//labels: ['MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT', 'SUN'], |
|||
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], |
|||
|
|||
datasets: [ |
|||
{ |
|||
label: 'Total Complaints', |
|||
fill: true, |
|||
backgroundColor: '#c7d7e6', |
|||
borderColor: 'transparent', |
|||
pointBackgroundColor: '#c7d7e6', |
|||
pointBorderColor: '#fff', |
|||
pointHoverBackgroundColor: '#fff', |
|||
pointHoverBorderColor: '#c7d7e6', |
|||
data: [0, 0, 0, 1, 0, 0, 2] |
|||
}, |
|||
{ |
|||
label: 'Closed Complaint', |
|||
fill: true, |
|||
backgroundColor: '#c2d7ab', |
|||
borderColor: 'transparent', |
|||
pointBackgroundColor: '#c2d7ab', |
|||
pointBorderColor: '#fff', |
|||
pointHoverBackgroundColor: '#fff', |
|||
pointHoverBorderColor: '#c2d7ab', |
|||
data: [0, 0, 0, 1, 0, 0, 0] |
|||
}, |
|||
{ |
|||
label: 'Pending Complaint', |
|||
fill: true, |
|||
backgroundColor: '#e9cb91', |
|||
borderColor: 'transparent', |
|||
pointBackgroundColor: '#e9cb91', |
|||
pointBorderColor: '#fff', |
|||
pointHoverBackgroundColor: '#fff', |
|||
pointHoverBorderColor: '#e9cb91', |
|||
data: [0, 0, 0, 0, 0, 0, 2] |
|||
} |
|||
] |
|||
}; |
|||
|
|||
// Init Chart |
|||
if (chartBarsCon !== null) { |
|||
chartBars = new Chart(chartBarsCon, { |
|||
type: 'bar', |
|||
data: chartLinesBarsData, |
|||
options: { |
|||
responsive: true, |
|||
maintainAspectRatio: false, |
|||
plugins: { |
|||
tooltip: { |
|||
callbacks: { |
|||
label: function (context) { |
|||
return context.dataset.label + ': ' + context.parsed.y + ''; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
|
|||
/* |
|||
* Init functionality |
|||
* |
|||
*/ |
|||
static init() { |
|||
this.initChartsBars(); |
|||
} |
|||
} |
|||
|
|||
// Initialize when page loads |
|||
Dashmix.onLoad(() => pageDashboard.init()); |
|||
|
|||
</script> |
|||
|
|||
<script type="text/javascript"> |
|||
$(function() { |
|||
|
|||
var start = moment().subtract(29, 'days'); |
|||
var end = moment(); |
|||
|
|||
function cb(start, end) { |
|||
$('#reportrange span').html(start.format('MMMM D, YYYY') + ' - ' + end.format('MMMM D, YYYY')); |
|||
} |
|||
|
|||
$('#reportrange').daterangepicker({ |
|||
startDate: start, |
|||
endDate: end, |
|||
ranges: { |
|||
'Today': [moment(), moment()], |
|||
'Yesterday': [moment().subtract(1, 'days'), moment().subtract(1, 'days')], |
|||
'Last 7 Days': [moment().subtract(6, 'days'), moment()], |
|||
'Last 30 Days': [moment().subtract(29, 'days'), moment()], |
|||
'This Month': [moment().startOf('month'), moment().endOf('month')], |
|||
'Last Month': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')] |
|||
} |
|||
}, cb); |
|||
|
|||
cb(start, end); |
|||
|
|||
}); |
|||
</script> |
|||
|
|||
<script type="text/javascript"> |
|||
//Chart Update data |
|||
/* static updateChartLinesBarsData(newData) { |
|||
// Update the chart data; |
|||
pageDashboard.chartLinesBarsData.datasets[0].data = newData.totalFeedbacks; |
|||
pageDashboard.chartLinesBarsData.datasets[1].data = newData.positiveFeedbacks; |
|||
pageDashboard.chartLinesBarsData.datasets[2].data = newData.negativeFeedbacks; |
|||
|
|||
// Update the chart |
|||
if (pageDashboard.chartBars !== undefined) { |
|||
pageDashboard.chartBars.data = pageDashboard.chartLinesBarsData; |
|||
pageDashboard.chartBars.update(); |
|||
} |
|||
} |
|||
|
|||
function getAndpushdata(){ |
|||
$.ajax({ |
|||
url: 'api/dashboard', // Replace with the URL to fetch the updated data |
|||
method: 'GET', // Replace with the appropriate HTTP method |
|||
dataType: 'json', // Replace with the data type you are expecting |
|||
success: function (response) { |
|||
// Assuming the response contains the updated chart data in the expected format |
|||
pageDashboard.updateChartLinesBarsData(response); |
|||
}, |
|||
error: function (xhr, status, error) { |
|||
// Handle the error scenario |
|||
console.error('Error:', error); |
|||
} |
|||
}); |
|||
} */ |
|||
|
|||
|
|||
// Assuming pageDashboard is an object or class instance |
|||
var pageDashboard = { |
|||
chartLinesBarsData: { |
|||
datasets: [ |
|||
{ data: [] }, // Assuming totalFeedbacks is an array |
|||
{ data: [] }, // Assuming positiveFeedbacks is an array |
|||
{ data: [] } // Assuming negativeFeedbacks is an array |
|||
] |
|||
}, |
|||
chartBars: undefined, // Assuming chartBars is initially undefined |
|||
|
|||
updateChartLinesBarsData: function(newData) { |
|||
// Update the chart data |
|||
this.chartLinesBarsData.datasets[0].data = newData.totalFeedbacks; |
|||
this.chartLinesBarsData.datasets[1].data = newData.positiveFeedbacks; |
|||
this.chartLinesBarsData.datasets[2].data = newData.negativeFeedbacks; |
|||
|
|||
// Update the chart |
|||
if (this.chartBars !== undefined) { |
|||
this.chartBars.data = this.chartLinesBarsData; |
|||
this.chartBars.update(); |
|||
} |
|||
}, |
|||
|
|||
getAndPushData: function() { |
|||
var self = this; // Store a reference to the current object |
|||
|
|||
$.ajax({ |
|||
url: 'api/dashboard', // Replace with the URL to fetch the updated data |
|||
method: 'GET', // Replace with the appropriate HTTP method |
|||
dataType: 'json', // Replace with the data type you are expecting |
|||
success: function(response) { |
|||
// Assuming the response contains the updated chart data in the expected format |
|||
self.updateChartLinesBarsData(response); |
|||
}, |
|||
error: function(xhr, status, error) { |
|||
// Handle the error scenario |
|||
console.error('Error:', error); |
|||
} |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
// Call the getAndPushData method to fetch and update chart data |
|||
pageDashboard.getAndPushData(); |
|||
|
|||
|
|||
|
|||
|
|||
</script> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,455 @@ |
|||
<!doctype html> |
|||
<html xmlns:th="http://www.thymeleaf.org"> |
|||
<head th:replace="fragments/head :: head"></head> |
|||
|
|||
<body> |
|||
<!-- Page Container --> |
|||
<div id="page-container" class="sidebar-o sidebar-dark enable-page-overlay side-scroll page-header-fixed page-header-dark"> |
|||
<!-- Side Overlay aside (right)--> |
|||
<aside th:replace="fragments/aside-right :: aside"></aside> |
|||
<!-- END Side Overlay (right)--> |
|||
|
|||
<!-- Sidebar Nav--> |
|||
<nav th:replace="fragments/nav :: nav"></nav> |
|||
<!-- END Sidebar --> |
|||
|
|||
<!-- Header --> |
|||
<header th:replace="fragments/header :: header"></header> |
|||
<!-- END Header --> |
|||
|
|||
<!-- Main Container --> |
|||
<main id="main-container"> |
|||
<!-- Hero --> |
|||
<div class=""> |
|||
<div class="content content-full"> |
|||
<div class="d-flex flex-column flex-sm-row justify-content-sm-between align-items-sm-center"> |
|||
<h3 class="flex-grow-1 fs-5 fw-semibold my-2 my-sm-3">Welcome</h3> |
|||
<nav class="flex-shrink-0 my-2 my-sm-0 ms-sm-3" aria-label="breadcrumb"> |
|||
<ol class="breadcrumb"> |
|||
<li class="breadcrumb-item">Home</li> |
|||
<li class="breadcrumb-item active" aria-current="page">Dashboard</li> |
|||
</ol> |
|||
</nav> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END Hero --> |
|||
|
|||
<!-- Page Content --> |
|||
<div class="content"> |
|||
<!-- Overview --> |
|||
<div class="row items-push"> |
|||
<div class="col-sm-6 col-xl-3"> |
|||
<div class="block block-rounded text-center d-flex flex-column h-100 mb-0"> |
|||
<div class="block-content block-content-full flex-grow-1"> |
|||
<div class="item rounded-3 bg-body mx-auto my-3"> |
|||
<i class="fa fa-qrcode fa-lg text-primary"></i> |
|||
</div> |
|||
<div class="fs-2 fw-bold text-success" th:utext="${totalAssets}">000</div> |
|||
<div class="text-muted mb-1 fs-5">Total Asset</div> |
|||
|
|||
</div> |
|||
<div class="block-content block-content-full block-content-sm bg-body-light fs-sm"> |
|||
<a class="fw-medium" href="/gcc-asset-list"> |
|||
View all Assets |
|||
<i class="fa fa-arrow-right ms-1 opacity-25"></i> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-sm-6 col-xl-3"> |
|||
<div class="block block-rounded text-center d-flex flex-column h-100 mb-0"> |
|||
<div class="block-content block-content-full flex-grow-1"> |
|||
<div class="item rounded-3 bg-body mx-auto my-3"> |
|||
<i class="fa fa-comments fa-lg text-primary"></i> |
|||
</div> |
|||
<div class="fs-2 fw-bold text-info" th:utext="${totalFeedbacks}">000</div> |
|||
<div class="text-muted mb-1 fs-5">Total Complaints</div> |
|||
|
|||
</div> |
|||
<div class="block-content block-content-full block-content-sm bg-body-light fs-sm"> |
|||
<a class="fw-medium" href="/complaint-list"> |
|||
View all Complaints |
|||
<i class="fa fa-arrow-right ms-1 opacity-25"></i> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-sm-6 col-xl-3"> |
|||
<div class="block block-rounded text-center d-flex flex-column h-100 mb-0"> |
|||
<div class="block-content block-content-full flex-grow-1"> |
|||
<div class="item rounded-3 bg-body mx-auto my-3"> |
|||
<i class="fa fa-thumbs-up fa-lg text-primary"></i> |
|||
</div> |
|||
<div class="fs-2 fw-bold text-success" th:utext="${totalYesFeedbacks}">000</div> |
|||
<div class="text-muted mb-1 fs-5">Total closed Complaints</div> |
|||
|
|||
</div> |
|||
<div class="block-content block-content-full block-content-sm bg-body-light fs-sm"> |
|||
<a class="fw-medium" href="/closed-complaint"> |
|||
View all Closed Complaints |
|||
<i class="fa fa-arrow-right ms-1 opacity-25"></i> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-sm-6 col-xl-3"> |
|||
<div class="block block-rounded text-center d-flex flex-column h-100 mb-0"> |
|||
<div class="block-content block-content-full"> |
|||
<div class="item rounded-3 bg-body mx-auto my-3"> |
|||
<i class="fa fa-thumbs-down fa-lg text-primary"></i> |
|||
</div> |
|||
<div class="fs-2 fw-bold text-warning" th:utext="${totalNoFeedbacks}">000</div> |
|||
<div class="text-muted mb-1 fs-5">Total Pending Complaints</div> |
|||
|
|||
</div> |
|||
<div class="block-content block-content-full block-content-sm bg-body-light fs-sm"> |
|||
<a class="fw-medium" href="/pending-complaint"> |
|||
View all Pending Complaint |
|||
<i class="fa fa-arrow-right ms-1 opacity-25"></i> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END Overview --> |
|||
|
|||
<!-- Store Growth --> |
|||
|
|||
<div class="row"> |
|||
<div class="col-12 col-md-6 col-xl-6"> |
|||
<div class="p-md-2 p-lg-3 w-100" style="height: 400px;"> |
|||
<!-- Chart 1 Container --> |
|||
<canvas id="myChart1"></canvas> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="col-12 col-md-6 col-xl-6"> |
|||
<div class="p-md-2 p-lg-3 w-100" style="height: 500px;"> |
|||
<!-- Chart 2 Container --> |
|||
<canvas id="myChart"></canvas> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
</div> |
|||
|
|||
|
|||
|
|||
<!-- END Store Growth --> |
|||
|
|||
<!-- Latest Orders + Stats --> |
|||
|
|||
<!-- END Latest Orders + Stats --> |
|||
|
|||
<!-- END Page Content --> |
|||
</main> |
|||
<!-- END Main Container --> |
|||
|
|||
<!-- Footer --> |
|||
<footer th:replace="fragments/footer :: footer"></footer> |
|||
<!-- END Footer --> |
|||
</div> |
|||
<!-- END Page Container --> |
|||
|
|||
<!-- Scripts --> |
|||
<!-- Include jQuery --> |
|||
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script> |
|||
<!-- Your existing script tag follows --> |
|||
<script th:replace="fragments/script :: script"></script> |
|||
<!-- Page JS Plugins --> |
|||
<script src="assets/js/plugins/chart.js/chart.umd.js"></script> |
|||
<!-- Include Date Range Picker --> |
|||
<script type="text/javascript" src="assets/js/plugins/bootstrap-daterangepicker/daterangepicker.js"></script> |
|||
<link rel="stylesheet" type="text/css" href="assets/js/plugins/bootstrap-daterangepicker/daterangepicker.css" /> |
|||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> |
|||
|
|||
<script> |
|||
var dash = {}; |
|||
|
|||
function convert() { |
|||
// Ensure proper initialization logic for feedbackAnalysisData |
|||
dash.feedbackAnalysisData = /*[[${dashboard}]]*/ {}; |
|||
} |
|||
|
|||
convert(); |
|||
|
|||
|
|||
var pageDashboard = { |
|||
chartBars: undefined, |
|||
chartLinesBarsData: { |
|||
datasets: [ |
|||
{ data: [] }, // Assuming totalYesFeedbacks is an array |
|||
{ data: [] }, |
|||
{data:[] } // Assuming totalNoFeedbacks is an array |
|||
] |
|||
}, |
|||
|
|||
initChart: function (feedbackAnalysis) { |
|||
// Set Global Chart.js configuration |
|||
Chart.defaults.color = '#818d96'; |
|||
Chart.defaults.scale.grid.color = 'transparent'; |
|||
Chart.defaults.scale.grid.zeroLineColor = 'transparent'; |
|||
Chart.defaults.scale.beginAtZero = true; |
|||
Chart.defaults.elements.line.borderWidth = 1; |
|||
Chart.defaults.plugins.legend.labels.boxWidth = 12; |
|||
|
|||
// Get Chart Container |
|||
let chartBarsCon = document.getElementById('myChart'); |
|||
|
|||
var data = { |
|||
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], |
|||
datasets: [ |
|||
{ |
|||
label: 'Total Complaints', |
|||
data: [], |
|||
fill: true, |
|||
backgroundColor: '#3498db', |
|||
borderColor: 'transparent', |
|||
pointBackgroundColor: '#c7d7e6', |
|||
pointBorderColor: '#fff', |
|||
pointHoverBackgroundColor: '#2980b9', |
|||
pointHoverBorderColor: '#c7d7e6', |
|||
}, |
|||
|
|||
] |
|||
}; |
|||
|
|||
|
|||
var options = { |
|||
responsive: true, |
|||
scales: { |
|||
x: { beginAtZero: true }, |
|||
y: { beginAtZero: true } |
|||
}, |
|||
plugins: { |
|||
datalabels: { |
|||
anchor: 'end', |
|||
align: 'end', |
|||
color: 'black', |
|||
formatter: function (value, context) { |
|||
// Display the value only if it's greater than 0 |
|||
return value > 0 ? value : ''; |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
// Create the chart |
|||
this.chartBars = new Chart(chartBarsCon, { |
|||
type: 'bar', |
|||
data: data, |
|||
options: options |
|||
}); |
|||
}, |
|||
updateChartLinesBarsData: function (newData) { |
|||
// Ensure the chart is initialized before updating |
|||
if (this.chartBars) { |
|||
// Assuming labels for the chart are ['Jan', 'Feb', 'Mar', ..., 'Dec'] |
|||
var labels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; |
|||
|
|||
// Initialize arrays with values from dataArray |
|||
var totalFeedbacksData = Array.from({ length: labels.length }, (_, index) => { |
|||
return newData.reduce((sum, item) => { |
|||
const key = Object.keys(item)[0]; |
|||
const dataArray = item[key]; |
|||
// console.log(totalFeedbacksData[${index}]: ${dataArray[index]}); |
|||
return sum + dataArray[index]; |
|||
}, 0); |
|||
}); |
|||
|
|||
var totalYesFeedbacksData = Array.from({ length: labels.length }, (_, index) => { |
|||
return newData.reduce((sum, item) => { |
|||
const key = Object.keys(item)[0]; |
|||
const dataArray = item[key]; |
|||
// console.log(totalYesFeedbacksData[${index}]: ${dataArray[index]}); |
|||
return dataArray[index]; |
|||
}, 0); |
|||
}); |
|||
|
|||
// Subtract totalYesFeedbacksData from totalFeedbacksData |
|||
var totalNoFeedbacksData = totalFeedbacksData.map((value, index) => value - totalYesFeedbacksData[index]); |
|||
|
|||
// Update the chart data |
|||
this.chartBars.data.datasets[0].data = totalFeedbacksData; |
|||
// this.chartBars.data.datasets[1].data = totalYesFeedbacksData; |
|||
// this.chartBars.data.datasets[2].data = totalNoFeedbacksData; |
|||
|
|||
// Log the updated chart data |
|||
// console.log('Updated chart data (totalFeedbacksData):', this.chartBars.data.datasets[0].data); |
|||
//console.log('Updated chart data (totalYesFeedbacksData):', this.chartBars.data.datasets[1].data); |
|||
//console.log('Updated chart data (totalNoFeedbacksData):', this.chartBars.data.datasets[2].data); |
|||
|
|||
// Update the chart |
|||
this.chartBars.update(); |
|||
} else { |
|||
console.error('Chart is not initialized. Unable to update data.'); |
|||
} |
|||
}, |
|||
|
|||
|
|||
|
|||
getAndPushData: function (cdate) { |
|||
|
|||
// Ensure convert() is called before accessing dash.feedbackAnalysisData |
|||
convert(); |
|||
|
|||
|
|||
var self = this; |
|||
|
|||
$.ajax({ |
|||
url: 'api/cou/' + cdate, |
|||
method: 'GET', |
|||
dataType: 'json', |
|||
success: function (response) { |
|||
console.log('Data fetched successfully:', response); |
|||
self.updateChartLinesBarsData(response); |
|||
}, |
|||
error: function (xhr, status, error) { |
|||
console.error('Error:', error); |
|||
} |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
// Call the initChart function with the feedbackAnalysis data |
|||
pageDashboard.initChart(dash.feedbackAnalysisData || {}); |
|||
|
|||
// Call the getAndPushData method to fetch and update chart data |
|||
pageDashboard.getAndPushData(); |
|||
pageDashboard.getAndPushData(); |
|||
var pageDashboard = { |
|||
chartPie: undefined, |
|||
chartPieData: { |
|||
labels: ['Total Complaints', 'Closed Complaint', 'Pending Complaint'], |
|||
datasets: [ |
|||
{ |
|||
data: [], |
|||
backgroundColor: ['#3498db', '#e74c3c', '#cc6633'], |
|||
hoverBackgroundColor: ['#2980b9', '#c0392b', '#A35128'] |
|||
} |
|||
] |
|||
}, |
|||
|
|||
initChart: function () { |
|||
// Get Chart Container |
|||
let chartPieCon = document.getElementById('myChart1'); |
|||
|
|||
var options = { |
|||
responsive: true, |
|||
plugins: { |
|||
datalabels: { |
|||
color: 'black', |
|||
formatter: function (value) { |
|||
// Display the value only if it's greater than 0 |
|||
return value > 0 ? value : ''; |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
// Create the chart |
|||
this.chartPie = new Chart(chartPieCon, { |
|||
type: 'pie', |
|||
data: this.chartPieData, |
|||
options: options |
|||
}); |
|||
|
|||
// Add click event listener to the chart container |
|||
chartPieCon.onclick = function (event) { |
|||
var elements = pageDashboard.chartPie.getElementsAtEventForMode(event, 'point', pageDashboard.chartPie.options); |
|||
|
|||
if (elements && elements.length > 0) { |
|||
var clickedIndex = elements[0].index; |
|||
console.log('Clicked Index:', clickedIndex); |
|||
console.log('Elements:', elements); |
|||
console.log('Labels:', pageDashboard.chartPieData.labels); |
|||
|
|||
// Continue with the rest of your code... |
|||
} else { |
|||
console.error('No elements found at the click event.'); |
|||
} |
|||
if (clickedIndex >= 0 && clickedIndex < pageDashboard.chartPieData.labels.length) { |
|||
var clickedLabel = pageDashboard.chartPieData.labels[clickedIndex]; |
|||
|
|||
// Log the clicked label for debugging |
|||
console.log('Clicked Label:', clickedLabel); |
|||
|
|||
// Navigate based on the clicked label |
|||
switch (clickedLabel) { |
|||
case 'Total Complaints': |
|||
console.log('Navigating to pendingchart.html'); |
|||
window.location.href = 'pendingchart.html'; |
|||
break; |
|||
case 'Pending Complaint': |
|||
console.log('Navigating to nofeedbacks.html'); |
|||
window.location.href = 'closedchart.html'; |
|||
break; |
|||
case 'Closed Complaint': |
|||
console.log('Navigating to yesfeedbacks.html'); |
|||
window.location.href = 'totalchart.html'; |
|||
break; |
|||
// Add more cases for other labels if needed |
|||
default: |
|||
console.log('No action defined for clicked label:', clickedLabel); |
|||
} |
|||
} else { |
|||
console.error('Invalid clicked index:', clickedIndex); |
|||
} |
|||
|
|||
}; |
|||
}, |
|||
|
|||
updateChartPieData: function (data) { |
|||
if (this.chartPie) { |
|||
var totalFeedbacks = data.totalFeedbacks || 0; |
|||
var totalYesFeedbacks = data.totalYesFeedbacks || 0; |
|||
var totalNoFeedbacks = data.totalNoFeedbacks || 0; |
|||
|
|||
// Update the chart data |
|||
this.chartPieData.datasets[0].data = [totalFeedbacks, totalYesFeedbacks, totalNoFeedbacks]; |
|||
|
|||
// Update the chart |
|||
this.chartPie.update(); |
|||
} else { |
|||
console.error('Chart is not initialized. Unable to update data.'); |
|||
} |
|||
}, |
|||
|
|||
getAndPushData: function () { |
|||
// Assume you have a function named 'convert' |
|||
convert(); |
|||
var self = this; |
|||
|
|||
// Fetch data from the actual API |
|||
$.ajax({ |
|||
url: 'http://localhost:8071/api/dashboard-summary', |
|||
method: 'GET', |
|||
dataType: 'json', |
|||
success: function (response) { |
|||
console.log('Data fetched successfully:', response); |
|||
|
|||
// Call the function to process the API response |
|||
self.updateChartPieData(response); |
|||
}, |
|||
error: function (xhr, status, error) { |
|||
console.error('Error:', error); |
|||
} |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
// Call the initChart function |
|||
pageDashboard.initChart(); |
|||
|
|||
// Call the getAndPushData method to fetch and update chart data |
|||
pageDashboard.getAndPushData(); |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
</script> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,62 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<title>Feedback Chart</title> |
|||
<!-- Include Chart.js from CDN --> |
|||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> |
|||
</head> |
|||
<body> |
|||
<canvas id="feedbackChart" width="400" height="400"></canvas> |
|||
|
|||
<script> |
|||
var dash=[[${dashboard}]]; |
|||
console.log(dash); |
|||
// Assume your API endpoint returns a JSON object with the data |
|||
// Modify the URL accordingly based on your server setup |
|||
const apiUrl = 'api/cou/{cdate}'; // Replace with your actual API endpoint |
|||
|
|||
// Fetch data from the API |
|||
fetch(apiUrl) |
|||
.then(response => response.json()) |
|||
.then(data => { |
|||
// Extract data for chart |
|||
const labels = ['Yes', 'No', 'Total']; |
|||
const values = [data.yes, data.no, data.total]; |
|||
|
|||
// Create a Chart.js chart |
|||
const ctx = document.getElementById('feedbackChart').getContext('2d'); |
|||
const myChart = new Chart(ctx, { |
|||
type: 'bar', |
|||
data: { |
|||
labels: labels, |
|||
datasets: [{ |
|||
label: 'Feedback Data', |
|||
data: values, |
|||
backgroundColor: [ |
|||
'rgba(75, 192, 192, 0.2)', |
|||
'rgba(255, 99, 132, 0.2)', |
|||
'rgba(255, 255, 255, 0.2)' |
|||
], |
|||
borderColor: [ |
|||
'rgba(75, 192, 192, 1)', |
|||
'rgba(255, 99, 132, 1)', |
|||
'rgba(255, 255, 255, 1)' |
|||
], |
|||
borderWidth: 1 |
|||
}] |
|||
}, |
|||
options: { |
|||
scales: { |
|||
y: { |
|||
beginAtZero: true |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
}) |
|||
.catch(error => console.error('Error fetching data:', error)); |
|||
</script> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,452 @@ |
|||
<!doctype html> |
|||
<html xmlns:th="http://www.thymeleaf.org"> |
|||
<head th:replace="fragments/head :: head"></head> |
|||
|
|||
<body> |
|||
<!-- Page Container --> |
|||
<div id="page-container" class="sidebar-o sidebar-dark enable-page-overlay side-scroll page-header-fixed page-header-dark"> |
|||
<!-- Side Overlay aside (right)--> |
|||
<aside th:replace="fragments/aside-right :: aside"></aside> |
|||
<!-- END Side Overlay (right)--> |
|||
|
|||
<!-- Sidebar Nav--> |
|||
<nav th:replace="fragments/nav :: nav"></nav> |
|||
<!-- END Sidebar --> |
|||
|
|||
<!-- Header --> |
|||
<header th:replace="fragments/header :: header"></header> |
|||
<!-- END Header --> |
|||
|
|||
<!-- Main Container --> |
|||
<main id="main-container"> |
|||
<!-- Hero --> |
|||
<div class=""> |
|||
<div class="content content-full"> |
|||
<div class="d-flex flex-column flex-sm-row justify-content-sm-between align-items-sm-center"> |
|||
<h3 class="flex-grow-1 fs-5 fw-semibold my-2 my-sm-3">Welcome</h3> |
|||
<nav class="flex-shrink-0 my-2 my-sm-0 ms-sm-3" aria-label="breadcrumb"> |
|||
<ol class="breadcrumb"> |
|||
<li class="breadcrumb-item">Home</li> |
|||
<li class="breadcrumb-item active" aria-current="page">Dashboard</li> |
|||
</ol> |
|||
</nav> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END Hero --> |
|||
|
|||
<!-- Page Content --> |
|||
<div class="content"> |
|||
<!-- Overview --> |
|||
<div class="row items-push"> |
|||
<div class="col-sm-6 col-xl-3"> |
|||
<div class="block block-rounded text-center d-flex flex-column h-100 mb-0"> |
|||
<div class="block-content block-content-full flex-grow-1"> |
|||
<div class="item rounded-3 bg-body mx-auto my-3"> |
|||
<i class="fa fa-qrcode fa-lg text-primary"></i> |
|||
</div> |
|||
<div class="fs-2 fw-bold text-success" th:utext="${totalAssets}">000</div> |
|||
<div class="text-muted mb-1 fs-5">Total Asset</div> |
|||
</div> |
|||
<div class="block-content block-content-full block-content-sm bg-body-light fs-sm"> |
|||
<a class="fw-medium" href="/gcc-asset-list"> |
|||
View all Assets |
|||
<i class="fa fa-arrow-right ms-1 opacity-25"></i> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-sm-6 col-xl-3"> |
|||
<div class="block block-rounded text-center d-flex flex-column h-100 mb-0"> |
|||
<div class="block-content block-content-full flex-grow-1"> |
|||
<div class="item rounded-3 bg-body mx-auto my-3"> |
|||
<i class="fa fa-comments fa-lg text-primary"></i> |
|||
</div> |
|||
<div class="fs-2 fw-bold text-info" th:utext="${totalFeedbacks}">000</div> |
|||
<div class="text-muted mb-1 fs-5">Total Complaints</div> |
|||
|
|||
</div> |
|||
<div class="block-content block-content-full block-content-sm bg-body-light fs-sm"> |
|||
<a class="fw-medium" href="/complaint-list"> |
|||
View all Complaints |
|||
<i class="fa fa-arrow-right ms-1 opacity-25"></i> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-sm-6 col-xl-3"> |
|||
<div class="block block-rounded text-center d-flex flex-column h-100 mb-0"> |
|||
<div class="block-content block-content-full flex-grow-1"> |
|||
<div class="item rounded-3 bg-body mx-auto my-3"> |
|||
<i class="fa fa-thumbs-up fa-lg text-primary"></i> |
|||
</div> |
|||
<div class="fs-2 fw-bold text-success" th:utext="${totalYesFeedbacks}">000</div> |
|||
<div class="text-muted mb-1 fs-5">Total closed Complaints</div> |
|||
|
|||
</div> |
|||
<div class="block-content block-content-full block-content-sm bg-body-light fs-sm"> |
|||
<a class="fw-medium" href="/closed-complaint"> |
|||
View all Closed Complaints |
|||
<i class="fa fa-arrow-right ms-1 opacity-25"></i> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-sm-6 col-xl-3"> |
|||
<div class="block block-rounded text-center d-flex flex-column h-100 mb-0"> |
|||
<div class="block-content block-content-full"> |
|||
<div class="item rounded-3 bg-body mx-auto my-3"> |
|||
<i class="fa fa-thumbs-down fa-lg text-primary"></i> |
|||
</div> |
|||
<div class="fs-2 fw-bold text-warning" th:utext="${totalNoFeedbacks}">000</div> |
|||
<div class="text-muted mb-1 fs-5">Total Pending Complaints</div> |
|||
|
|||
</div> |
|||
<div class="block-content block-content-full block-content-sm bg-body-light fs-sm"> |
|||
<a class="fw-medium" href="/pending-complaint"> |
|||
View all Pending Complaint |
|||
<i class="fa fa-arrow-right ms-1 opacity-25"></i> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END Overview --> |
|||
|
|||
<!-- Store Growth --> |
|||
|
|||
<div class="row"> |
|||
<div class="col-12 col-md-6 col-xl-6"> |
|||
<div class="p-md-2 p-lg-3 w-100" style="height: 400px;"> |
|||
<!-- Chart 1 Container --> |
|||
<canvas id="myChart1"></canvas> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="col-12 col-md-6 col-xl-6"> |
|||
<div class="p-md-2 p-lg-3 w-100" style="height: 500px;"> |
|||
<!-- Chart 2 Container --> |
|||
<canvas id="myChart"></canvas> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
<!-- END Store Growth --> |
|||
|
|||
<!-- Latest Orders + Stats --> |
|||
|
|||
<!-- END Latest Orders + Stats --> |
|||
</div> |
|||
<!-- END Page Content --> |
|||
</main> |
|||
<!-- END Main Container --> |
|||
|
|||
<!-- Footer --> |
|||
<footer th:replace="fragments/footer :: footer"></footer> |
|||
<!-- END Footer --> |
|||
</div> |
|||
<!-- END Page Container --> |
|||
|
|||
<!-- Scripts --> |
|||
<!-- Include jQuery --> |
|||
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script> |
|||
<!-- Your existing script tag follows --> |
|||
<script th:replace="fragments/script :: script"></script> |
|||
<!-- Page JS Plugins --> |
|||
<script src="assets/js/plugins/chart.js/chart.umd.js"></script> |
|||
<!-- Include Date Range Picker --> |
|||
<script type="text/javascript" src="assets/js/plugins/bootstrap-daterangepicker/daterangepicker.js"></script> |
|||
<link rel="stylesheet" type="text/css" href="assets/js/plugins/bootstrap-daterangepicker/daterangepicker.css" /> |
|||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> |
|||
|
|||
<script> |
|||
var dash = {}; |
|||
|
|||
function convert() { |
|||
// Ensure proper initialization logic for feedbackAnalysisData |
|||
dash.feedbackAnalysisData = /*[[${dashboard}]]*/ {}; |
|||
} |
|||
|
|||
convert(); |
|||
|
|||
|
|||
var pageDashboard = { |
|||
chartBars: undefined, |
|||
chartLinesBarsData: { |
|||
datasets: [ |
|||
{ data: [] }, // Assuming totalYesFeedbacks is an array |
|||
{ data: [] }, |
|||
{data:[] } // Assuming totalNoFeedbacks is an array |
|||
] |
|||
}, |
|||
|
|||
initChart: function (feedbackAnalysis) { |
|||
// Set Global Chart.js configuration |
|||
Chart.defaults.color = '#818d96'; |
|||
Chart.defaults.scale.grid.color = 'transparent'; |
|||
Chart.defaults.scale.grid.zeroLineColor = 'transparent'; |
|||
Chart.defaults.scale.beginAtZero = true; |
|||
Chart.defaults.elements.line.borderWidth = 1; |
|||
Chart.defaults.plugins.legend.labels.boxWidth = 12; |
|||
|
|||
// Get Chart Container |
|||
let chartBarsCon = document.getElementById('myChart'); |
|||
|
|||
var data = { |
|||
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], |
|||
datasets: [ |
|||
{ |
|||
label: 'Closed Complaint', |
|||
data: [], |
|||
fill: true, |
|||
backgroundColor: '#cc6633', |
|||
borderColor: 'transparent', |
|||
pointBackgroundColor: '#e9cb91', |
|||
pointBorderColor: '#fff', |
|||
pointHoverBackgroundColor: '#A35128', |
|||
pointHoverBorderColor: '#e9cb91', |
|||
}, |
|||
|
|||
] |
|||
}; |
|||
|
|||
|
|||
var options = { |
|||
responsive: true, |
|||
scales: { |
|||
x: { beginAtZero: true }, |
|||
y: { beginAtZero: true } |
|||
}, |
|||
plugins: { |
|||
datalabels: { |
|||
anchor: 'end', |
|||
align: 'end', |
|||
color: 'black', |
|||
formatter: function (value, context) { |
|||
// Display the value only if it's greater than 0 |
|||
return value > 0 ? value : ''; |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
// Create the chart |
|||
this.chartBars = new Chart(chartBarsCon, { |
|||
type: 'bar', |
|||
data: data, |
|||
options: options |
|||
}); |
|||
}, |
|||
updateChartLinesBarsData: function (newData) { |
|||
// Ensure the chart is initialized before updating |
|||
if (this.chartBars) { |
|||
// Assuming labels for the chart are ['Jan', 'Feb', 'Mar', ..., 'Dec'] |
|||
var labels = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; |
|||
|
|||
// Initialize arrays with values from dataArray |
|||
var totalFeedbacksData = Array.from({ length: labels.length }, (_, index) => { |
|||
return newData.reduce((sum, item) => { |
|||
const key = Object.keys(item)[0]; |
|||
const dataArray = item[key]; |
|||
// console.log(totalFeedbacksData[${index}]: ${dataArray[index]}); |
|||
return sum + dataArray[index]; |
|||
}, 0); |
|||
}); |
|||
|
|||
var totalYesFeedbacksData = Array.from({ length: labels.length }, (_, index) => { |
|||
return newData.reduce((sum, item) => { |
|||
const key = Object.keys(item)[0]; |
|||
const dataArray = item[key]; |
|||
// console.log(totalYesFeedbacksData[${index}]: ${dataArray[index]}); |
|||
return dataArray[index]; |
|||
}, 0); |
|||
}); |
|||
|
|||
// Subtract totalYesFeedbacksData from totalFeedbacksData |
|||
var totalNoFeedbacksData = totalFeedbacksData.map((value, index) => value - totalYesFeedbacksData[index]); |
|||
|
|||
// Update the chart data |
|||
// this.chartBars.data.datasets[0].data = totalFeedbacksData; |
|||
// this.chartBars.data.datasets[0].data = totalYesFeedbacksData; |
|||
this.chartBars.data.datasets[0].data = totalNoFeedbacksData; |
|||
|
|||
// Log the updated chart data |
|||
// console.log('Updated chart data (totalFeedbacksData):', this.chartBars.data.datasets[0].data); |
|||
//console.log('Updated chart data (totalYesFeedbacksData):', this.chartBars.data.datasets[1].data); |
|||
//console.log('Updated chart data (totalNoFeedbacksData):', this.chartBars.data.datasets[2].data); |
|||
|
|||
// Update the chart |
|||
this.chartBars.update(); |
|||
} else { |
|||
console.error('Chart is not initialized. Unable to update data.'); |
|||
} |
|||
}, |
|||
|
|||
|
|||
|
|||
getAndPushData: function (cdate) { |
|||
// Ensure convert() is called before accessing dash.feedbackAnalysisData |
|||
convert(); |
|||
|
|||
var self = this; |
|||
|
|||
$.ajax({ |
|||
url: 'api/cou/' + cdate, |
|||
method: 'GET', |
|||
dataType: 'json', |
|||
success: function (response) { |
|||
console.log('Data fetched successfully:', response); |
|||
self.updateChartLinesBarsData(response); |
|||
}, |
|||
error: function (xhr, status, error) { |
|||
console.error('Error:', error); |
|||
} |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
// Call the initChart function with the feedbackAnalysis data |
|||
pageDashboard.initChart(dash.feedbackAnalysisData || {}); |
|||
|
|||
// Call the getAndPushData method to fetch and update chart data |
|||
pageDashboard.getAndPushData(); |
|||
|
|||
pageDashboard.getAndPushData(); |
|||
var pageDashboard = { |
|||
chartPie: undefined, |
|||
chartPieData: { |
|||
labels: ['Total Complaints', 'Closed Complaint', 'Pending Complaint'], |
|||
datasets: [ |
|||
{ |
|||
data: [], |
|||
backgroundColor: ['#3498db', '#e74c3c', '#cc6633'], |
|||
hoverBackgroundColor: ['#2980b9', '#c0392b', '#A35128'] |
|||
} |
|||
] |
|||
}, |
|||
|
|||
initChart: function () { |
|||
// Get Chart Container |
|||
let chartPieCon = document.getElementById('myChart1'); |
|||
|
|||
var options = { |
|||
responsive: true, |
|||
plugins: { |
|||
datalabels: { |
|||
color: 'black', |
|||
formatter: function (value) { |
|||
// Display the value only if it's greater than 0 |
|||
return value > 0 ? value : ''; |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
// Create the chart |
|||
this.chartPie = new Chart(chartPieCon, { |
|||
type: 'pie', |
|||
data: this.chartPieData, |
|||
options: options |
|||
}); |
|||
|
|||
// Add click event listener to the chart container |
|||
chartPieCon.onclick = function (event) { |
|||
var elements = pageDashboard.chartPie.getElementsAtEventForMode(event, 'point', pageDashboard.chartPie.options); |
|||
|
|||
if (elements && elements.length > 0) { |
|||
var clickedIndex = elements[0].index; |
|||
console.log('Clicked Index:', clickedIndex); |
|||
console.log('Elements:', elements); |
|||
console.log('Labels:', pageDashboard.chartPieData.labels); |
|||
|
|||
// Continue with the rest of your code... |
|||
} else { |
|||
console.error('No elements found at the click event.'); |
|||
} |
|||
if (clickedIndex >= 0 && clickedIndex < pageDashboard.chartPieData.labels.length) { |
|||
var clickedLabel = pageDashboard.chartPieData.labels[clickedIndex]; |
|||
|
|||
// Log the clicked label for debugging |
|||
console.log('Clicked Label:', clickedLabel); |
|||
|
|||
// Navigate based on the clicked label |
|||
switch (clickedLabel) { |
|||
case 'Total Complaints': |
|||
console.log('Navigating to pendingchart.html'); |
|||
window.location.href = 'pendingchart.html'; |
|||
break; |
|||
case 'Pending Complaint': |
|||
console.log('Navigating to nofeedbacks.html'); |
|||
window.location.href = 'closedchart.html'; |
|||
break; |
|||
case 'Closed Complaint': |
|||
console.log('Navigating to yesfeedbacks.html'); |
|||
window.location.href = 'totalchart.html'; |
|||
break; |
|||
// Add more cases for other labels if needed |
|||
default: |
|||
console.log('No action defined for clicked label:', clickedLabel); |
|||
} |
|||
} else { |
|||
console.error('Invalid clicked index:', clickedIndex); |
|||
} |
|||
|
|||
}; |
|||
}, |
|||
|
|||
updateChartPieData: function (data) { |
|||
if (this.chartPie) { |
|||
var totalFeedbacks = data.totalFeedbacks || 0; |
|||
var totalYesFeedbacks = data.totalYesFeedbacks || 0; |
|||
var totalNoFeedbacks = data.totalNoFeedbacks || 0; |
|||
|
|||
// Update the chart data |
|||
this.chartPieData.datasets[0].data = [totalFeedbacks, totalYesFeedbacks, totalNoFeedbacks]; |
|||
|
|||
// Update the chart |
|||
this.chartPie.update(); |
|||
} else { |
|||
console.error('Chart is not initialized. Unable to update data.'); |
|||
} |
|||
}, |
|||
|
|||
getAndPushData: function () { |
|||
// Assume you have a function named 'convert' |
|||
convert(); |
|||
var self = this; |
|||
|
|||
// Fetch data from the actual API |
|||
$.ajax({ |
|||
url: 'http://localhost:8071/api/dashboard-summary', |
|||
method: 'GET', |
|||
dataType: 'json', |
|||
success: function (response) { |
|||
console.log('Data fetched successfully:', response); |
|||
|
|||
// Call the function to process the API response |
|||
self.updateChartPieData(response); |
|||
}, |
|||
error: function (xhr, status, error) { |
|||
console.error('Error:', error); |
|||
} |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
// Call the initChart function |
|||
pageDashboard.initChart(); |
|||
|
|||
// Call the getAndPushData method to fetch and update chart data |
|||
pageDashboard.getAndPushData(); |
|||
|
|||
|
|||
|
|||
|
|||
</script> |
|||
</body> |
|||
</html> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue