82 changed files with 3513 additions and 7550 deletions
-
6pom.xml
-
6src/main/java/com/gcc/flagpoles_services/FlagpolesApplication.java
-
12src/main/java/com/gcc/flagpoles_services/configuration/AppConfig.java
-
23src/main/java/com/gcc/flagpoles_services/configuration/DataSourceConfig.java
-
2src/main/java/com/gcc/flagpoles_services/configuration/JacksonConfiguration.java
-
25src/main/java/com/gcc/flagpoles_services/configuration/SecurityConfig.java
-
2src/main/java/com/gcc/flagpoles_services/configuration/ThymeleafConfig.java
-
16src/main/java/com/gcc/flagpoles_services/configuration/WebMvcConfig.java
-
42src/main/java/com/gcc/flagpoles_services/controller/APIController.java
-
30src/main/java/com/gcc/flagpoles_services/controller/AdminController.java
-
4src/main/java/com/gcc/flagpoles_services/controller/CustomErrorController.java
-
2src/main/java/com/gcc/flagpoles_services/controller/DateTimeUtil.java
-
6src/main/java/com/gcc/flagpoles_services/controller/FileController.java
-
6src/main/java/com/gcc/flagpoles_services/controller/MainController.java
-
36src/main/java/com/gcc/flagpoles_services/controller/MenuController.java
-
6src/main/java/com/gcc/flagpoles_services/controller/login.java
-
2src/main/java/com/gcc/flagpoles_services/entity/AppModuleAccessEntity.java
-
2src/main/java/com/gcc/flagpoles_services/entity/AppModuleEntity.java
-
2src/main/java/com/gcc/flagpoles_services/entity/AppUserEntity.java
-
2src/main/java/com/gcc/flagpoles_services/entity/AppUserGroupEntity.java
-
2src/main/java/com/gcc/flagpoles_services/entity/MenuItemAccessEntity.java
-
2src/main/java/com/gcc/flagpoles_services/entity/MenuItemEntity.java
-
2src/main/java/com/gcc/flagpoles_services/entity/SubMenuItemAccessEntity.java
-
2src/main/java/com/gcc/flagpoles_services/entity/SubMenuItemEntity.java
-
2src/main/java/com/gcc/flagpoles_services/entity/UserActivityLog.java
-
2src/main/java/com/gcc/flagpoles_services/entity/UserInfoEntity.java
-
425src/main/java/com/gcc/flagpoles_services/flagpoles/controller/FlagPoleApiController.java
-
53src/main/java/com/gcc/flagpoles_services/flagpoles/controller/MainController.java
-
248src/main/java/com/gcc/flagpoles_services/flagpoles/service/FlagpoleSMSService.java
-
1356src/main/java/com/gcc/flagpoles_services/flagpoles/service/RdoService.java
-
41src/main/java/com/gcc/flagpoles_services/flagpoles/util/MessageUtility.java
-
36src/main/java/com/gcc/flagpoles_services/interceptor/AppInterceptor.java
-
2src/main/java/com/gcc/flagpoles_services/modeldata/ErrorResponse.java
-
4src/main/java/com/gcc/flagpoles_services/repository/AppModuleAccessRepository.java
-
4src/main/java/com/gcc/flagpoles_services/repository/AppModuleRepository.java
-
4src/main/java/com/gcc/flagpoles_services/repository/AppUserGroupRepository.java
-
4src/main/java/com/gcc/flagpoles_services/repository/AppUserRepository.java
-
4src/main/java/com/gcc/flagpoles_services/repository/MenuItemAccessRepository.java
-
4src/main/java/com/gcc/flagpoles_services/repository/MenuItemRepository.java
-
4src/main/java/com/gcc/flagpoles_services/repository/SubMenuItemAccessRepository.java
-
4src/main/java/com/gcc/flagpoles_services/repository/SubMenuItemRepository.java
-
4src/main/java/com/gcc/flagpoles_services/repository/UserActivityLogRepository.java
-
2src/main/java/com/gcc/flagpoles_services/repository/UserInfoRepository.java
-
2src/main/java/com/gcc/flagpoles_services/service/Base64Util.java
-
2src/main/java/com/gcc/flagpoles_services/service/CustomUserDetails.java
-
6src/main/java/com/gcc/flagpoles_services/service/CustomUserDetailsService.java
-
2src/main/java/com/gcc/flagpoles_services/service/LoginUserInfo.java
-
6src/main/java/com/gcc/flagpoles_services/service/UserActivityService.java
-
6src/main/java/com/gcc/flagpoles_services/service/UserActivityTimelineService.java
-
163src/main/java/com/gcc/swm_services/swm/controller/AdminController.java
-
35src/main/java/com/gcc/swm_services/swm/controller/DropDownApiController.java
-
71src/main/java/com/gcc/swm_services/swm/controller/MainController.java
-
145src/main/java/com/gcc/swm_services/swm/controller/SwmAdminApiController.java
-
202src/main/java/com/gcc/swm_services/swm/controller/SwmApiController.java
-
510src/main/java/com/gcc/swm_services/swm/service/AddDetailsService.java
-
37src/main/java/com/gcc/swm_services/swm/service/DropDownService.java
-
2src/main/resources/application-dev.properties
-
4src/main/resources/application-prod.properties
-
4src/main/resources/application.properties
-
98src/main/resources/templates/error-403.html
-
2src/main/resources/templates/fragments/modules/base/footer.html
-
2src/main/resources/templates/fragments/modules/base/head.html
-
4src/main/resources/templates/fragments/modules/base/header.html
-
2src/main/resources/templates/fragments/modules/base/login-head.html
-
2src/main/resources/templates/fragments/modules/base/script.html
-
6src/main/resources/templates/index.html
-
6src/main/resources/templates/login.html
-
4src/main/resources/templates/modules/admin/user-group-access.html
-
2src/main/resources/templates/modules/admin/user-list.html
-
480src/main/resources/templates/modules/flagpole/approvedandrejectedlist.html
-
930src/main/resources/templates/modules/flagpole/requestlist.html
-
754src/main/resources/templates/modules/swm/biogas.html
-
416src/main/resources/templates/modules/swm/cdwaste.html
-
764src/main/resources/templates/modules/swm/eachreport.html
-
447src/main/resources/templates/modules/swm/gwtcwaste.html
-
421src/main/resources/templates/modules/swm/incinerator.html
-
428src/main/resources/templates/modules/swm/mcc.html
-
424src/main/resources/templates/modules/swm/mrf.html
-
418src/main/resources/templates/modules/swm/plastingbaling.html
-
944src/main/resources/templates/modules/swm/reports.html
-
442src/main/resources/templates/modules/swm/requestlist.html
-
419src/main/resources/templates/modules/swm/windrow.html
@ -1,13 +1,13 @@ |
|||
package com.gcc.swm_services; |
|||
package com.gcc.flagpoles_services; |
|||
|
|||
import org.springframework.boot.SpringApplication; |
|||
import org.springframework.boot.autoconfigure.SpringBootApplication; |
|||
|
|||
@SpringBootApplication |
|||
public class SwmApplication { |
|||
public class FlagpolesApplication { |
|||
|
|||
public static void main(String[] args) { |
|||
SpringApplication.run(SwmApplication.class, args); |
|||
SpringApplication.run(FlagpolesApplication.class, args); |
|||
} |
|||
|
|||
} |
|||
@ -1,4 +1,4 @@ |
|||
package com.gcc.swm_services.configuration; |
|||
package com.gcc.flagpoles_services.configuration; |
|||
|
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
@ -1,4 +1,4 @@ |
|||
package com.gcc.swm_services.configuration; |
|||
package com.gcc.flagpoles_services.configuration; |
|||
|
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
@ -1,4 +1,4 @@ |
|||
package com.gcc.swm_services.controller; |
|||
package com.gcc.flagpoles_services.controller; |
|||
|
|||
import org.springframework.stereotype.Service; |
|||
import java.time.LocalDateTime; |
|||
@ -1,12 +1,12 @@ |
|||
package com.gcc.swm_services.controller; |
|||
package com.gcc.flagpoles_services.controller; |
|||
|
|||
import org.springframework.stereotype.Controller; |
|||
import org.springframework.ui.Model; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
|
|||
@RequestMapping("/swm") |
|||
@Controller("swmLoginController") |
|||
@RequestMapping("/flagpoles") |
|||
@Controller("flagpolesLoginController") |
|||
public class login { |
|||
|
|||
@GetMapping("/login") |
|||
@ -1,4 +1,4 @@ |
|||
package com.gcc.swm_services.entity; |
|||
package com.gcc.flagpoles_services.entity; |
|||
|
|||
import javax.persistence.Column; |
|||
import javax.persistence.Entity; |
|||
@ -1,4 +1,4 @@ |
|||
package com.gcc.swm_services.entity; |
|||
package com.gcc.flagpoles_services.entity; |
|||
|
|||
import javax.persistence.Column; |
|||
import javax.persistence.Entity; |
|||
@ -1,4 +1,4 @@ |
|||
package com.gcc.swm_services.entity; |
|||
package com.gcc.flagpoles_services.entity; |
|||
|
|||
import javax.persistence.Column; |
|||
import javax.persistence.Entity; |
|||
@ -1,4 +1,4 @@ |
|||
package com.gcc.swm_services.entity; |
|||
package com.gcc.flagpoles_services.entity; |
|||
|
|||
import javax.persistence.Column; |
|||
import javax.persistence.Entity; |
|||
@ -1,4 +1,4 @@ |
|||
package com.gcc.swm_services.entity; |
|||
package com.gcc.flagpoles_services.entity; |
|||
|
|||
import javax.persistence.Column; |
|||
import javax.persistence.Entity; |
|||
@ -1,4 +1,4 @@ |
|||
package com.gcc.swm_services.entity; |
|||
package com.gcc.flagpoles_services.entity; |
|||
|
|||
import javax.persistence.Column; |
|||
import javax.persistence.Entity; |
|||
@ -1,4 +1,4 @@ |
|||
package com.gcc.swm_services.entity; |
|||
package com.gcc.flagpoles_services.entity; |
|||
|
|||
import javax.persistence.Column; |
|||
import javax.persistence.Entity; |
|||
@ -1,4 +1,4 @@ |
|||
package com.gcc.swm_services.entity; |
|||
package com.gcc.flagpoles_services.entity; |
|||
|
|||
import javax.persistence.Column; |
|||
import javax.persistence.Entity; |
|||
@ -1,4 +1,4 @@ |
|||
package com.gcc.swm_services.entity; |
|||
package com.gcc.flagpoles_services.entity; |
|||
|
|||
import java.time.LocalDateTime; |
|||
import javax.persistence.Entity; |
|||
@ -1,4 +1,4 @@ |
|||
package com.gcc.swm_services.entity; |
|||
package com.gcc.flagpoles_services.entity; |
|||
|
|||
import javax.persistence.Column; |
|||
import javax.persistence.Entity; |
|||
@ -0,0 +1,425 @@ |
|||
package com.gcc.flagpoles_services.flagpoles.controller; |
|||
|
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.http.ResponseEntity; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.PostMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestParam; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
import org.springframework.web.client.RestTemplate; |
|||
|
|||
import com.gcc.flagpoles_services.configuration.AppConfig; |
|||
import com.gcc.flagpoles_services.flagpoles.service.FlagpoleSMSService; |
|||
import com.gcc.flagpoles_services.flagpoles.service.RdoService; |
|||
|
|||
@RestController |
|||
@RequestMapping("/flagpoles/api/flagpoleregistration") |
|||
public class FlagPoleApiController { |
|||
|
|||
@Autowired |
|||
private RdoService rdoService; |
|||
|
|||
@Autowired |
|||
private FlagpoleSMSService flagpoleSMSService; |
|||
|
|||
private final RestTemplate restTemplate; |
|||
private final AppConfig appConfig; |
|||
|
|||
@Autowired |
|||
public FlagPoleApiController(RestTemplate restTemplate, AppConfig appConfig) { |
|||
this.restTemplate = restTemplate; |
|||
this.appConfig = appConfig; |
|||
} |
|||
|
|||
// new |
|||
// @GetMapping("/getAllDetails") |
|||
// public ResponseEntity<?> getAllRequestDetails( |
|||
// @RequestParam String userLogin, |
|||
// @RequestParam(required = false) String startDate, |
|||
// @RequestParam(required = false) String endDate) { |
|||
|
|||
// try { |
|||
// List<Map<String, Object>> result = |
|||
// rdoService.getAllRequestDetailsByUserLogin( |
|||
// userLogin, startDate, endDate); |
|||
|
|||
// // 🔥 Attach HISTORY per refid |
|||
// for (Map<String, Object> record : result) { |
|||
// String refid = (String) record.get("refid"); |
|||
|
|||
// // List<Map<String, Object>> history = |
|||
// // rdoService.getRequestHistoryByRefId(refid); |
|||
// List<Map<String, Object>> history = |
|||
// rdoService.getOfficerFeedbackHistoryByRefId(refid, |
|||
// userLogin); |
|||
|
|||
// record.put("history", history); |
|||
// } |
|||
|
|||
// return ResponseEntity.ok( |
|||
// Map.of( |
|||
// "status", "success", |
|||
// "count", result.size(), |
|||
// "data", result)); |
|||
|
|||
// } catch (Exception e) { |
|||
// e.printStackTrace(); |
|||
// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) |
|||
// .body(Map.of( |
|||
// "status", "error", |
|||
// "message", "Failed to fetch data", |
|||
// "error", e.getMessage())); |
|||
// } |
|||
// } |
|||
|
|||
// @GetMapping("/getAllDetails") |
|||
// public ResponseEntity<?> getAllRequestDetails( |
|||
// @RequestParam String gccUserId, |
|||
// @RequestParam(required = false) String startDate, |
|||
// @RequestParam(required = false) String endDate) { |
|||
|
|||
// try { |
|||
|
|||
// // 🔥 Resolve username ONCE (backend trust) |
|||
// String username = rdoService.getUsernameByUserId(gccUserId); |
|||
// if (username == null) { |
|||
// throw new RuntimeException("Invalid gccUserId : " + gccUserId); |
|||
// } |
|||
|
|||
// List<Map<String, Object>> result = |
|||
// rdoService.getAllRequestDetailsByUserLogin( |
|||
// gccUserId, startDate, endDate); |
|||
|
|||
// // 🔥 Attach HISTORY per refid (dept-wise) |
|||
// for (Map<String, Object> record : result) { |
|||
// String refid = (String) record.get("refid"); |
|||
|
|||
// List<Map<String, Object>> history = |
|||
// rdoService.getOfficerFeedbackHistoryByRefId( |
|||
// refid, username); |
|||
|
|||
// record.put("history", history); |
|||
// } |
|||
|
|||
// return ResponseEntity.ok( |
|||
// Map.of( |
|||
// "status", "success", |
|||
// "count", result.size(), |
|||
// "data", result)); |
|||
|
|||
// } catch (Exception e) { |
|||
// e.printStackTrace(); |
|||
// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) |
|||
// .body(Map.of( |
|||
// "status", "error", |
|||
// "message", "Failed to fetch data", |
|||
// "error", e.getMessage())); |
|||
// } |
|||
// } |
|||
|
|||
@GetMapping("/getAllDetails") |
|||
public ResponseEntity<?> getAllRequestDetails( |
|||
@RequestParam String gccUserId, |
|||
@RequestParam(required = false) String startDate, |
|||
@RequestParam(required = false) String endDate) { |
|||
|
|||
try { |
|||
|
|||
/* 🔥 Normalize input (username OR id → gccuserid) */ |
|||
gccUserId = rdoService.resolveGccUserId(gccUserId); |
|||
|
|||
List<Map<String, Object>> result = rdoService.getAllRequestDetailsByUserLogin(gccUserId, |
|||
startDate, endDate); |
|||
|
|||
/* 🔥 Attach HISTORY per refid */ |
|||
for (Map<String, Object> record : result) { |
|||
|
|||
String refid = (String) record.get("refid"); |
|||
|
|||
List<Map<String, Object>> history = rdoService.getOfficerFeedbackHistoryByRefId(refid, |
|||
gccUserId); |
|||
|
|||
record.put("history", history); |
|||
} |
|||
|
|||
return ResponseEntity.ok( |
|||
Map.of( |
|||
"status", "success", |
|||
"count", result.size(), |
|||
"data", result)); |
|||
|
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) |
|||
.body(Map.of( |
|||
"status", "error", |
|||
"message", "Failed to fetch data", |
|||
"error", e.getMessage())); |
|||
} |
|||
} |
|||
|
|||
// old |
|||
// @PostMapping("/rdo/updateDecision") |
|||
// public ResponseEntity<?> updateRdoDecision( |
|||
// @RequestParam String refid, |
|||
// @RequestParam String status, |
|||
// @RequestParam String remarks, |
|||
// @RequestParam String approvedBy) { |
|||
|
|||
// int count = rdoService.updateRdoDecision(refid, status, remarks, approvedBy); |
|||
|
|||
// if (count > 0) { |
|||
// return ResponseEntity.ok(Map.of( |
|||
// "status", "SUCCESS", |
|||
// "message", "Decision updated successfully")); |
|||
// } else { |
|||
// return ResponseEntity.badRequest().body(Map.of( |
|||
// "status", "FAILED", |
|||
// "message", "Unable to update decision")); |
|||
// } |
|||
// } |
|||
|
|||
// @PostMapping("/rdo/updateDecision") |
|||
// public ResponseEntity<?> updateRdoDecision( |
|||
// @RequestParam String refid, |
|||
// @RequestParam String status, |
|||
// @RequestParam String remarks, |
|||
// @RequestParam String gccUserId) { |
|||
|
|||
// try { |
|||
|
|||
// /* 🔥 Normalize username OR id → gccuserid */ |
|||
// gccUserId = rdoService.resolveGccUserId(gccUserId); |
|||
|
|||
// int count = rdoService.updateRdoDecision( |
|||
// refid, status, remarks, gccUserId); |
|||
|
|||
// if (count > 0) { |
|||
// return ResponseEntity.ok(Map.of( |
|||
// "status", "SUCCESS", |
|||
// "message", "Decision updated successfully")); |
|||
// } else { |
|||
// return ResponseEntity.badRequest().body(Map.of( |
|||
// "status", "FAILED", |
|||
// "message", "Unable to update decision")); |
|||
// } |
|||
|
|||
// } catch (Exception e) { |
|||
// e.printStackTrace(); |
|||
// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) |
|||
// .body(Map.of( |
|||
// "status", "ERROR", |
|||
// "message", e.getMessage())); |
|||
// } |
|||
// } |
|||
|
|||
@PostMapping("/officer/updateDecision") |
|||
public ResponseEntity<?> updateOfficerDecision( |
|||
@RequestParam String refid, |
|||
@RequestParam String status, |
|||
@RequestParam String remarks, |
|||
@RequestParam String gccUserId, |
|||
@RequestParam String username) { |
|||
|
|||
try { |
|||
|
|||
/* 🔥 Normalize username OR id → gccuserid */ |
|||
gccUserId = rdoService.resolveGccUserId(gccUserId); |
|||
|
|||
int count = rdoService.updateOfficerDecision( |
|||
refid, |
|||
status, |
|||
remarks, |
|||
gccUserId, |
|||
username); |
|||
|
|||
if (count > 0) { |
|||
return ResponseEntity.ok(Map.of( |
|||
"status", "SUCCESS", |
|||
"message", "Decision updated successfully")); |
|||
} else { |
|||
return ResponseEntity.badRequest().body(Map.of( |
|||
"status", "FAILED", |
|||
"message", "Unable to update decision")); |
|||
} |
|||
|
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) |
|||
.body(Map.of( |
|||
"status", "ERROR", |
|||
"message", e.getMessage())); |
|||
} |
|||
} |
|||
|
|||
// old |
|||
// @GetMapping("/getApprovedAndRejectedDetails") |
|||
// public ResponseEntity<?> getApprovedRequestDetails( |
|||
// @RequestParam String userLogin, |
|||
// @RequestParam(required = false) String startDate, |
|||
// @RequestParam(required = false) String endDate, |
|||
// @RequestParam(required = false) String status) { |
|||
|
|||
// try { |
|||
// List<Map<String, Object>> result = |
|||
// rdoService.getRdoApprovedRequestDetailsByUserLogin( |
|||
// userLogin, startDate, endDate, status); |
|||
|
|||
// return ResponseEntity.ok( |
|||
// Map.of( |
|||
// "status", "success", |
|||
// "count", result.size(), |
|||
// "data", result)); |
|||
|
|||
// } catch (Exception e) { |
|||
// e.printStackTrace(); |
|||
// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) |
|||
// .body( |
|||
// Map.of( |
|||
// "status", "error", |
|||
// "message", "Failed to fetch data", |
|||
// "error", e.getMessage())); |
|||
// } |
|||
// } |
|||
|
|||
// new |
|||
// @GetMapping("/getApprovedAndRejectedDetails") |
|||
// public ResponseEntity<?> getApprovedRequestDetails( |
|||
// @RequestParam String userLogin, |
|||
// @RequestParam(required = false) String startDate, |
|||
// @RequestParam(required = false) String endDate, |
|||
// @RequestParam(required = false) String status) { |
|||
|
|||
// try { |
|||
// List<Map<String, Object>> result = |
|||
// rdoService.getRdoApprovedRequestDetailsByUserLogin( |
|||
// userLogin, startDate, endDate, status); |
|||
|
|||
// // 🔥 Attach HISTORY per refid |
|||
// for (Map<String, Object> record : result) { |
|||
// String refid = (String) record.get("refid"); |
|||
|
|||
// List<Map<String, Object>> history = |
|||
// rdoService.getRequestHistoryByRefId(refid); |
|||
|
|||
// record.put("history", history); |
|||
// } |
|||
|
|||
// return ResponseEntity.ok( |
|||
// Map.of( |
|||
// "status", "success", |
|||
// "count", result.size(), |
|||
// "data", result)); |
|||
|
|||
// } catch (Exception e) { |
|||
// e.printStackTrace(); |
|||
// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) |
|||
// .body(Map.of( |
|||
// "status", "error", |
|||
// "message", "Failed to fetch data", |
|||
// "error", e.getMessage())); |
|||
// } |
|||
// } |
|||
|
|||
// @GetMapping("/getApprovedAndRejectedDetails") |
|||
// public ResponseEntity<?> getApprovedRequestDetails( |
|||
// @RequestParam String userLogin, |
|||
// @RequestParam(required = false) String startDate, |
|||
// @RequestParam(required = false) String endDate) { |
|||
|
|||
// try { |
|||
// List<Map<String, Object>> result = |
|||
// rdoService.getRdoApprovedRequestDetailsByUserLogin( |
|||
// userLogin, startDate, endDate, null); |
|||
|
|||
// for (Map<String, Object> record : result) { |
|||
// String refid = (String) record.get("refid"); |
|||
|
|||
// // 🔥 NEW: officer feedback history |
|||
// List<Map<String, Object>> history = |
|||
// rdoService.getOfficerFeedbackHistoryByRefId(refid, |
|||
// userLogin); |
|||
|
|||
// record.put("history", history); |
|||
// } |
|||
|
|||
// return ResponseEntity.ok(Map.of( |
|||
// "status", "success", |
|||
// "count", result.size(), |
|||
// "data", result)); |
|||
|
|||
// } catch (Exception e) { |
|||
// e.printStackTrace(); |
|||
// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) |
|||
// .body(Map.of( |
|||
// "status", "error", |
|||
// "message", "Failed to fetch data", |
|||
// "error", e.getMessage())); |
|||
// } |
|||
// } |
|||
|
|||
@GetMapping("/getApprovedAndRejectedDetails") |
|||
public ResponseEntity<?> getApprovedRequestDetails( |
|||
@RequestParam String gccUserId, |
|||
@RequestParam(required = false) String startDate, |
|||
@RequestParam(required = false) String endDate) { |
|||
|
|||
try { |
|||
|
|||
/* 🔥 Normalize username OR id → gccuserid */ |
|||
gccUserId = rdoService.resolveGccUserId(gccUserId); |
|||
|
|||
/* 🔥 Fetch approved & rejected records */ |
|||
List<Map<String, Object>> result = rdoService.getRdoApprovedRequestDetailsByUserLogin( |
|||
gccUserId, startDate, endDate, null); |
|||
|
|||
/* 🔥 Attach officer feedback history per refid */ |
|||
for (Map<String, Object> record : result) { |
|||
|
|||
String refid = (String) record.get("refid"); |
|||
|
|||
List<Map<String, Object>> history = rdoService.getOfficerFeedbackHistoryByRefId(refid, |
|||
gccUserId); |
|||
|
|||
record.put("history", history); |
|||
} |
|||
|
|||
return ResponseEntity.ok(Map.of( |
|||
"status", "success", |
|||
"count", result.size(), |
|||
"data", result)); |
|||
|
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) |
|||
.body(Map.of( |
|||
"status", "error", |
|||
"message", "Failed to fetch approved/rejected data", |
|||
"error", e.getMessage())); |
|||
} |
|||
} |
|||
|
|||
@GetMapping("/sendApprovedMessage") |
|||
public String sendApprovedMessage(@RequestParam String mobileNo, |
|||
@RequestParam String refid) { |
|||
|
|||
return flagpoleSMSService.userrequestApprovedsms(mobileNo, refid); |
|||
} |
|||
|
|||
@GetMapping("/sendRejectMessage") |
|||
public String sendRejectMessage(@RequestParam String mobileNo, @RequestParam String refid) { |
|||
return flagpoleSMSService.userrequestRejectedsms(mobileNo, refid); |
|||
} |
|||
|
|||
@GetMapping("/sendUnauthorizedMessage") |
|||
public String sendUnauthorizedMessage(@RequestParam String mobileNo, @RequestParam String location, |
|||
@RequestParam String fineAmount, @RequestParam String refid) { |
|||
return flagpoleSMSService.unauthorizedFlagPoleSms(mobileNo, location, fineAmount, refid); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,53 @@ |
|||
package com.gcc.flagpoles_services.flagpoles.controller; |
|||
|
|||
import org.springframework.stereotype.Controller; |
|||
import org.springframework.ui.Model; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
|
|||
import com.gcc.flagpoles_services.service.LoginUserInfo; |
|||
|
|||
@RequestMapping("/flagpoles/list") |
|||
@Controller("flagpolesController") |
|||
public class MainController { |
|||
|
|||
@GetMapping("/requestlist") |
|||
public String home(Model model) { |
|||
|
|||
String LoginUserId = LoginUserInfo.getLoginUserId(); |
|||
model.addAttribute("LoginUserId", LoginUserId); |
|||
|
|||
String officer_name = LoginUserInfo.getCurrentUserDetails().getUsername(); |
|||
model.addAttribute("officer_name", officer_name); |
|||
|
|||
String UserRole = LoginUserInfo.getUserRole(); // rdo_north / rdo_central |
|||
model.addAttribute("UserRole", UserRole); |
|||
|
|||
return "modules/flagpole/requestlist"; |
|||
} |
|||
|
|||
@GetMapping("/approvedandrejectedlist") |
|||
public String batches(Model model) { |
|||
String LoginUserId = LoginUserInfo.getLoginUserId(); |
|||
model.addAttribute("LoginUserId", LoginUserId); |
|||
String officer_name = LoginUserInfo.getCurrentUserDetails().getUsername(); |
|||
model.addAttribute("officer_name", officer_name); |
|||
|
|||
String UserRole = LoginUserInfo.getUserRole(); |
|||
model.addAttribute("UserRole", UserRole); |
|||
return "modules/flagpole/approvedandrejectedlist"; |
|||
} |
|||
|
|||
@GetMapping("/reports") |
|||
public String dataentry(Model model) { |
|||
String LoginUserId = LoginUserInfo.getLoginUserId(); |
|||
model.addAttribute("LoginUserId", LoginUserId); |
|||
|
|||
String officer_name = LoginUserInfo.getCurrentUserDetails().getUsername(); |
|||
model.addAttribute("officer_name", officer_name); |
|||
|
|||
String UserRole = LoginUserInfo.getUserRole(); |
|||
model.addAttribute("UserRole", UserRole); |
|||
return "modules/flagpole/reports"; |
|||
} |
|||
} |
|||
@ -0,0 +1,248 @@ |
|||
package com.gcc.flagpoles_services.flagpoles.service; |
|||
|
|||
import java.io.BufferedReader; |
|||
import java.io.InputStreamReader; |
|||
import java.net.HttpURLConnection; |
|||
import java.net.URL; |
|||
import java.net.URLEncoder; |
|||
import java.nio.charset.StandardCharsets; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import com.gcc.flagpoles_services.configuration.AppConfig; |
|||
import com.gcc.flagpoles_services.flagpoles.util.MessageUtility; |
|||
|
|||
@Service |
|||
public class FlagpoleSMSService { |
|||
|
|||
@Autowired |
|||
private AppConfig appConfig; |
|||
|
|||
@Autowired |
|||
private MessageUtility messageUtility; |
|||
|
|||
private final String key = "pfTEYN6H"; |
|||
|
|||
public String sendBookingSuccesssms(String mobileNo, String requestId) { |
|||
|
|||
String message = "Your Flag Pole permission request has been submitted successfully. " |
|||
+ "Request ID: " + requestId |
|||
+ ". You will be notified once the status is updated. By GCC"; |
|||
|
|||
// Encode message and fix colon issue (gateway not decoding %3A) |
|||
String encodedMsg = URLEncoder.encode(message, StandardCharsets.UTF_8) |
|||
.replace("%3A", ":"); |
|||
|
|||
String urlString = appConfig.getOtpUrl() |
|||
+ "from=GCCCRP" |
|||
+ "&key=" + key |
|||
+ "&sender=GCCCRP" |
|||
+ "&to=" + mobileNo |
|||
+ "&body=" + encodedMsg |
|||
+ "&entityid=1401572690000011081" |
|||
+ "&templateid=1407176959297472163"; |
|||
|
|||
System.out.println("SMS URL:- " + urlString); |
|||
|
|||
String response = messageUtility.sendSMS(urlString); |
|||
System.out.println("SMS RESPONSE:- " + response); |
|||
|
|||
return response; |
|||
} |
|||
|
|||
public String userrequestApprovedsms(String mobileNo, String requestId) { |
|||
|
|||
String message = "Your Flag Pole permission request has been approved. " |
|||
+ "Request ID: " + requestId |
|||
+ ". Please proceed as per the permitted guidelines. By GCC"; |
|||
|
|||
// Encode message and fix colon issue (gateway not decoding %3A) |
|||
String encodedMsg = URLEncoder.encode(message, StandardCharsets.UTF_8) |
|||
.replace("%3A", ":"); |
|||
|
|||
String urlString = appConfig.getOtpUrl() |
|||
+ "from=GCCCRP" |
|||
+ "&key=" + key |
|||
+ "&sender=GCCCRP" |
|||
+ "&to=" + mobileNo |
|||
+ "&body=" + encodedMsg |
|||
+ "&entityid=1401572690000011081" |
|||
+ "&templateid=1407176959304753543"; |
|||
|
|||
System.out.println("SMS URL:- " + urlString); |
|||
|
|||
String response = messageUtility.sendSMS(urlString); |
|||
System.out.println("SMS RESPONSE:- " + response); |
|||
|
|||
return response; |
|||
} |
|||
|
|||
// public String userrequestRejectedsms(String mobileNo, String requestId) { |
|||
|
|||
// String message = "Your Flag Pole permission request has been rejected. " |
|||
// + "Request ID: " + requestId + ". " |
|||
// + "Review the details in the portal |
|||
// https://gccservices.in/flagpolesregistration/status\n" |
|||
// + "By GCC"; |
|||
|
|||
// // ONLY encode. Do NOT replace %3A |
|||
// String encodedMsg = URLEncoder.encode(message, StandardCharsets.UTF_8); |
|||
|
|||
// String urlString = appConfig.getOtpUrl() |
|||
// + "from=GCCCRP" |
|||
// + "&key=" + key |
|||
// + "&sender=GCCCRP" |
|||
// + "&to=" + mobileNo |
|||
// + "&body=" + encodedMsg |
|||
// + "&entityid=1401572690000011081" |
|||
// + "&templateid=1407176959315374790"; |
|||
|
|||
// System.out.println("SMS URL:- " + urlString); |
|||
|
|||
// String response = messageUtility.sendSMS(urlString); |
|||
// System.out.println("SMS RESPONSE:- " + response); |
|||
|
|||
// return response; |
|||
// } |
|||
|
|||
public String userrequestRejectedsms(String mobileNo, String requestId) { |
|||
|
|||
try { |
|||
|
|||
String url = "https://gccservices.in/flagpolesregistration/status"; |
|||
|
|||
String message = "Your Flag Pole permission request has been rejected. Request ID: " + requestId |
|||
+ ". Review the details in the portal " + url + "\r\nBy GCC"; |
|||
|
|||
String encodedMsg = URLEncoder.encode(message, StandardCharsets.UTF_8); |
|||
|
|||
String urlString = appConfig.getOtpUrl() |
|||
+ "from=GCCCRP" |
|||
+ "&key=" + key |
|||
+ "&sender=GCCCRP" |
|||
+ "&to=" + mobileNo |
|||
+ "&body=" + encodedMsg |
|||
+ "&entityid=1401572690000011081" |
|||
+ "&templateid=1407176959315374790"; |
|||
|
|||
System.out.println("FINAL SMS URL:- " + urlString); |
|||
|
|||
URL apiUrl = new URL(urlString); |
|||
HttpURLConnection conn = (HttpURLConnection) apiUrl.openConnection(); |
|||
conn.setRequestMethod("GET"); |
|||
conn.setConnectTimeout(15000); |
|||
conn.setReadTimeout(15000); |
|||
|
|||
BufferedReader in = new BufferedReader( |
|||
new InputStreamReader(conn.getInputStream())); |
|||
String inputLine; |
|||
StringBuilder content = new StringBuilder(); |
|||
|
|||
while ((inputLine = in.readLine()) != null) { |
|||
content.append(inputLine); |
|||
} |
|||
|
|||
in.close(); |
|||
conn.disconnect(); |
|||
|
|||
System.out.println("DIRECT SMS RESPONSE:- " + content.toString()); |
|||
|
|||
return content.toString(); |
|||
|
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
return "FAILED"; |
|||
} |
|||
} |
|||
|
|||
// public String unauthorizedFlagPoleSms(String mobileNo, |
|||
// String location, |
|||
// String fineAmount, |
|||
// String requestId) { |
|||
|
|||
// String message = "An unauthorized flag pole installation was found at " + |
|||
// location + ". " |
|||
// + "Fine amount: Rs. " + fineAmount |
|||
// + " to be paid at |
|||
// https://gccservices.in/flagpolesregistration/paymentform?requestId=" |
|||
// + requestId + " to avoid further action.\n" |
|||
// + "By GCC"; |
|||
|
|||
// // Encode full message |
|||
// String encodedMsg = URLEncoder.encode(message, StandardCharsets.UTF_8); |
|||
|
|||
// String urlString = appConfig.getOtpUrl() |
|||
// + "from=GCCCRP" |
|||
// + "&key=" + key |
|||
// + "&sender=GCCCRP" |
|||
// + "&to=" + mobileNo |
|||
// + "&body=" + encodedMsg |
|||
// + "&entityid=1401572690000011081" |
|||
// + "&templateid=1407176959335259899"; // replace with actual template id |
|||
|
|||
// System.out.println("SMS URL:- " + urlString); |
|||
|
|||
// String response = messageUtility.sendSMS(urlString); |
|||
// System.out.println("SMS RESPONSE:- " + response); |
|||
|
|||
// return response; |
|||
// } |
|||
|
|||
public String unauthorizedFlagPoleSms(String mobileNo, |
|||
String location, |
|||
String fineAmount, |
|||
String requestId) { |
|||
|
|||
try { |
|||
|
|||
String paymentUrl = "https://gccservices.in/flagpolesregistration/paymentform?requestId=" |
|||
+ requestId; |
|||
|
|||
String message = "An unauthorized flag pole installation was found at " + location + ". " |
|||
+ "Fine amount: Rs. " + fineAmount |
|||
+ " to be paid at " + paymentUrl |
|||
+ " to avoid further action.\r\n" |
|||
+ "By GCC"; |
|||
|
|||
String encodedMsg = URLEncoder.encode(message, StandardCharsets.UTF_8); |
|||
|
|||
String urlString = appConfig.getOtpUrl() |
|||
+ "from=GCCCRP" |
|||
+ "&key=" + key |
|||
+ "&sender=GCCCRP" |
|||
+ "&to=" + mobileNo |
|||
+ "&body=" + encodedMsg |
|||
+ "&entityid=1401572690000011081" |
|||
+ "&templateid=1407176959335259899"; |
|||
|
|||
System.out.println("FINAL SMS URL:- " + urlString); |
|||
|
|||
URL apiUrl = new URL(urlString); |
|||
HttpURLConnection conn = (HttpURLConnection) apiUrl.openConnection(); |
|||
conn.setRequestMethod("GET"); |
|||
conn.setConnectTimeout(15000); |
|||
conn.setReadTimeout(15000); |
|||
|
|||
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream())); |
|||
String inputLine; |
|||
StringBuilder content = new StringBuilder(); |
|||
|
|||
while ((inputLine = in.readLine()) != null) { |
|||
content.append(inputLine); |
|||
} |
|||
|
|||
in.close(); |
|||
conn.disconnect(); |
|||
|
|||
System.out.println("DIRECT SMS RESPONSE:- " + content.toString()); |
|||
|
|||
return content.toString(); |
|||
|
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
return "FAILED"; |
|||
} |
|||
} |
|||
|
|||
} |
|||
1356
src/main/java/com/gcc/flagpoles_services/flagpoles/service/RdoService.java
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,41 @@ |
|||
package com.gcc.flagpoles_services.flagpoles.util; |
|||
|
|||
import java.net.HttpURLConnection; |
|||
import java.net.URL; |
|||
|
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.web.client.RestTemplate; |
|||
|
|||
@Service |
|||
public class MessageUtility { |
|||
|
|||
public String sendMsg(String msgUrl) { |
|||
System.out.println("Whatsapp URL :-" + msgUrl); |
|||
|
|||
String response = ""; |
|||
try { |
|||
HttpURLConnection connection = null; |
|||
|
|||
URL url = new URL(msgUrl); |
|||
connection = (HttpURLConnection) url.openConnection(); |
|||
connection.setRequestMethod("GET"); |
|||
|
|||
int responseCode = connection.getResponseCode(); |
|||
response = responseCode + ""; |
|||
System.out.println("Response Code: " + responseCode); |
|||
|
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
|
|||
return response; |
|||
} |
|||
|
|||
public String sendSMS(String SMS_Url) { |
|||
// System.out.println("SMS URL:- " + SMS_Url); |
|||
RestTemplate restTemplate = new RestTemplate(); |
|||
String response = restTemplate.getForObject(SMS_Url, String.class); |
|||
return response; |
|||
} |
|||
|
|||
} |
|||
@ -1,4 +1,4 @@ |
|||
package com.gcc.swm_services.modeldata; |
|||
package com.gcc.flagpoles_services.modeldata; |
|||
|
|||
public class ErrorResponse { |
|||
|
|||
@ -1,10 +1,10 @@ |
|||
package com.gcc.swm_services.repository; |
|||
package com.gcc.flagpoles_services.repository; |
|||
|
|||
import org.springframework.data.jpa.repository.JpaRepository; |
|||
import org.springframework.data.jpa.repository.Query; |
|||
import org.springframework.stereotype.Repository; |
|||
|
|||
import com.gcc.swm_services.entity.AppUserGroupEntity; |
|||
import com.gcc.flagpoles_services.entity.AppUserGroupEntity; |
|||
|
|||
import javax.transaction.Transactional; |
|||
|
|||
@ -1,11 +1,11 @@ |
|||
package com.gcc.swm_services.repository; |
|||
package com.gcc.flagpoles_services.repository; |
|||
|
|||
import java.util.List; |
|||
|
|||
import org.springframework.data.jpa.repository.JpaRepository; |
|||
import org.springframework.stereotype.Repository; |
|||
|
|||
import com.gcc.swm_services.entity.UserActivityLog; |
|||
import com.gcc.flagpoles_services.entity.UserActivityLog; |
|||
|
|||
import javax.transaction.Transactional; |
|||
|
|||
@ -1,4 +1,4 @@ |
|||
package com.gcc.swm_services.repository; |
|||
package com.gcc.flagpoles_services.repository; |
|||
|
|||
import org.springframework.data.jpa.repository.Query; |
|||
import org.springframework.stereotype.Repository; |
|||
@ -1,4 +1,4 @@ |
|||
package com.gcc.swm_services.service; |
|||
package com.gcc.flagpoles_services.service; |
|||
|
|||
import java.util.Base64; |
|||
|
|||
@ -1,4 +1,4 @@ |
|||
package com.gcc.swm_services.service; |
|||
package com.gcc.flagpoles_services.service; |
|||
|
|||
import org.springframework.security.core.GrantedAuthority; |
|||
import org.springframework.security.core.userdetails.UserDetails; |
|||
@ -1,4 +1,4 @@ |
|||
package com.gcc.swm_services.service; |
|||
package com.gcc.flagpoles_services.service; |
|||
|
|||
import java.time.LocalDate; |
|||
import java.time.temporal.ChronoUnit; |
|||
@ -1,10 +1,10 @@ |
|||
package com.gcc.swm_services.service; |
|||
package com.gcc.flagpoles_services.service; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import com.gcc.swm_services.entity.UserActivityLog; |
|||
import com.gcc.swm_services.repository.UserActivityLogRepository; |
|||
import com.gcc.flagpoles_services.entity.UserActivityLog; |
|||
import com.gcc.flagpoles_services.repository.UserActivityLogRepository; |
|||
|
|||
import java.time.LocalDateTime; |
|||
|
|||
@ -1,10 +1,10 @@ |
|||
package com.gcc.swm_services.service; |
|||
package com.gcc.flagpoles_services.service; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import com.gcc.swm_services.entity.UserActivityLog; |
|||
import com.gcc.swm_services.repository.UserActivityLogRepository; |
|||
import com.gcc.flagpoles_services.entity.UserActivityLog; |
|||
import com.gcc.flagpoles_services.repository.UserActivityLogRepository; |
|||
|
|||
import java.util.List; |
|||
|
|||
@ -1,163 +0,0 @@ |
|||
package com.gcc.swm_services.swm.controller; |
|||
|
|||
import org.springframework.stereotype.Controller; |
|||
import org.springframework.ui.Model; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
|
|||
import com.gcc.swm_services.service.LoginUserInfo; |
|||
|
|||
@Controller("AdminswmController") |
|||
@RequestMapping("/swm/adminfacilities") |
|||
public class AdminController { |
|||
@GetMapping("/mcc") |
|||
public String mcc(Model model) { |
|||
String LoginUserId = LoginUserInfo.getLoginUserId(); |
|||
model.addAttribute("LoginUserId", LoginUserId); |
|||
|
|||
String officer_name = LoginUserInfo.getCurrentUserDetails().getUsername(); |
|||
model.addAttribute("officer_name", officer_name); |
|||
|
|||
String UserRole = LoginUserInfo.getUserRole(); // rdo_north / rdo_central |
|||
model.addAttribute("UserRole", UserRole); |
|||
int facilityTypeId = 1; // Plastic Baling Centre |
|||
model.addAttribute("facilityTypeId", facilityTypeId); |
|||
return "modules/swm/mcc"; |
|||
} |
|||
|
|||
@GetMapping("/windrow") |
|||
public String windrow(Model model) { |
|||
String LoginUserId = LoginUserInfo.getLoginUserId(); |
|||
model.addAttribute("LoginUserId", LoginUserId); |
|||
|
|||
String officer_name = LoginUserInfo.getCurrentUserDetails().getUsername(); |
|||
model.addAttribute("officer_name", officer_name); |
|||
|
|||
String UserRole = LoginUserInfo.getUserRole(); // rdo_north / rdo_central |
|||
model.addAttribute("UserRole", UserRole); |
|||
int facilityTypeId = 2; // Plastic Baling Centre |
|||
model.addAttribute("facilityTypeId", facilityTypeId); |
|||
return "modules/swm/windrow"; |
|||
} |
|||
|
|||
@GetMapping("/biocng") |
|||
public String biocng(Model model) { |
|||
String LoginUserId = LoginUserInfo.getLoginUserId(); |
|||
model.addAttribute("LoginUserId", LoginUserId); |
|||
|
|||
String officer_name = LoginUserInfo.getCurrentUserDetails().getUsername(); |
|||
model.addAttribute("officer_name", officer_name); |
|||
|
|||
String UserRole = LoginUserInfo.getUserRole(); // rdo_north / rdo_central |
|||
model.addAttribute("UserRole", UserRole); |
|||
int facilityTypeId = 3; // Plastic Baling Centre |
|||
model.addAttribute("facilityTypeId", facilityTypeId); |
|||
return "modules/swm/biocng"; |
|||
} |
|||
|
|||
@GetMapping("/biogas") |
|||
public String biogas(Model model) { |
|||
String LoginUserId = LoginUserInfo.getLoginUserId(); |
|||
model.addAttribute("LoginUserId", LoginUserId); |
|||
|
|||
String officer_name = LoginUserInfo.getCurrentUserDetails().getUsername(); |
|||
model.addAttribute("officer_name", officer_name); |
|||
|
|||
String UserRole = LoginUserInfo.getUserRole(); // rdo_north / rdo_central |
|||
model.addAttribute("UserRole", UserRole); |
|||
int facilityTypeId = 4; // Plastic Baling Centre |
|||
model.addAttribute("facilityTypeId", facilityTypeId); |
|||
return "modules/swm/biogas"; |
|||
} |
|||
|
|||
@GetMapping("/gwtcwaste") |
|||
public String gwtcwaste(Model model) { |
|||
String LoginUserId = LoginUserInfo.getLoginUserId(); |
|||
model.addAttribute("LoginUserId", LoginUserId); |
|||
|
|||
String officer_name = LoginUserInfo.getCurrentUserDetails().getUsername(); |
|||
model.addAttribute("officer_name", officer_name); |
|||
|
|||
String UserRole = LoginUserInfo.getUserRole(); // rdo_north / rdo_central |
|||
model.addAttribute("UserRole", UserRole); |
|||
int facilityTypeId = 5; // Plastic Baling Centre |
|||
model.addAttribute("facilityTypeId", facilityTypeId); |
|||
return "modules/swm/gwtcwaste"; |
|||
} |
|||
|
|||
@GetMapping("/mrf") |
|||
public String mrf(Model model) { |
|||
String LoginUserId = LoginUserInfo.getLoginUserId(); |
|||
model.addAttribute("LoginUserId", LoginUserId); |
|||
|
|||
String officer_name = LoginUserInfo.getCurrentUserDetails().getUsername(); |
|||
model.addAttribute("officer_name", officer_name); |
|||
|
|||
String UserRole = LoginUserInfo.getUserRole(); // rdo_north / rdo_central |
|||
model.addAttribute("UserRole", UserRole); |
|||
int facilityTypeId = 6; // Plastic Baling Centre |
|||
model.addAttribute("facilityTypeId", facilityTypeId); |
|||
return "modules/swm/mrf"; |
|||
} |
|||
|
|||
@GetMapping("/incinerator") |
|||
public String incinerator(Model model) { |
|||
String LoginUserId = LoginUserInfo.getLoginUserId(); |
|||
model.addAttribute("LoginUserId", LoginUserId); |
|||
|
|||
String officer_name = LoginUserInfo.getCurrentUserDetails().getUsername(); |
|||
model.addAttribute("officer_name", officer_name); |
|||
|
|||
String UserRole = LoginUserInfo.getUserRole(); // rdo_north / rdo_central |
|||
model.addAttribute("UserRole", UserRole); |
|||
int facilityTypeId = 7; // Plastic Baling Centre |
|||
model.addAttribute("facilityTypeId", facilityTypeId); |
|||
return "modules/swm/incinerator"; |
|||
} |
|||
|
|||
@GetMapping("/plastingbaling") |
|||
public String plastingbaling(Model model) { |
|||
String LoginUserId = LoginUserInfo.getLoginUserId(); |
|||
model.addAttribute("LoginUserId", LoginUserId); |
|||
|
|||
int facilityTypeId = 8; // Plastic Baling Centre |
|||
model.addAttribute("facilityTypeId", facilityTypeId); |
|||
String officer_name = LoginUserInfo.getCurrentUserDetails().getUsername(); |
|||
model.addAttribute("officer_name", officer_name); |
|||
|
|||
String UserRole = LoginUserInfo.getUserRole(); // rdo_north / rdo_central |
|||
model.addAttribute("UserRole", UserRole); |
|||
return "modules/swm/plastingbaling"; |
|||
} |
|||
|
|||
@GetMapping("/cdwaste") |
|||
public String cdwaste(Model model) { |
|||
String LoginUserId = LoginUserInfo.getLoginUserId(); |
|||
model.addAttribute("LoginUserId", LoginUserId); |
|||
|
|||
String officer_name = LoginUserInfo.getCurrentUserDetails().getUsername(); |
|||
model.addAttribute("officer_name", officer_name); |
|||
|
|||
String UserRole = LoginUserInfo.getUserRole(); // rdo_north / rdo_central |
|||
model.addAttribute("UserRole", UserRole); |
|||
int facilityTypeId = 9; // Plastic Baling Centre |
|||
model.addAttribute("facilityTypeId", facilityTypeId); |
|||
return "modules/swm/cdwaste"; |
|||
} |
|||
|
|||
@GetMapping("/reports") |
|||
public String reports(Model model) { |
|||
String LoginUserId = LoginUserInfo.getLoginUserId(); |
|||
model.addAttribute("LoginUserId", LoginUserId); |
|||
|
|||
String officer_name = LoginUserInfo.getCurrentUserDetails().getUsername(); |
|||
model.addAttribute("officer_name", officer_name); |
|||
|
|||
String UserRole = LoginUserInfo.getUserRole(); // rdo_north / rdo_central |
|||
model.addAttribute("UserRole", UserRole); |
|||
int facilityTypeId = 9; // Plastic Baling Centre |
|||
model.addAttribute("facilityTypeId", facilityTypeId); |
|||
return "modules/swm/reports"; |
|||
} |
|||
|
|||
} |
|||
@ -1,35 +0,0 @@ |
|||
package com.gcc.swm_services.swm.controller; |
|||
|
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
|
|||
import java.util.Map; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.http.ResponseEntity; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestParam; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import com.gcc.swm_services.swm.service.DropDownService; |
|||
|
|||
@RestController |
|||
@RequestMapping("/swm/api/dropdown") |
|||
public class DropDownApiController { |
|||
|
|||
@Autowired |
|||
private DropDownService dropDownService; |
|||
|
|||
@GetMapping("/getfacilitiestypelist") |
|||
public List<Map<String, Object>> getFacilitiesTypeList() { |
|||
return dropDownService.getFacilitiesTypeList(); |
|||
} |
|||
|
|||
@GetMapping("/getzoneslist") |
|||
public List<Map<String, Object>> getZonesList() { |
|||
return dropDownService.getZonesList(); |
|||
} |
|||
|
|||
} |
|||
@ -1,71 +0,0 @@ |
|||
package com.gcc.swm_services.swm.controller; |
|||
|
|||
import javax.servlet.http.HttpSession; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Controller; |
|||
import org.springframework.ui.Model; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
|
|||
import com.gcc.swm_services.service.LoginUserInfo; |
|||
import com.gcc.swm_services.swm.service.AddDetailsService; |
|||
|
|||
@Controller("swmController") |
|||
@RequestMapping("/swm/facilities") |
|||
public class MainController { |
|||
|
|||
@Autowired |
|||
private AddDetailsService addDetailsService; |
|||
|
|||
@GetMapping("/adddetails") |
|||
public String home(Model model, HttpSession session) { |
|||
|
|||
String loginUserId = LoginUserInfo.getLoginUserId(); // String |
|||
String officerName = LoginUserInfo.getCurrentUserDetails().getUsername(); |
|||
String userRole = LoginUserInfo.getUserRole(); |
|||
|
|||
// store in session |
|||
session.setAttribute("gcc_user_id", loginUserId); |
|||
session.setAttribute("username", officerName); |
|||
|
|||
// 🔑 derive facility type |
|||
int gccUserId = Integer.parseInt(loginUserId); |
|||
int dpid = addDetailsService.getDpidByGccUserId(gccUserId); |
|||
|
|||
// DIRECT MAPPING (as fixed earlier) |
|||
int facilityTypeId = dpid; |
|||
|
|||
// 🔑 THIS WAS MISSING |
|||
boolean isTwoWeightFacility = (facilityTypeId == 5); |
|||
boolean isWeightTypeFacility = (facilityTypeId == 5 || facilityTypeId == 9); |
|||
|
|||
// add to model |
|||
model.addAttribute("LoginUserId", loginUserId); |
|||
model.addAttribute("officer_name", officerName); |
|||
model.addAttribute("UserRole", userRole); |
|||
model.addAttribute("facilityTypeId", facilityTypeId); |
|||
model.addAttribute("isTwoWeightFacility", isTwoWeightFacility); |
|||
model.addAttribute("isWeightTypeFacility", isWeightTypeFacility); |
|||
|
|||
return "modules/swm/requestlist"; |
|||
} |
|||
|
|||
@GetMapping("/approvelist") |
|||
public String batches() { |
|||
return "modules/swm/approvelist"; |
|||
} |
|||
|
|||
@GetMapping("/reports") |
|||
public String dataentry(Model model) { |
|||
String LoginUserId = LoginUserInfo.getLoginUserId(); |
|||
model.addAttribute("LoginUserId", LoginUserId); |
|||
|
|||
String officer_name = LoginUserInfo.getCurrentUserDetails().getUsername(); |
|||
model.addAttribute("officer_name", officer_name); |
|||
|
|||
String UserRole = LoginUserInfo.getUserRole(); // rdo_north / rdo_central |
|||
model.addAttribute("UserRole", UserRole); |
|||
return "modules/swm/eachreport"; |
|||
} |
|||
} |
|||
@ -1,145 +0,0 @@ |
|||
package com.gcc.swm_services.swm.controller; |
|||
|
|||
import java.time.LocalDate; |
|||
import java.util.Map; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.format.annotation.DateTimeFormat; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.http.ResponseEntity; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.PostMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestParam; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import com.gcc.swm_services.service.LoginUserInfo; |
|||
import com.gcc.swm_services.swm.service.AddDetailsService; |
|||
|
|||
@RestController |
|||
@RequestMapping("/swm/api/admin") |
|||
public class SwmAdminApiController { |
|||
|
|||
@Autowired |
|||
private AddDetailsService addDetailsService; |
|||
|
|||
@PostMapping("/addfacility") |
|||
public ResponseEntity<?> addFacilityForAdmin( |
|||
|
|||
@RequestParam int facilityTypeId, |
|||
@RequestParam int zoneId, |
|||
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate reqDate, |
|||
@RequestParam Double weight, |
|||
@RequestParam(required = false) Double weight1, |
|||
@RequestParam(required = false) String weightType, |
|||
@RequestParam String createdBy) { |
|||
|
|||
try { |
|||
// 🔴 Validation |
|||
if (facilityTypeId < 1 || facilityTypeId > 9) { |
|||
throw new IllegalArgumentException("Invalid facility type"); |
|||
} |
|||
|
|||
if (zoneId <= 0) { |
|||
throw new IllegalArgumentException("Invalid zone"); |
|||
} |
|||
|
|||
if (reqDate == null) { |
|||
throw new IllegalArgumentException("Request date is required"); |
|||
} |
|||
|
|||
if (weight == null) { |
|||
throw new IllegalArgumentException("Weight is required"); |
|||
} |
|||
|
|||
if (facilityTypeId == 5) { |
|||
if (weight < 0) { |
|||
throw new IllegalArgumentException("Weight cannot be negative"); |
|||
} |
|||
} else { |
|||
if (weight <= 0) { |
|||
throw new IllegalArgumentException("Weight must be greater than zero"); |
|||
} |
|||
} |
|||
|
|||
// 🔴 Facility type 5 → TWO weights + weightType |
|||
if (facilityTypeId == 5) { |
|||
if (weight1 == null) { |
|||
throw new IllegalArgumentException( |
|||
"Second weight is required for GW & TC Waste facility"); |
|||
} |
|||
if (weightType == null || weightType.isBlank()) { |
|||
throw new IllegalArgumentException( |
|||
"Weight type (KDG / PDG) is required"); |
|||
} |
|||
} |
|||
|
|||
if (facilityTypeId == 9) { |
|||
|
|||
if (weightType == null || weightType.isBlank()) { |
|||
throw new IllegalArgumentException( |
|||
"Weight type (KDG / PDG) is required"); |
|||
} |
|||
} |
|||
|
|||
// 🔐 Admin username for audit |
|||
// String createdBy = LoginUserInfo.getCurrentUserDetails().getUsername(); |
|||
|
|||
// 🔵 SAVE |
|||
addDetailsService.addFacility( |
|||
facilityTypeId, |
|||
zoneId, |
|||
reqDate, |
|||
createdBy, |
|||
weight, |
|||
weight1, |
|||
weightType); |
|||
|
|||
return ResponseEntity.ok( |
|||
Map.of("status", "SUCCESS", "message", "Added successfully")); |
|||
|
|||
} catch (IllegalArgumentException ex) { |
|||
return ResponseEntity.badRequest().body( |
|||
Map.of("status", "ERROR", "message", ex.getMessage())); |
|||
} catch (Exception ex) { |
|||
ex.printStackTrace(); |
|||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body( |
|||
Map.of("status", "ERROR", "message", "Internal server error")); |
|||
} |
|||
} |
|||
|
|||
@GetMapping("/reports") |
|||
public ResponseEntity<?> getZoneTargetPercentage( |
|||
@RequestParam String fromDate, |
|||
@RequestParam String toDate) { |
|||
|
|||
if (fromDate == null || toDate == null || |
|||
fromDate.isBlank() || toDate.isBlank()) { |
|||
|
|||
return ResponseEntity.badRequest().body( |
|||
Map.of("status", "ERROR", "message", "Date range is required")); |
|||
} |
|||
|
|||
return ResponseEntity.ok( |
|||
Map.of( |
|||
"status", "SUCCESS", |
|||
"data", addDetailsService.getZoneTargetPercentage(fromDate, toDate))); |
|||
} |
|||
|
|||
@GetMapping("/singledayreports") |
|||
public ResponseEntity<?> getZoneTargetPercentagePerDay( |
|||
@RequestParam String Date) { |
|||
|
|||
if (Date == null || Date.isBlank()) { |
|||
|
|||
return ResponseEntity.badRequest().body( |
|||
Map.of("status", "ERROR", "message", "Date range is required")); |
|||
} |
|||
|
|||
return ResponseEntity.ok( |
|||
Map.of( |
|||
"status", "SUCCESS", |
|||
"data", addDetailsService.getZoneTargetPercentageForOneDay(Date))); |
|||
} |
|||
|
|||
} |
|||
@ -1,202 +0,0 @@ |
|||
package com.gcc.swm_services.swm.controller; |
|||
|
|||
import java.time.LocalDate; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
import javax.servlet.http.HttpSession; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.format.annotation.DateTimeFormat; |
|||
import org.springframework.http.HttpStatus; |
|||
import org.springframework.http.ResponseEntity; |
|||
import org.springframework.security.authentication.AnonymousAuthenticationToken; |
|||
import org.springframework.security.core.Authentication; |
|||
import org.springframework.security.core.context.SecurityContextHolder; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.PostMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestParam; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
import com.gcc.swm_services.service.LoginUserInfo; |
|||
import com.gcc.swm_services.swm.service.AddDetailsService; |
|||
|
|||
@RestController |
|||
@RequestMapping("/swm/api/facilities") |
|||
public class SwmApiController { |
|||
|
|||
@Autowired |
|||
private AddDetailsService addDetailsService; |
|||
|
|||
// @PostMapping("/addfacility") |
|||
// public ResponseEntity<?> addFacility( |
|||
|
|||
// @RequestParam int zoneId, |
|||
// @RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate |
|||
// reqDate, |
|||
// @RequestParam Double weight, |
|||
// @RequestParam(required = false) Double weight1, |
|||
// HttpSession session) { |
|||
|
|||
// try { |
|||
// // 🔴 Validation |
|||
// if (zoneId <= 0) { |
|||
// throw new IllegalArgumentException("Invalid zone"); |
|||
// } |
|||
|
|||
// if (reqDate == null) { |
|||
// throw new IllegalArgumentException("Request date is required"); |
|||
// } |
|||
|
|||
// if (weight == null || weight <= 0) { |
|||
// throw new IllegalArgumentException("Weight must be greater than zero"); |
|||
// } |
|||
|
|||
// // 🔐 GET LOGIN DATA FROM SESSION (CORRECT WAY) |
|||
// Object gccUserIdObj = session.getAttribute("gcc_user_id"); |
|||
// Object usernameObj = session.getAttribute("username"); |
|||
|
|||
// if (gccUserIdObj == null || usernameObj == null) { |
|||
// throw new IllegalStateException("User session expired. Please login again."); |
|||
// } |
|||
|
|||
// int gccUserId = Integer.parseInt(gccUserIdObj.toString()); |
|||
// String username = usernameObj.toString(); |
|||
|
|||
// // 🔐 DB MAPPING |
|||
// int dpid = addDetailsService.getDpidByGccUserId(gccUserId); |
|||
// int facilityTypeId = addDetailsService.getFacilityTypeIdByDpid(dpid); |
|||
|
|||
// if (facilityTypeId == 5 && (weight1 == null || weight1 <= 0)) { |
|||
// throw new IllegalArgumentException( |
|||
// "Second weight is required for GW & TC Waste facility"); |
|||
// } |
|||
|
|||
// addDetailsService.addFacility( |
|||
// facilityTypeId, |
|||
// zoneId, |
|||
// reqDate, |
|||
// username, |
|||
// weight, |
|||
// weight1); |
|||
|
|||
// return ResponseEntity.ok( |
|||
// Map.of("status", "SUCCESS", "message", "Facility added successfully")); |
|||
|
|||
// } catch (IllegalArgumentException | IllegalStateException ex) { |
|||
// return ResponseEntity.badRequest().body( |
|||
// Map.of("status", "ERROR", "message", ex.getMessage())); |
|||
// } catch (Exception ex) { |
|||
// ex.printStackTrace(); |
|||
// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body( |
|||
// Map.of("status", "ERROR", "message", "Internal server error")); |
|||
// } |
|||
// } |
|||
|
|||
@PostMapping("/addfacility") |
|||
public ResponseEntity<?> addFacility( |
|||
@RequestParam int zoneId, |
|||
@RequestParam @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate reqDate, |
|||
@RequestParam Double weight, |
|||
@RequestParam(required = false) Double weight1, |
|||
@RequestParam(required = false) String weightType, // ✅ ADDED |
|||
HttpSession session) { |
|||
|
|||
try { |
|||
|
|||
// 🔐 Session values |
|||
Object gccUserIdObj = session.getAttribute("gcc_user_id"); |
|||
Object usernameObj = session.getAttribute("username"); |
|||
int gccUserId = Integer.parseInt(gccUserIdObj.toString()); |
|||
String username = usernameObj.toString(); |
|||
|
|||
// 🔐 gcc_user_id → dpid → facilityTypeId |
|||
int dpid = addDetailsService.getDpidByGccUserId(gccUserId); |
|||
int facilityTypeId = dpid; |
|||
// 🔴 Validation |
|||
if (zoneId <= 0) { |
|||
throw new IllegalArgumentException("Invalid zone"); |
|||
} |
|||
|
|||
if (reqDate == null) { |
|||
throw new IllegalArgumentException("Request date is required"); |
|||
} |
|||
|
|||
if (weight == null) { |
|||
throw new IllegalArgumentException("Weight is required"); |
|||
} |
|||
|
|||
if (facilityTypeId == 5) { |
|||
if (weight < 0) { |
|||
throw new IllegalArgumentException("Weight cannot be negative"); |
|||
} |
|||
} else { |
|||
if (weight <= 0) { |
|||
throw new IllegalArgumentException("Weight must be greater than zero"); |
|||
} |
|||
} |
|||
|
|||
if (gccUserIdObj == null || usernameObj == null) { |
|||
throw new IllegalStateException("User session expired. Please login again."); |
|||
} |
|||
|
|||
// 🔴 Facility type 5 → TWO weights + weightType |
|||
if (facilityTypeId == 5) { |
|||
if (weight1 == null) { |
|||
throw new IllegalArgumentException( |
|||
"Second weight is required for GW & TC Waste facility"); |
|||
} |
|||
if (weightType == null || weightType.isBlank()) { |
|||
throw new IllegalArgumentException( |
|||
"Location (KDG / PDG) is required"); |
|||
} |
|||
} |
|||
|
|||
if (facilityTypeId == 9) { |
|||
|
|||
if (weightType == null || weightType.isBlank()) { |
|||
throw new IllegalArgumentException( |
|||
"Location (KDG / PDG) is required"); |
|||
} |
|||
} |
|||
|
|||
// 🔵 SAVE |
|||
addDetailsService.addFacility( |
|||
facilityTypeId, |
|||
zoneId, |
|||
reqDate, |
|||
username, |
|||
weight, |
|||
weight1, |
|||
weightType // ✅ PASSED |
|||
); |
|||
|
|||
return ResponseEntity.ok( |
|||
Map.of("status", "SUCCESS", "message", "Added successfully")); |
|||
|
|||
} catch (IllegalArgumentException | IllegalStateException ex) { |
|||
return ResponseEntity.badRequest().body( |
|||
Map.of("status", "ERROR", "message", ex.getMessage())); |
|||
} catch (Exception ex) { |
|||
ex.printStackTrace(); |
|||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body( |
|||
Map.of("status", "ERROR", "message", "Internal server error")); |
|||
} |
|||
} |
|||
|
|||
@GetMapping("/reports") |
|||
public ResponseEntity<?> getZoneWiseByLogin( |
|||
@RequestParam String username, |
|||
@RequestParam String fromDate, |
|||
@RequestParam String toDate) { |
|||
|
|||
List<Map<String, Object>> data = addDetailsService.getZoneWiseFacilityByLogin( |
|||
username, fromDate, toDate); |
|||
|
|||
return ResponseEntity.ok(Map.of( |
|||
"status", "SUCCESS", |
|||
"data", data)); |
|||
} |
|||
|
|||
} |
|||
@ -1,510 +0,0 @@ |
|||
package com.gcc.swm_services.swm.service; |
|||
|
|||
import java.sql.Timestamp; |
|||
import java.time.LocalDate; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
import javax.sql.DataSource; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.beans.factory.annotation.Qualifier; |
|||
import org.springframework.jdbc.core.JdbcTemplate; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
@Service |
|||
public class AddDetailsService { |
|||
|
|||
@Autowired |
|||
private JdbcTemplate jdbcTemplate; |
|||
|
|||
@Autowired |
|||
public void setDataSourcemysql(@Qualifier("mysqlSwmDataSource") DataSource dataSource) { |
|||
this.jdbcTemplate = new JdbcTemplate(dataSource); |
|||
} |
|||
|
|||
// // ---------------- SAVE ---------------- |
|||
// public void addFacility( |
|||
// int facilityTypeId, |
|||
// int zoneId, |
|||
// LocalDate reqDate, |
|||
// String createdBy, |
|||
// Double weight, |
|||
// Double weight1) { |
|||
|
|||
// String sql = """ |
|||
// INSERT INTO facilities_weight_details |
|||
// (ft_id, zone_id, req_date, cby, weight, weight_1) |
|||
// VALUES (?, ?, ?, ?, ?, ?) |
|||
// """; |
|||
|
|||
// Timestamp reqTimestamp = Timestamp.valueOf(reqDate.atStartOfDay()); |
|||
|
|||
// Double dbWeight1 = (facilityTypeId == 5) ? weight1 : null; |
|||
|
|||
// jdbcTemplate.update( |
|||
// sql, |
|||
// facilityTypeId, |
|||
// zoneId, |
|||
// reqTimestamp, |
|||
// createdBy, |
|||
// weight, |
|||
// dbWeight1); |
|||
// } |
|||
|
|||
// public void addFacility( |
|||
// int facilityTypeId, |
|||
// int zoneId, |
|||
// LocalDate reqDate, |
|||
// String createdBy, |
|||
// Double weight, |
|||
// Double weight1, |
|||
// String weightType) { |
|||
|
|||
// String sql = """ |
|||
// INSERT INTO facilities_weight_details |
|||
// (ft_id, zone_id, req_date, cby, weight, weight_1, weight_type) |
|||
// VALUES (?, ?, ?, ?, ?, ?, ?) |
|||
// """; |
|||
|
|||
// Timestamp reqTimestamp = Timestamp.valueOf(reqDate.atStartOfDay()); |
|||
|
|||
// Double dbWeight1 = (facilityTypeId == 5) ? weight1 : null; |
|||
// // ✅ weight_type allowed for GW & TC (5) AND PBC / C&D (9) |
|||
// String dbWeightType = (facilityTypeId == 5 || facilityTypeId == 9) |
|||
// ? weightType |
|||
// : null; |
|||
|
|||
// jdbcTemplate.update( |
|||
// sql, |
|||
// facilityTypeId, |
|||
// zoneId, |
|||
// reqTimestamp, |
|||
// createdBy, |
|||
// weight, |
|||
// dbWeight1, |
|||
// dbWeightType); |
|||
// } |
|||
|
|||
private Integer getExistingRecordId( |
|||
int facilityTypeId, |
|||
int zoneId, |
|||
LocalDate reqDate) { |
|||
|
|||
String sql = """ |
|||
SELECT fid |
|||
FROM facilities_weight_details |
|||
WHERE ft_id = ? |
|||
AND zone_id = ? |
|||
AND DATE(req_date) = ? |
|||
AND is_delete = 0 |
|||
LIMIT 1 |
|||
"""; |
|||
|
|||
List<Integer> ids = jdbcTemplate.query( |
|||
sql, |
|||
ps -> { |
|||
ps.setInt(1, facilityTypeId); |
|||
ps.setInt(2, zoneId); |
|||
ps.setDate(3, java.sql.Date.valueOf(reqDate)); |
|||
}, |
|||
(rs, rowNum) -> rs.getInt("fid")); |
|||
|
|||
return ids.isEmpty() ? null : ids.get(0); |
|||
} |
|||
|
|||
public void addFacility( |
|||
int facilityTypeId, |
|||
int zoneId, |
|||
LocalDate reqDate, |
|||
String officerName, |
|||
Double weight, |
|||
Double weight1, |
|||
String weightType) { |
|||
|
|||
Timestamp reqTimestamp = Timestamp.valueOf(reqDate.atStartOfDay()); |
|||
|
|||
Double dbWeight1 = (facilityTypeId == 5) ? weight1 : null; |
|||
String dbWeightType = (facilityTypeId == 5 || facilityTypeId == 9) |
|||
? weightType |
|||
: null; |
|||
|
|||
Integer existingId = getExistingRecordId( |
|||
facilityTypeId, zoneId, reqDate); |
|||
|
|||
if (existingId == null) { |
|||
// 🟢 INSERT |
|||
String insertSql = """ |
|||
INSERT INTO facilities_weight_details |
|||
(ft_id, zone_id, req_date, weight, weight_1, weight_type, |
|||
cby, cdate, is_active, is_delete) |
|||
VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), 1, 0) |
|||
"""; |
|||
|
|||
jdbcTemplate.update( |
|||
insertSql, |
|||
facilityTypeId, |
|||
zoneId, |
|||
reqTimestamp, |
|||
weight, |
|||
dbWeight1, |
|||
dbWeightType, |
|||
officerName); |
|||
|
|||
} else { |
|||
// 🔵 UPDATE |
|||
String updateSql = """ |
|||
UPDATE facilities_weight_details |
|||
SET weight = ?, |
|||
weight_1 = ?, |
|||
weight_type = ?, |
|||
updated_by = ?, |
|||
updated_date = NOW() |
|||
WHERE fid = ? |
|||
"""; |
|||
|
|||
jdbcTemplate.update( |
|||
updateSql, |
|||
weight, |
|||
dbWeight1, |
|||
dbWeightType, |
|||
officerName, |
|||
existingId); |
|||
} |
|||
} |
|||
|
|||
// ---------------- DPID ---------------- |
|||
public int getDpidByGccUserId(int gccUserId) { |
|||
|
|||
String sql = """ |
|||
SELECT dpid |
|||
FROM department_login |
|||
WHERE gcc_user_id = ? |
|||
AND is_active = 1 |
|||
AND is_delete = 0 |
|||
"""; |
|||
|
|||
List<Integer> list = jdbcTemplate.queryForList(sql, Integer.class, gccUserId); |
|||
|
|||
if (list.isEmpty()) { |
|||
throw new IllegalArgumentException( |
|||
"Department not mapped for user id: " + gccUserId); |
|||
} |
|||
|
|||
return list.get(0); |
|||
} |
|||
|
|||
// ---------------- FACILITY TYPE ---------------- |
|||
public int getFacilityTypeIdByDpid(int dpid) { |
|||
|
|||
String sql = """ |
|||
SELECT ft.ft_id |
|||
FROM department_login dl |
|||
JOIN facilities_type ft |
|||
ON LOWER(REPLACE(REPLACE(dl.department_name,'swm_',''),'_',' ')) |
|||
LIKE CONCAT('%', LOWER(ft.facilities_name), '%') |
|||
WHERE dl.dpid = ? |
|||
AND dl.is_active = 1 |
|||
AND dl.is_delete = 0 |
|||
AND ft.is_active = 1 |
|||
AND ft.is_delete = 0 |
|||
"""; |
|||
|
|||
List<Integer> list = jdbcTemplate.queryForList(sql, Integer.class, dpid); |
|||
|
|||
if (list.isEmpty()) { |
|||
throw new IllegalArgumentException( |
|||
"Facility type not mapped for department id: " + dpid); |
|||
} |
|||
|
|||
return list.get(0); |
|||
} |
|||
|
|||
public List<Map<String, Object>> getZoneTargetPercentage( |
|||
String fromDate, String toDate) { |
|||
|
|||
String sql = """ |
|||
SELECT |
|||
t.zone, |
|||
t.facility, |
|||
t.target, |
|||
COALESCE(a.achieved, 0) AS achieved, |
|||
ROUND( |
|||
CASE |
|||
WHEN t.target = 0 AND COALESCE(a.achieved, 0) > 0 THEN 100 |
|||
WHEN t.target = 0 THEN 0 |
|||
ELSE LEAST((COALESCE(a.achieved, 0) / t.target) * 100, 100) |
|||
END, |
|||
2 |
|||
) AS percentage |
|||
FROM ( |
|||
SELECT zone, 1 AS ft_id, 'MCC' AS facility, mcc AS target |
|||
FROM zonewise_target WHERE is_active = 1 AND is_delete = 0 |
|||
|
|||
UNION ALL |
|||
SELECT zone, 2, 'Windrow', windrow FROM zonewise_target |
|||
WHERE is_active = 1 AND is_delete = 0 |
|||
|
|||
UNION ALL |
|||
SELECT zone, 3, 'Bio-CNG', bio_cng FROM zonewise_target |
|||
WHERE is_active = 1 AND is_delete = 0 |
|||
|
|||
UNION ALL |
|||
SELECT zone, 4, 'Bio-GAS', bio_gas FROM zonewise_target |
|||
WHERE is_active = 1 AND is_delete = 0 |
|||
|
|||
UNION ALL |
|||
SELECT zone, 5, 'GW & TC Waste', gw_tc_waste FROM zonewise_target |
|||
WHERE is_active = 1 AND is_delete = 0 |
|||
|
|||
UNION ALL |
|||
SELECT zone, 6, 'MRF OR RRC', mrf_mrr FROM zonewise_target |
|||
WHERE is_active = 1 AND is_delete = 0 |
|||
|
|||
UNION ALL |
|||
SELECT zone, 7, 'Incinerator', incinerator FROM zonewise_target |
|||
WHERE is_active = 1 AND is_delete = 0 |
|||
|
|||
UNION ALL |
|||
SELECT zone, 8, 'Plasting Baling Centre', plasting_baling_centre |
|||
FROM zonewise_target WHERE is_active = 1 AND is_delete = 0 |
|||
) t |
|||
LEFT JOIN ( |
|||
SELECT |
|||
fwd.zone_id AS zone, |
|||
fwd.ft_id, |
|||
SUM( |
|||
CASE |
|||
WHEN fwd.ft_id = 5 |
|||
THEN COALESCE(fwd.weight, 0) |
|||
+ COALESCE(fwd.weight_1, 0) |
|||
ELSE |
|||
COALESCE(fwd.weight, 0) |
|||
END |
|||
) AS achieved |
|||
FROM facilities_weight_details fwd |
|||
WHERE fwd.is_active = 1 |
|||
AND fwd.is_delete = 0 |
|||
AND DATE(fwd.req_date) BETWEEN ? AND ? |
|||
GROUP BY fwd.zone_id, fwd.ft_id |
|||
) a |
|||
ON a.zone = t.zone |
|||
AND a.ft_id = t.ft_id |
|||
ORDER BY t.zone, t.facility |
|||
"""; |
|||
|
|||
return jdbcTemplate.queryForList(sql, fromDate, toDate); |
|||
} |
|||
|
|||
public List<Map<String, Object>> getZoneTargetPercentageForOneDay(String date) { |
|||
String sql = """ |
|||
SELECT |
|||
t.zone, |
|||
t.facility, |
|||
t.target, |
|||
COALESCE(a.achieved, 0) AS achieved, |
|||
ROUND( |
|||
CASE |
|||
WHEN t.target = 0 AND COALESCE(a.achieved, 0) > 0 THEN 100 |
|||
WHEN t.target = 0 THEN 0 |
|||
ELSE LEAST((COALESCE(a.achieved, 0) / t.target) * 100, 100) |
|||
END, |
|||
2 |
|||
) AS percentage |
|||
FROM ( |
|||
SELECT zone, 1 AS ft_id, 'MCC' AS facility, mcc AS target FROM zonewise_target WHERE is_active = 1 AND is_delete = 0 |
|||
UNION ALL SELECT zone, 2, 'Windrow', windrow FROM zonewise_target WHERE is_active = 1 AND is_delete = 0 |
|||
UNION ALL SELECT zone, 3, 'Bio-CNG', bio_cng FROM zonewise_target WHERE is_active = 1 AND is_delete = 0 |
|||
UNION ALL SELECT zone, 4, 'Bio-GAS', bio_gas FROM zonewise_target WHERE is_active = 1 AND is_delete = 0 |
|||
UNION ALL SELECT zone, 5, 'GW & TC Waste', gw_tc_waste FROM zonewise_target WHERE is_active = 1 AND is_delete = 0 |
|||
UNION ALL SELECT zone, 6, 'MRF OR RRC', mrf_mrr FROM zonewise_target WHERE is_active = 1 AND is_delete = 0 |
|||
UNION ALL SELECT zone, 7, 'Incinerator', incinerator FROM zonewise_target WHERE is_active = 1 AND is_delete = 0 |
|||
UNION ALL SELECT zone, 8, 'Plasting Baling Centre', plasting_baling_centre FROM zonewise_target WHERE is_active = 1 AND is_delete = 0 |
|||
) t |
|||
LEFT JOIN ( |
|||
SELECT |
|||
fwd.zone_id AS zone, |
|||
fwd.ft_id, |
|||
SUM( |
|||
CASE |
|||
WHEN fwd.ft_id = 5 |
|||
THEN COALESCE(fwd.weight, 0) + COALESCE(fwd.weight_1, 0) |
|||
ELSE COALESCE(fwd.weight, 0) |
|||
END |
|||
) AS achieved |
|||
FROM facilities_weight_details fwd |
|||
WHERE fwd.is_active = 1 |
|||
AND fwd.is_delete = 0 |
|||
AND DATE(fwd.req_date) = ? -- **single‑date filter** |
|||
GROUP BY fwd.zone_id, fwd.ft_id |
|||
) a |
|||
ON a.zone = t.zone |
|||
AND a.ft_id = t.ft_id |
|||
ORDER BY t.zone, t.facility |
|||
"""; |
|||
// Only one parameter (the date) is bound now. |
|||
return jdbcTemplate.queryForList(sql, date); |
|||
} |
|||
|
|||
// public List<Map<String, Object>> getZoneWiseFacilityByLogin( |
|||
// String username, |
|||
// String fromDate, |
|||
// String toDate) { |
|||
|
|||
// String sql = """ |
|||
// SELECT |
|||
// t.zone, |
|||
// t.facility, |
|||
// t.target, |
|||
// COALESCE(a.achieved, 0) AS achieved, |
|||
// ROUND( |
|||
// CASE |
|||
// WHEN t.target = 0 AND COALESCE(a.achieved, 0) > 0 THEN 100 |
|||
// WHEN t.target = 0 AND COALESCE(a.achieved, 0) = 0 THEN 0 |
|||
// ELSE LEAST((COALESCE(a.achieved, 0) / t.target) * 100, 100) |
|||
// END, 2 |
|||
// ) AS percentage |
|||
// FROM ( |
|||
// /* 🔹 TARGET – ONLY FACILITY FROM LOGIN */ |
|||
// SELECT |
|||
// zt.zone, |
|||
// ft.facilities_name AS facility, |
|||
// CASE ft.ft_id |
|||
// WHEN 1 THEN zt.mcc |
|||
// WHEN 2 THEN zt.windrow |
|||
// WHEN 3 THEN zt.bio_cng |
|||
// WHEN 4 THEN zt.bio_gas |
|||
// WHEN 5 THEN zt.gw_tc_waste |
|||
// WHEN 6 THEN zt.mrf_mrr |
|||
// WHEN 7 THEN zt.incinerator |
|||
// WHEN 8 THEN zt.plasting_baling_centre |
|||
// ELSE 0 |
|||
// END AS target |
|||
|
|||
// FROM department_login dl |
|||
// JOIN facilities_type ft ON ft.ft_id = dl.dpid |
|||
// JOIN zonewise_target zt ON zt.is_active = 1 AND zt.is_delete = 0 |
|||
// WHERE dl.user_name = ? |
|||
// ) t |
|||
// LEFT JOIN ( |
|||
// /* 🔹 ACHIEVED – SAME FT_ID + LOGIN */ |
|||
// SELECT |
|||
// fwd.zone_id AS zone, |
|||
// ft.facilities_name AS facility, |
|||
// SUM(COALESCE(fwd.weight, 0) + COALESCE(fwd.weight_1, 0)) AS achieved |
|||
// FROM facilities_weight_details fwd |
|||
// JOIN facilities_type ft ON ft.ft_id = fwd.ft_id |
|||
// WHERE fwd.is_active = 1 |
|||
// AND fwd.is_delete = 0 |
|||
// AND fwd.cby = ? |
|||
// AND DATE(fwd.req_date) BETWEEN ? AND ? |
|||
// GROUP BY fwd.zone_id, ft.facilities_name |
|||
// ) a |
|||
// ON a.zone = t.zone AND a.facility = t.facility |
|||
// ORDER BY t.zone |
|||
// """; |
|||
|
|||
// return jdbcTemplate.queryForList( |
|||
// sql, |
|||
// username, |
|||
// username, |
|||
// fromDate, |
|||
// toDate); |
|||
// } |
|||
|
|||
private String normalizeDate(String date) { |
|||
|
|||
if (date == null || date.isBlank()) { |
|||
return date; |
|||
} |
|||
|
|||
// If browser format yyyy-MM-dd → convert to dd-MM-yyyy |
|||
if (date.matches("\\d{4}-\\d{2}-\\d{2}")) { |
|||
String[] p = date.split("-"); |
|||
return p[2] + "-" + p[1] + "-" + p[0]; |
|||
} |
|||
|
|||
// Already dd-MM-yyyy |
|||
return date; |
|||
} |
|||
|
|||
public List<Map<String, Object>> getZoneWiseFacilityByLogin( |
|||
String username, |
|||
String fromDate, |
|||
String toDate) { |
|||
|
|||
// 🔥 Normalize date format (supports yyyy-MM-dd and dd-MM-yyyy) |
|||
fromDate = normalizeDate(fromDate); |
|||
toDate = normalizeDate(toDate); |
|||
|
|||
String sql = """ |
|||
SELECT |
|||
t.zone, |
|||
t.facility, |
|||
t.target, |
|||
COALESCE(a.achieved, 0) AS achieved, |
|||
ROUND( |
|||
CASE |
|||
WHEN t.target = 0 AND COALESCE(a.achieved, 0) > 0 THEN 100 |
|||
WHEN t.target = 0 AND COALESCE(a.achieved, 0) = 0 THEN 0 |
|||
ELSE LEAST((COALESCE(a.achieved, 0) / t.target) * 100, 100) |
|||
END, 2 |
|||
) AS percentage |
|||
FROM ( |
|||
/* TARGET */ |
|||
SELECT |
|||
zt.zone, |
|||
ft.ft_id, |
|||
ft.facilities_name AS facility, |
|||
CASE ft.ft_id |
|||
WHEN 1 THEN zt.mcc |
|||
WHEN 2 THEN zt.windrow |
|||
WHEN 3 THEN zt.bio_cng |
|||
WHEN 4 THEN zt.bio_gas |
|||
WHEN 5 THEN zt.gw_tc_waste |
|||
WHEN 6 THEN zt.mrf_mrr |
|||
WHEN 7 THEN zt.incinerator |
|||
WHEN 8 THEN zt.plasting_baling_centre |
|||
ELSE 0 |
|||
END AS target |
|||
FROM department_login dl |
|||
JOIN facilities_type ft ON ft.ft_id = dl.dpid |
|||
JOIN zonewise_target zt |
|||
ON zt.is_active = 1 |
|||
AND zt.is_delete = 0 |
|||
WHERE TRIM(dl.user_name) = ? |
|||
) t |
|||
LEFT JOIN ( |
|||
/* ACHIEVED */ |
|||
SELECT |
|||
fwd.zone_id AS zone, |
|||
fwd.ft_id, |
|||
SUM(COALESCE(fwd.weight, 0) + COALESCE(fwd.weight_1, 0)) AS achieved |
|||
FROM facilities_weight_details fwd |
|||
WHERE fwd.is_active = 1 |
|||
AND fwd.is_delete = 0 |
|||
AND TRIM(fwd.cby) = ? |
|||
AND fwd.req_date >= STR_TO_DATE(CONCAT(?, ' 00:00:00'), '%d-%m-%Y %H:%i:%s') |
|||
AND fwd.req_date <= STR_TO_DATE(CONCAT(?, ' 23:59:59'), '%d-%m-%Y %H:%i:%s') |
|||
AND fwd.ft_id = ( |
|||
SELECT dpid |
|||
FROM department_login |
|||
WHERE TRIM(user_name) = ? |
|||
) |
|||
GROUP BY fwd.zone_id, fwd.ft_id |
|||
) a |
|||
ON a.zone = t.zone |
|||
AND a.ft_id = t.ft_id |
|||
ORDER BY t.zone |
|||
"""; |
|||
|
|||
return jdbcTemplate.queryForList( |
|||
sql, |
|||
username, |
|||
username, |
|||
fromDate, |
|||
toDate, |
|||
username); |
|||
} |
|||
|
|||
} |
|||
@ -1,37 +0,0 @@ |
|||
package com.gcc.swm_services.swm.service; |
|||
|
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
import javax.sql.DataSource; |
|||
|
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.beans.factory.annotation.Qualifier; |
|||
import org.springframework.jdbc.core.JdbcTemplate; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.web.client.RestTemplate; |
|||
|
|||
import com.fasterxml.jackson.databind.ObjectMapper; |
|||
|
|||
@Service |
|||
public class DropDownService { |
|||
|
|||
@Autowired |
|||
private JdbcTemplate jdbcTemplate; |
|||
|
|||
@Autowired |
|||
public void setDataSourcemysql(@Qualifier("mysqlSwmDataSource") DataSource dataSource) { |
|||
this.jdbcTemplate = new JdbcTemplate(dataSource); |
|||
} |
|||
|
|||
public List<Map<String, Object>> getFacilitiesTypeList() { |
|||
String sql = " SELECT * FROM facilities_type where is_active = '1' and is_delete ='0' "; |
|||
return jdbcTemplate.queryForList(sql); |
|||
} |
|||
|
|||
public List<Map<String, Object>> getZonesList() { |
|||
String sql = " SELECT * FROM zones where is_active = '1' and is_delete ='0' "; |
|||
return jdbcTemplate.queryForList(sql); |
|||
} |
|||
|
|||
} |
|||
@ -1,5 +1,5 @@ |
|||
assets.base-url=/assets/ |
|||
|
|||
fileBaseUrl=http://localhost:8060 |
|||
fileBaseUrl=http://localhost:8061 |
|||
|
|||
#fileBaseUrl = D:/Projects/Election_Project/election_v1/gcc_election_uploads |
|||
@ -1,3 +1,3 @@ |
|||
assets.base-url=/swm/assets/ |
|||
assets.base-url=/flagpoles/assets/ |
|||
|
|||
fileBaseUrl=https://gccservices.in/files |
|||
fileBaseUrl=https://gccservices.in/flagpoles |
|||
@ -1,57 +1,63 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en" dir=""> |
|||
<html xmlns:th="http://www.thymeleaf.org"> |
|||
|
|||
<head th:replace="~{fragments/modules/base/head :: head}"></head> |
|||
<body> |
|||
<!--[if lt IE 8]> |
|||
|
|||
<body> |
|||
<!--[if lt IE 8]> |
|||
<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> |
|||
<![endif]--> |
|||
|
|||
<div class="auth-wrapper"> |
|||
<div class="container-fluid h-100"> |
|||
<div class="row flex-row h-100 bg-white"> |
|||
<div class="col-xl-6 col-lg-6 col-md-5 p-0 d-md-block d-lg-block d-sm-none d-none"> |
|||
<div class="lavalite-bg authentication-form mx-auto text-center"> |
|||
<div class="logo-centered" style="padding-top: 30px;"></div> |
|||
<img src="images/403.png" width="90%"/> |
|||
</div> |
|||
</div> |
|||
<div class="col-xl-6 col-lg-6 col-md-7 my-auto p-0"> |
|||
<div class="authentication-form mx-auto text-center"> |
|||
<div class="logo-centered"> |
|||
<a href="/"><img src="images/logo.png" alt="Greater Chennai Corporation" class="header-brand-img" width="100%"></a> |
|||
</div> |
|||
<h3>Greater Chennai Corporation</h3> |
|||
<!-- Content --> |
|||
<div class="flex-grow-1 d-flex align-items-center p-5 bg-body-light"> |
|||
<div class="w-100"> |
|||
<p class="text-danger fs-4 fw-bold text-uppercase mb-2" th:utext="${errorStatus}"> |
|||
403 Error |
|||
</p> |
|||
<h1 class="fw-bold mb-2" th:utext="${errorError}"> |
|||
403 - Access Denied |
|||
</h1> |
|||
<p class="fs-4 fw-medium text-muted mb-5" th:utext="${errorMessage}"> |
|||
Oops, You don`t have permission to access this page. |
|||
</p> |
|||
<a class="btn btn-lg btn-alt-danger" href="#403" onclick="return goBack();"> |
|||
<i class="fa fa-arrow-left opacity-50 me-1"></i> Back |
|||
</a> |
|||
</div> |
|||
</div> |
|||
<!-- END Content --> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="auth-wrapper"> |
|||
<div class="container-fluid h-100"> |
|||
<div class="row flex-row h-100 bg-white"> |
|||
<div class="col-xl-6 col-lg-6 col-md-5 p-0 d-md-block d-lg-block d-sm-none d-none"> |
|||
<div class="lavalite-bg authentication-form mx-auto text-center"> |
|||
<div class="logo-centered" style="padding-top: 30px;"></div> |
|||
<img src="images/403.png" width="90%" /> |
|||
</div> |
|||
</div> |
|||
<div class="col-xl-6 col-lg-6 col-md-7 my-auto p-0"> |
|||
<div class="authentication-form mx-auto text-center"> |
|||
<div class="logo-centered"> |
|||
<a href="/"><img src="images/logo.png" alt="Greater Chennai Corporation" class="header-brand-img" |
|||
width="100%"></a> |
|||
</div> |
|||
<h3>Greater Chennai Corporation |
|||
Flagpoles Officer Login |
|||
</h3> |
|||
<!-- Content --> |
|||
<div class="flex-grow-1 d-flex align-items-center p-5 bg-body-light"> |
|||
<div class="w-100"> |
|||
<p class="text-danger fs-4 fw-bold text-uppercase mb-2" th:utext="${errorStatus}"> |
|||
403 Error |
|||
</p> |
|||
<h1 class="fw-bold mb-2" th:utext="${errorError}"> |
|||
403 - Access Denied |
|||
</h1> |
|||
<p class="fs-4 fw-medium text-muted mb-5" th:utext="${errorMessage}"> |
|||
Oops, You don`t have permission to access this page. |
|||
</p> |
|||
<a class="btn btn-lg btn-alt-danger" href="#403" onclick="return goBack();"> |
|||
<i class="fa fa-arrow-left opacity-50 me-1"></i> Back |
|||
</a> |
|||
</div> |
|||
</div> |
|||
<!-- END Content --> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script th:replace="~{fragments/modules/base/script :: script}"></script> |
|||
<script> |
|||
function goBack() { |
|||
history.go(-1); // This will go back one step in the browser's history |
|||
return false; // Prevent the default link behavior |
|||
} |
|||
</script> |
|||
</body> |
|||
|
|||
<script th:replace="~{fragments/modules/base/script :: script}"></script> |
|||
<script> |
|||
function goBack() { |
|||
history.go(-1); // This will go back one step in the browser's history |
|||
return false; // Prevent the default link behavior |
|||
} |
|||
</script> |
|||
</body> |
|||
</html> |
|||
@ -1,5 +1,5 @@ |
|||
<footer class="footer"> |
|||
<form id="logout-form" th:action="@{/swm/logout}" method="post" style="display: none;"></form> |
|||
<form id="logout-form" th:action="@{/flagpoles/logout}" method="post" style="display: none;"></form> |
|||
<div class="w-100 clearfix text-center"> |
|||
<span class="text-center">Copyright © Greater Chennai Corporation | All rights reserved</span> |
|||
<!-- <span class="float-none float-sm-right mt-1 mt-sm-0 text-center">Coded By BonTon Softwares Pvt Ltd</span> --> |
|||
|
|||
@ -0,0 +1,930 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en" xmlns:th="http://www.thymeleaf.org"> |
|||
|
|||
<head th:replace="~{fragments/modules/base/head :: head}"></head> |
|||
<style> |
|||
.width1 { |
|||
width: 120px; |
|||
} |
|||
|
|||
.width2 { |
|||
width: 150px; |
|||
} |
|||
|
|||
.modal-label { |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.modal-value { |
|||
color: #444; |
|||
} |
|||
|
|||
.modal-section-title { |
|||
font-size: 1.2rem; |
|||
font-weight: bold; |
|||
margin-top: 20px; |
|||
margin-bottom: 10px; |
|||
border-bottom: 2px solid #dee2e6; |
|||
padding-bottom: 5px; |
|||
} |
|||
|
|||
|
|||
.modal-title-big { |
|||
font-size: 20px; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
.modal-subtext { |
|||
color: #b4c5d3; |
|||
font-size: 13px; |
|||
} |
|||
|
|||
.card-section { |
|||
background: white; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
margin-bottom: 25px; |
|||
border: 1px solid #eee; |
|||
} |
|||
|
|||
.section-title { |
|||
font-weight: 700; |
|||
color: #333; |
|||
margin-bottom: 15px; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.label-text { |
|||
font-size: 13px; |
|||
color: #6c757d; |
|||
} |
|||
|
|||
.value-text { |
|||
font-size: 15px; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.info-block { |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
|
|||
.badge-status { |
|||
background: #ffd9b3; |
|||
color: #a65c00; |
|||
padding: 6px 10px; |
|||
border-radius: 5px; |
|||
font-size: 13px; |
|||
|
|||
} |
|||
|
|||
.btn-big { |
|||
padding: 12px 25px; |
|||
border-radius: 8px; |
|||
width: 200px; |
|||
} |
|||
|
|||
.rdo-box { |
|||
border: 1px solid #eee; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
} |
|||
</style> |
|||
|
|||
<body> |
|||
|
|||
<div class="wrapper"> |
|||
<!-- header top menu Start --> |
|||
<header th:replace="~{fragments/modules/base/header :: header}"></header> |
|||
<!-- header top menu end --> |
|||
<div class="page-wrap"> |
|||
<!--=============== Left Menu side Start ================--> |
|||
<div th:replace="~{fragments/modules/base/menu :: menu}"></div> |
|||
<!--=============== Left side End ================--> |
|||
<div class="main-content"> |
|||
<div class="container-fluid"> |
|||
<div class="page-header"> |
|||
<div class="row align-items-end"> |
|||
<div class="col-lg-6"> |
|||
<div class="page-header-title"> |
|||
<i class="fa fa-list-alt bg-blue"></i> |
|||
<div class="d-inline"> |
|||
<h5>Request List</h5> |
|||
<span>Flag Pole Request List</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-6"> |
|||
<nav class="breadcrumb-container" aria-label="breadcrumb"> |
|||
<ol class="breadcrumb"> |
|||
<li class="breadcrumb-item"> |
|||
<a href="/flagpoles/index"><i class="ik ik-home"></i></a> |
|||
</li> |
|||
<li class="breadcrumb-item" aria-current="page">Flag Pole Request List</li> |
|||
<li class="breadcrumb-item active" aria-current="page">Request List</li> |
|||
</ol> |
|||
</nav> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="row mt-4"> |
|||
|
|||
<div class="col-md-12"> |
|||
<div class="card"> |
|||
<div class="card-header d-flex justify-content-between align-items-center fw-bold"> |
|||
<h3 class="mb-0">Temporary Flag Poles - Request List : <span |
|||
th:text="${officer_name}"></span></h3> |
|||
<input type="hidden" id="userName" th:value="${officer_name}"> |
|||
<input type="hidden" id="loginuserid" th:value="${LoginUserId}"> |
|||
</div> |
|||
|
|||
<div class="row mt-3 ml-2"> |
|||
<div class="col-md-3"> |
|||
<label for="startDate" class="form-label" style="font-size: medium;">From |
|||
Date:</label> |
|||
<input type="date" id="startDate" class="form-control" placeholder="Start Date"> |
|||
</div> |
|||
<div class="col-md-3"> |
|||
<label for="endDate" class="form-label" style="font-size: medium;">To |
|||
Date:</label> |
|||
<input type="date" id="endDate" class="form-control" placeholder="End Date"> |
|||
</div> |
|||
<div class="col-md-3" style="margin-top: 30px;"> |
|||
<button id="searchBtn" class="btn btn-primary">Search</button> |
|||
<button id="resetBtn" class="btn btn-secondary">Reset</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="card-body"> |
|||
<div> |
|||
<div class="row mt-2"> |
|||
|
|||
|
|||
<div class="col-xl-3 col-md-3 col-sm-12"> |
|||
<div class="card card-box p-4"> |
|||
<h6 class="text-facebook mb-20 mt-2 text-center fw-bold"><b>Total |
|||
Request</b> |
|||
</h6> |
|||
<h4 class="text-twitter fw-700 text-center" id="totalrequest"> |
|||
</h4> |
|||
</div> |
|||
</div> |
|||
<div class="col-xl-3 col-md-3 col-sm-12"> |
|||
<div class="card card-box p-4"> |
|||
<h6 class="text-facebook mb-20 mt-2 text-center"><b>Pending Decision |
|||
</b></h6> |
|||
<h4 class="text-twitter fw-700 text-center" id="pendingdecision"> |
|||
</h4> |
|||
</div> |
|||
</div> |
|||
<div class="col-xl-3 col-md-3 col-sm-12" style="display: none;"> |
|||
<div class="card card-box p-4"> |
|||
<h6 class="text-facebook mb-20 mt-2 text-center"><b>Approved</b> |
|||
</h6> |
|||
<h4 class="text-twitter fw-700 text-center" id="approved"></h4> |
|||
</div> |
|||
</div> |
|||
<div class="col-xl-3 col-md-3 col-sm-12" style="display: none;"> |
|||
<div class="card card-box p-4"> |
|||
<h6 class="text-facebook mb-20 mt-2 text-center"><b>Rejected</b> |
|||
</h6> |
|||
<h4 class="text-twitter fw-700 text-center" id="rejected"></h4> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div> |
|||
<table id="QaqcDatatable" |
|||
class="table table-striped table-bordered table-hover dataTable" |
|||
role="grid"> |
|||
<thead class="thead-dark"> |
|||
<tr role="row"> |
|||
<th class="text-center">S.No</th> |
|||
<th class="text-center no-sort">Applicant Name</th> |
|||
<th class="text-center">RequestId</th> |
|||
<th class="text-center">Zone/Ward</th> |
|||
<th class="text-center">Event Type</th> |
|||
<th class="text-center">Event Date</th> |
|||
<th class="text-center">Total Cost</th> |
|||
<th class="text-center">Status</th> |
|||
<th class="text-center">Action</th> |
|||
|
|||
</tr> |
|||
|
|||
</thead> |
|||
<tbody> |
|||
|
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
<div id="pageLoader" |
|||
style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); z-index: 9999; text-align: center;"> |
|||
<div style="position: relative; top: 50%; transform: translateY(-50%);"> |
|||
<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;"> |
|||
<span class="sr-only">Loading...</span> |
|||
</div> |
|||
<!-- Add the 'Please wait' text below the spinner --> |
|||
<p style="margin-top: 1rem; font-size: 1.2rem; color: #007bff;">Please wait...</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div th:replace="~{fragments/modules/base/app_module_menu_box :: div}"></div> |
|||
|
|||
<footer th:replace="~{fragments/modules/base/footer :: footer}"></footer> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Details Modal --> |
|||
<div class="modal fade" id="detailsModal" tabindex="-1" aria-hidden="true"> |
|||
<div class="modal-dialog modal-xl modal-dialog-scrollable"> |
|||
<div class="modal-content"> |
|||
|
|||
<div class="modal-header" style="background:#2f3e54; color:white;"> |
|||
<div> |
|||
<h4 class="modal-title-big" id="modalTitle"></h4> |
|||
<div id="modalSubTitle" class="modal-subtext"></div> |
|||
</div> |
|||
|
|||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span |
|||
aria-hidden="true">×</span></button> |
|||
</div> |
|||
|
|||
<div class="modal-body"> |
|||
|
|||
<div id="modalContent"></div> |
|||
|
|||
<div class="text-center mt-4"> |
|||
<button type="button" class="btn btn-primary btn-big" data-dismiss="modal" |
|||
style="background:#2f3e54;">Close</button> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
|
|||
<div class="modal fade" id="imagePreviewModal" tabindex="-1"> |
|||
<div class="modal-dialog modal-dialog-centered modal-lg"> |
|||
<div class="modal-content"> |
|||
<div class="modal-header"> |
|||
<h5 class="modal-title">Document Preview</h5> |
|||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button> |
|||
</div> |
|||
<div class="modal-body text-center"> |
|||
<img id="previewImage" class="img-fluid"> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
|
|||
<script th:replace="~{fragments/modules/base/script :: script}"></script> |
|||
<script type="text/javascript"> |
|||
|
|||
|
|||
let table; |
|||
|
|||
$(document).ready(function () { |
|||
loadTable(); |
|||
|
|||
$("#searchBtn").on("click", loadTable); |
|||
|
|||
$("#resetBtn").on("click", function () { |
|||
$("#startDate").val(""); |
|||
$("#endDate").val(""); |
|||
loadTable(); |
|||
}); |
|||
}); |
|||
|
|||
$(document).on("click", ".zoom-img", function () { |
|||
|
|||
const src = $(this).data("src"); |
|||
|
|||
$("#previewImage").attr("src", src); |
|||
|
|||
$("#imagePreviewModal").modal("show"); |
|||
}); |
|||
|
|||
|
|||
// function loadTable() { |
|||
|
|||
// let officer_name = $("#userName").val(); |
|||
// let startDate = $("#startDate").val(); |
|||
// let endDate = $("#endDate").val(); |
|||
|
|||
// if ($.fn.DataTable.isDataTable('#QaqcDatatable')) { |
|||
// $('#QaqcDatatable').DataTable().clear().destroy(); |
|||
// } |
|||
|
|||
// table = $('#QaqcDatatable').DataTable({ |
|||
// processing: true, |
|||
// responsive: true, |
|||
// scrollY: '50vh', |
|||
// dom: 'Bfrtip', // 🔥 ENABLE BUTTONS |
|||
|
|||
// ajax: { |
|||
// url: "/gcc/api/flagpoleregistration/getAllDetails", |
|||
// type: "GET", |
|||
// data: { |
|||
// userLogin: officer_name, |
|||
// startDate: startDate, |
|||
// endDate: endDate |
|||
// }, |
|||
// dataSrc: function (json) { |
|||
|
|||
// const data = json.data || []; |
|||
|
|||
// // 🔹 Dashboard counts |
|||
// let pending = 0, approved = 0, rejected = 0; |
|||
|
|||
// data.forEach(r => { |
|||
// if (!r.rdo_status) pending++; |
|||
// else if (r.rdo_status === 'APPROVED') approved++; |
|||
// else if (r.rdo_status === 'REJECTED') rejected++; |
|||
// }); |
|||
|
|||
// $("#totalrequest").text(data.length); |
|||
// $("#pendingdecision").text(pending); |
|||
// $("#approved").text(approved); |
|||
// $("#rejected").text(rejected); |
|||
|
|||
// return data; // ✅ already unique per refid |
|||
// } |
|||
// }, |
|||
|
|||
// columns: [ |
|||
// { |
|||
// data: null, |
|||
// className: "text-center", |
|||
// render: (d, t, r, m) => m.row + 1 |
|||
// }, |
|||
// { |
|||
// data: "applicant_name", |
|||
// className: "text-center" |
|||
// }, |
|||
// { |
|||
// data: "refid", |
|||
// className: "text-center" |
|||
// }, |
|||
// { |
|||
// data: null, |
|||
// className: "text-center", |
|||
// render: row => { |
|||
// if (!row.streets || row.streets.length === 0) return "-"; |
|||
// return `${row.streets[0].zone} / ${row.streets[0].ward}`; |
|||
// } |
|||
// }, |
|||
// { |
|||
// data: "event_name", |
|||
// className: "text-center" |
|||
// }, |
|||
// { |
|||
// data: "event_date", |
|||
// className: "text-center", |
|||
// render: d => new Date(d).toLocaleDateString("en-GB") |
|||
// }, |
|||
// { |
|||
// data: "total_cost", |
|||
// className: "text-center", |
|||
// render: d => d.toLocaleString("en-GB") |
|||
// }, |
|||
// { |
|||
// data: "rdo_status", |
|||
// className: "text-center", |
|||
// render: d => { |
|||
// if (!d) |
|||
// return `<span class="badge bg-warning text-dark">Pending</span>`; |
|||
// if (d === 'APPROVED') |
|||
// return `<span class="badge bg-success">Approved</span>`; |
|||
// return `<span class="badge bg-danger">Rejected</span>`; |
|||
// } |
|||
// }, |
|||
// { |
|||
// data: null, |
|||
// className: "text-center", |
|||
// render: row => |
|||
// `<button class="btn btn-primary btn-sm viewBtn" |
|||
// data-refid="${row.refid}"> |
|||
// View |
|||
// </button>` |
|||
// } |
|||
// ] |
|||
// }); |
|||
// } |
|||
|
|||
|
|||
|
|||
function loadTable() { |
|||
|
|||
let gccUserId = $("#loginuserid").val(); |
|||
let startDate = $("#startDate").val(); |
|||
let endDate = $("#endDate").val(); |
|||
|
|||
console.log("gccuserid:" + gccUserId); |
|||
|
|||
if ($.fn.DataTable.isDataTable('#QaqcDatatable')) { |
|||
$('#QaqcDatatable').DataTable().clear().destroy(); |
|||
} |
|||
|
|||
table = $('#QaqcDatatable').DataTable({ |
|||
processing: true, |
|||
responsive: true, |
|||
scrollY: '50vh', |
|||
dom: 'Bfrtip', |
|||
|
|||
ajax: { |
|||
url: "/flagpoles/api/flagpoleregistration/getAllDetails", |
|||
type: "GET", |
|||
data: { |
|||
gccUserId: gccUserId, |
|||
startDate: startDate, |
|||
endDate: endDate |
|||
}, |
|||
dataSrc: function (json) { |
|||
|
|||
const data = json.data || []; |
|||
|
|||
let pending = 0, approved = 0, rejected = 0; |
|||
|
|||
// data.forEach(r => { |
|||
// if (!r.rdo_status) pending++; |
|||
// else if (r.rdo_status === 'APPROVED') approved++; |
|||
// else if (r.rdo_status === 'REJECTED') rejected++; |
|||
// }); |
|||
|
|||
data.forEach(r => { |
|||
|
|||
const status = r.final_status; |
|||
|
|||
if (!status) pending++; |
|||
else if (status === 'APPROVED') approved++; |
|||
else if (status === 'REJECTED') rejected++; |
|||
}); |
|||
|
|||
|
|||
|
|||
$("#totalrequest").text(data.length); |
|||
$("#pendingdecision").text(pending); |
|||
$("#approved").text(approved); |
|||
$("#rejected").text(rejected); |
|||
|
|||
return data; |
|||
} |
|||
}, |
|||
|
|||
columns: [ |
|||
{ data: null, render: (d, t, r, m) => m.row + 1, className: "text-center" }, |
|||
{ data: "applicant_name", className: "text-center" }, |
|||
{ data: "refid", className: "text-center" }, |
|||
{ |
|||
data: null, |
|||
className: "text-center", |
|||
render: r => |
|||
r.streets?.length |
|||
? `${r.streets[0].zone} / ${r.streets[0].ward}` |
|||
: "-" |
|||
}, |
|||
{ data: "event_name", className: "text-center" }, |
|||
{ |
|||
data: "event_date", |
|||
className: "text-center", |
|||
render: d => new Date(d).toLocaleDateString("en-GB") |
|||
}, |
|||
{ |
|||
data: "total_cost", |
|||
className: "text-center", |
|||
render: d => d.toLocaleString("en-GB") |
|||
}, |
|||
// { |
|||
// data: "rdo_status", |
|||
// className: "text-center", |
|||
// render: d => |
|||
// !d |
|||
// ? `<span class="badge bg-warning text-dark">Pending</span>` |
|||
// : d === 'APPROVED' |
|||
// ? `<span class="badge bg-success">Approved</span>` |
|||
// : `<span class="badge bg-danger">Rejected</span>` |
|||
// }, |
|||
{ |
|||
data: null, |
|||
className: "text-center", |
|||
render: r => { |
|||
|
|||
const status = r.final_status; |
|||
|
|||
if (!status) |
|||
return `<span class="badge bg-warning text-dark">Pending</span>`; |
|||
else if (status === 'APPROVED') |
|||
return `<span class="badge bg-success">Approved</span>`; |
|||
else |
|||
return `<span class="badge bg-danger">Rejected</span>`; |
|||
} |
|||
}, |
|||
|
|||
{ |
|||
data: null, |
|||
className: "text-center", |
|||
render: r => |
|||
`<button class="btn btn-primary btn-sm viewBtn" |
|||
data-refid="${r.refid}"> |
|||
View |
|||
</button>` |
|||
} |
|||
] |
|||
}); |
|||
} |
|||
|
|||
|
|||
|
|||
// 🔹 View button action |
|||
|
|||
// Destroy previous instance if exists |
|||
if ($.fn.DataTable.isDataTable('#QaqcDatatable')) { |
|||
$('#QaqcDatatable').DataTable().clear().destroy(); |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
// $('#QaqcDatatable').on("click", ".viewBtn", function () { |
|||
|
|||
// // 🔹 Get full row data from DataTable |
|||
// const record = table.row($(this).closest('tr')).data(); |
|||
|
|||
// if (!record) { |
|||
// alert("No details found"); |
|||
// return; |
|||
// } |
|||
|
|||
// populateModal(record); |
|||
// $("#detailsModal").modal("show"); |
|||
// }); |
|||
|
|||
$('#QaqcDatatable').on("click", ".viewBtn", function () { |
|||
|
|||
let tr = $(this).closest('tr'); |
|||
|
|||
// ✅ Handle responsive child rows (mobile view) |
|||
if (tr.hasClass('child')) { |
|||
tr = tr.prev(); |
|||
} |
|||
|
|||
// 🔹 Get full row data from DataTable |
|||
const record = table.row(tr).data(); |
|||
|
|||
if (!record) { |
|||
alert("No details found"); |
|||
return; |
|||
} |
|||
|
|||
populateModal(record); |
|||
$("#detailsModal").modal("show"); |
|||
}); |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
function populateModal(record) { |
|||
|
|||
// HEADER |
|||
$("#modalTitle").html(`Application Details - ${record.applicant_name}`); |
|||
$("#modalSubTitle").html( |
|||
`Ref ID: ${record.refid} - ${record.streets.length} Streets` |
|||
); |
|||
|
|||
$("#detailsModal").data("refid", record.refid); |
|||
|
|||
// 🔹 Streets |
|||
let streetHtml = ""; |
|||
|
|||
record.streets.forEach((s, i) => { |
|||
streetHtml += ` |
|||
<div class="card-section"> |
|||
<div class="section-title">Street ${i + 1}</div> |
|||
|
|||
<div class="row mb-2"> |
|||
<div class="col-md-4"> |
|||
<div class="label-text">Street Name</div> |
|||
<div class="value-text">${s.street_name}</div> |
|||
</div> |
|||
<div class="col-md-4"> |
|||
<div class="label-text">Zone</div> |
|||
<div class="value-text">${s.zone}</div> |
|||
</div> |
|||
<div class="col-md-4"> |
|||
<div class="label-text">Ward</div> |
|||
<div class="value-text">${s.ward}</div> |
|||
</div> |
|||
<div class="col-md-4"> |
|||
<div class="label-text">No. of Poles</div> |
|||
<div class="value-text">${s.no_of_poles}</div> |
|||
</div> |
|||
|
|||
|
|||
<div class="col-md-4"> |
|||
<div class="label-text">Height</div> |
|||
<div class="value-text">${s.height}</div> |
|||
</div> |
|||
|
|||
<div class="col-md-4"> |
|||
<div class="label-text">Flag Material</div> |
|||
<div class="value-text">${s.flag_material}</div> |
|||
</div> |
|||
|
|||
<div class="col-md-4"> |
|||
<div class="label-text">Pole Material</div> |
|||
<div class="value-text">${s.pole_material}</div> |
|||
</div> |
|||
|
|||
</div> |
|||
|
|||
|
|||
</div>`; |
|||
}); |
|||
|
|||
let historyHtml = ""; |
|||
|
|||
if (record.history && record.history.length > 0) { |
|||
|
|||
historyHtml += ` |
|||
<div class="card-section"> |
|||
<div class="section-title">Application History</div> |
|||
`; |
|||
|
|||
record.history.forEach((h, index) => { |
|||
historyHtml += ` |
|||
<div class="row mb-2 border-bottom pb-2"> |
|||
<div class="col-md-3"> |
|||
<div class="label-text">Action Date</div> |
|||
<div class="value-text">${h.action_date}</div> |
|||
</div> |
|||
|
|||
<div class="col-md-3"> |
|||
<div class="label-text">Department</div> |
|||
<div class="value-text">${h.department_name}</div> |
|||
</div> |
|||
|
|||
|
|||
|
|||
<div class="col-md-3"> |
|||
<div class="label-text">Status</div> |
|||
<div class="value-text">${h.status}</div> |
|||
</div> |
|||
|
|||
|
|||
${h.remarks ? ` |
|||
<div class="col-md-3"> |
|||
<div class="label-text">Remarks</div> |
|||
<div class="value-text">${h.remarks}</div> |
|||
</div>` : ""} |
|||
</div> |
|||
`; |
|||
}); |
|||
|
|||
historyHtml += `</div>`; |
|||
} |
|||
|
|||
let decisionHtml = ""; |
|||
|
|||
// 🔹 Show decision buttons ONLY if pending |
|||
if (!record.final_status) { |
|||
decisionHtml = ` |
|||
<div class="rdo-box"> |
|||
<div class="section-title">Department Decision</div> |
|||
|
|||
<textarea id="rdoRemarks" class="form-control mb-3" |
|||
rows="4" placeholder="Enter remarks..."></textarea> |
|||
|
|||
<div class="d-flex justify-content-between"> |
|||
<button class="btn btn-success btn-big" |
|||
onclick="submitOfficerDecision('APPROVED')">Approve</button> |
|||
|
|||
<button class="btn btn-danger btn-big" |
|||
onclick="submitOfficerDecision('REJECTED')">Reject</button> |
|||
</div> |
|||
</div>`; |
|||
} |
|||
|
|||
|
|||
|
|||
let html = ` |
|||
<div class="card-section"> |
|||
<div class="section-title">Applicant Information</div> |
|||
|
|||
<div class="row mb-2"> |
|||
<div class="col-md-6"> |
|||
<div class="label-text">Applicant Name</div> |
|||
<div class="value-text">${record.applicant_name}</div> |
|||
</div> |
|||
<div class="col-md-6"> |
|||
<div class="label-text">Mobile Number</div> |
|||
<div class="value-text">${record.mobile_number}</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="row mb-2"> |
|||
<div class="col-md-6"> |
|||
<div class="label-text">Event Type</div> |
|||
<div class="value-text">${record.event_name}</div> |
|||
</div> |
|||
<div class="col-md-6"> |
|||
<div class="label-text">Event Date</div> |
|||
<div class="value-text"> |
|||
${new Date(record.event_date).toLocaleDateString("en-GB")} |
|||
</div> |
|||
</div> |
|||
<div class="col-md-6"> |
|||
<div class="label-text">Address</div> |
|||
<div class="value-text"> |
|||
${record.applicant_address} |
|||
</div> |
|||
</div> |
|||
<div class="col-md-6"> |
|||
<div class="label-text">Total Cost</div> |
|||
<div class="value-text"> |
|||
${record.total_cost.toLocaleString("en-GB")} |
|||
</div> |
|||
</div> |
|||
<div class="col-md-6"> |
|||
<div class="label-text">No. of Days</div> |
|||
<div class="value-text">${record.no_of_days}</div> |
|||
</div> |
|||
<div class="col-md-6"> |
|||
<div class="label-text">Event Description</div> |
|||
<div class="value-text">${record.event_desc}</div> |
|||
</div> |
|||
|
|||
</div> |
|||
|
|||
<div class="row mb-2"> |
|||
<div class="col-md-6"> |
|||
<div class="label-text">Applied Date</div> |
|||
<div class="value-text">${record.cdate}</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
|
|||
${streetHtml} |
|||
${historyHtml} |
|||
${decisionHtml} |
|||
|
|||
`; |
|||
|
|||
|
|||
|
|||
$("#modalContent").html(html); |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
// function submitRdoDecision(status) { |
|||
|
|||
// let remarks = ($("#rdoRemarks").val() || "").trim(); |
|||
// let refid = $("#detailsModal").data("refid"); |
|||
// let gccUserId = $("#loginuserid").val(); // 🔥 ONLY THIS |
|||
|
|||
// //let approvedBy = $("#userName").val(); // 🔥 FROM HIDDEN INPUT |
|||
|
|||
// if (!remarks) { |
|||
// Swal.fire({ |
|||
// icon: 'warning', |
|||
// title: 'Remarks Required', |
|||
// text: 'Please enter remarks before submitting' |
|||
// }); |
|||
// return; |
|||
// } |
|||
|
|||
// Swal.fire({ |
|||
// title: `Are you sure?`, |
|||
// text: `You want to ${status.toLowerCase()} this request`, |
|||
// icon: status === 'APPROVED' ? 'success' : 'error', |
|||
// showCancelButton: true, |
|||
// confirmButtonColor: status === 'APPROVED' ? '#28a745' : '#dc3545', |
|||
// cancelButtonColor: '#6c757d', |
|||
// confirmButtonText: `Yes, ${status}` |
|||
// }).then((result) => { |
|||
|
|||
// if (!result.isConfirmed) return; |
|||
|
|||
// $.ajax({ |
|||
// url: "/gcc/api/flagpoleregistration/rdo/updateDecision", |
|||
// type: "POST", |
|||
// data: { |
|||
// refid: refid, |
|||
// status: status, |
|||
// remarks: remarks, |
|||
// gccUserId: gccUserId |
|||
// //approvedBy: approvedBy // 🔥 PASS TO BACKEND |
|||
// }, |
|||
// success: function (res) { |
|||
|
|||
// Swal.fire({ |
|||
// icon: 'success', |
|||
// title: status === 'APPROVED' ? 'Approved!' : 'Rejected!', |
|||
// text: res.message || `Request has been ${status.toLowerCase()}`, |
|||
// timer: 2000, |
|||
// showConfirmButton: false |
|||
// }); |
|||
|
|||
// $("#detailsModal").modal("hide"); |
|||
// $("#QaqcDatatable").DataTable().ajax.reload(null, false); |
|||
// }, |
|||
// error: function () { |
|||
// Swal.fire({ |
|||
// icon: 'error', |
|||
// title: 'Error', |
|||
// text: 'Failed to update decision' |
|||
// }); |
|||
// } |
|||
// }); |
|||
// }); |
|||
// } |
|||
|
|||
function submitOfficerDecision(status) { |
|||
|
|||
let remarks = ($("#rdoRemarks").val() || "").trim(); |
|||
let refid = $("#detailsModal").data("refid"); |
|||
|
|||
let gccUserId = $("#loginuserid").val(); // login user id |
|||
let username = $("#userName").val(); // display username |
|||
|
|||
if (!remarks) { |
|||
Swal.fire({ |
|||
icon: 'warning', |
|||
title: 'Remarks Required', |
|||
text: 'Please enter remarks before submitting' |
|||
}); |
|||
return; |
|||
} |
|||
|
|||
Swal.fire({ |
|||
title: `Are you sure?`, |
|||
text: `You want to ${status.toLowerCase()} this request`, |
|||
icon: status === 'APPROVED' ? 'success' : 'error', |
|||
showCancelButton: true, |
|||
confirmButtonColor: status === 'APPROVED' ? '#28a745' : '#dc3545', |
|||
cancelButtonColor: '#6c757d', |
|||
confirmButtonText: `Yes, ${status}` |
|||
}).then((result) => { |
|||
|
|||
if (!result.isConfirmed) return; |
|||
|
|||
$.ajax({ |
|||
url: "/flagpoles/api/flagpoleregistration/officer/updateDecision", |
|||
type: "POST", |
|||
data: { |
|||
refid: refid, |
|||
status: status, |
|||
remarks: remarks, |
|||
gccUserId: gccUserId, |
|||
username: username // ✅ NEW |
|||
}, |
|||
success: function (res) { |
|||
|
|||
Swal.fire({ |
|||
icon: 'success', |
|||
title: status === 'APPROVED' ? 'Approved!' : 'Rejected!', |
|||
text: res.message || `Request has been ${status.toLowerCase()}`, |
|||
timer: 2000, |
|||
showConfirmButton: false |
|||
}); |
|||
|
|||
$("#detailsModal").modal("hide"); |
|||
$("#QaqcDatatable").DataTable().ajax.reload(null, false); |
|||
}, |
|||
error: function () { |
|||
Swal.fire({ |
|||
icon: 'error', |
|||
title: 'Error', |
|||
text: 'Failed to update decision' |
|||
}); |
|||
} |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
|
|||
</script> |
|||
</body> |
|||
|
|||
</html> |
|||
@ -1,754 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en" xmlns:th="http://www.thymeleaf.org"> |
|||
|
|||
<head th:replace="~{fragments/modules/base/head :: head}"></head> |
|||
<style> |
|||
.width1 { |
|||
width: 120px; |
|||
} |
|||
|
|||
.width2 { |
|||
width: 150px; |
|||
} |
|||
|
|||
.modal-label { |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.modal-value { |
|||
color: #444; |
|||
} |
|||
|
|||
.modal-section-title { |
|||
font-size: 1.2rem; |
|||
font-weight: bold; |
|||
margin-top: 20px; |
|||
margin-bottom: 10px; |
|||
border-bottom: 2px solid #dee2e6; |
|||
padding-bottom: 5px; |
|||
} |
|||
|
|||
|
|||
.modal-title-big { |
|||
font-size: 20px; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
.modal-subtext { |
|||
color: #b4c5d3; |
|||
font-size: 13px; |
|||
} |
|||
|
|||
.card-section { |
|||
background: white; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
margin-bottom: 25px; |
|||
border: 1px solid #eee; |
|||
} |
|||
|
|||
.section-title { |
|||
font-weight: 700; |
|||
color: #333; |
|||
margin-bottom: 15px; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.label-text { |
|||
font-size: 13px; |
|||
color: #6c757d; |
|||
} |
|||
|
|||
.value-text { |
|||
font-size: 15px; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.info-block { |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
|
|||
.badge-status { |
|||
background: #ffd9b3; |
|||
color: #a65c00; |
|||
padding: 6px 10px; |
|||
border-radius: 5px; |
|||
font-size: 13px; |
|||
|
|||
} |
|||
|
|||
.btn-big { |
|||
padding: 12px 25px; |
|||
border-radius: 8px; |
|||
width: 200px; |
|||
} |
|||
|
|||
.rdo-box { |
|||
border: 1px solid #eee; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
} |
|||
</style> |
|||
|
|||
<body th:attr="data-two-weight=${isTwoWeightFacility}"> |
|||
|
|||
<div class="wrapper"> |
|||
<!-- header top menu Start --> |
|||
<header th:replace="~{fragments/modules/base/header :: header}"></header> |
|||
<!-- header top menu end --> |
|||
<div class="page-wrap"> |
|||
<!--=============== Left Menu side Start ================--> |
|||
<div th:replace="~{fragments/modules/base/menu :: menu}"></div> |
|||
<!--=============== Left side End ================--> |
|||
<div class="main-content"> |
|||
<div class="container-fluid"> |
|||
<div class="page-header"> |
|||
<div class="row align-items-end"> |
|||
<div class="col-lg-6"> |
|||
<div class="page-header-title"> |
|||
<i class="fa fa-list-alt bg-blue"></i> |
|||
<div class="d-inline"> |
|||
<h5>SWD Biogas Facilities Add Details List</h5> |
|||
<span>Biogas Add Details</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-6"> |
|||
<nav class="breadcrumb-container" aria-label="breadcrumb"> |
|||
<ol class="breadcrumb"> |
|||
<li class="breadcrumb-item"> |
|||
<a href="/swm/index"><i class="ik ik-home"></i></a> |
|||
</li> |
|||
<li class="breadcrumb-item" aria-current="page">SWD Biogas Facilities Add |
|||
Details List |
|||
</li> |
|||
<li class="breadcrumb-item active" aria-current="page">Biogas Add Details</li> |
|||
</ol> |
|||
</nav> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="row mt-4"> |
|||
|
|||
<div class="col-md-12"> |
|||
<div class="card"> |
|||
<div class="card-header d-flex justify-content-between align-items-center fw-bold"> |
|||
<h3 class="mb-0"> SWM Biogas Add Details : <span th:text="${officer_name}"></span> |
|||
</h3> |
|||
<input type="hidden" id="userName" th:value="${officer_name}"> |
|||
</div> |
|||
|
|||
<div class="card-body"> |
|||
<div class="row"> |
|||
<div class="col-md-3"> |
|||
<label for="date" class="form-label" |
|||
style="font-size: medium;">Date:</label><span |
|||
class="text-danger">*</span> |
|||
<input type="date" id="date" class="form-control"> |
|||
</div> |
|||
<div class="col-md-3"> |
|||
<label for="zones" class="form-label">Zones <span |
|||
class="text-danger">*</span> |
|||
</label> <select id="zones" class="form-control"> |
|||
<option value="">Select zones</option> |
|||
|
|||
</select> |
|||
</div> |
|||
|
|||
<div class="col-md-3"> |
|||
|
|||
<label for="weight" class="form-label">Enter Weight:(in MT)</label><span |
|||
class="text-danger">*</span> |
|||
<input type="number" class="form-control" id="weight"> |
|||
</div> |
|||
|
|||
<input type="hidden" id="facilityTypeId" th:value="${facilityTypeId}"> |
|||
|
|||
|
|||
<!-- SECOND WEIGHT (TC) --> |
|||
<div class="col-md-3" id="weight2Div" style="display:none;"> |
|||
<label for="weight1">Enter Weight:</label><span class="text-danger">*</span> |
|||
<input type="number" class="form-control" id="weight1"> |
|||
</div> |
|||
|
|||
<div class="col-md-3" style="margin-top: 30px;"> |
|||
<button id="submitBtn" class="btn btn-primary">Submit</button> |
|||
<button id="resetBtn" class="btn btn-secondary">Reset</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
<div id="pageLoader" |
|||
style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); z-index: 9999; text-align: center;"> |
|||
<div style="position: relative; top: 50%; transform: translateY(-50%);"> |
|||
<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;"> |
|||
<span class="sr-only">Loading...</span> |
|||
</div> |
|||
<!-- Add the 'Please wait' text below the spinner --> |
|||
<p style="margin-top: 1rem; font-size: 1.2rem; color: #007bff;">Please wait...</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div th:replace="~{fragments/modules/base/app_module_menu_box :: div}"></div> |
|||
|
|||
<footer th:replace="~{fragments/modules/base/footer :: footer}"></footer> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Details Modal --> |
|||
<div class="modal fade" id="detailsModal" tabindex="-1" aria-hidden="true"> |
|||
<div class="modal-dialog modal-xl modal-dialog-scrollable"> |
|||
<div class="modal-content"> |
|||
|
|||
<div class="modal-header" style="background:#2f3e54; color:white;"> |
|||
<div> |
|||
<h4 class="modal-title-big" id="modalTitle"></h4> |
|||
<div id="modalSubTitle" class="modal-subtext"></div> |
|||
</div> |
|||
|
|||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span |
|||
aria-hidden="true">×</span></button> |
|||
</div> |
|||
|
|||
<div class="modal-body"> |
|||
|
|||
<div id="modalContent"></div> |
|||
|
|||
<div class="text-center mt-4"> |
|||
<button type="button" class="btn btn-primary btn-big" data-dismiss="modal" |
|||
style="background:#2f3e54;">Close</button> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
<script th:replace="~{fragments/modules/base/script :: script}"></script> |
|||
<script type="text/javascript"> |
|||
|
|||
$(document).ready(function () { |
|||
|
|||
const today = new Date(); |
|||
const day = today.getDay(); // 0=Sun, 1=Mon, ..., 6=Sat |
|||
|
|||
/* ============================= |
|||
LAST SATURDAY |
|||
============================= */ |
|||
const lastSaturday = new Date(today); |
|||
|
|||
// If today is Saturday (6) → today |
|||
// Else → go back to previous Saturday |
|||
const diffToLastSaturday = (day >= 6) |
|||
? day - 6 |
|||
: day + 1; |
|||
|
|||
lastSaturday.setDate(today.getDate() - diffToLastSaturday); |
|||
|
|||
/* ============================= |
|||
THIS WEEK FRIDAY |
|||
============================= */ |
|||
const thisFriday = new Date(today); |
|||
|
|||
// Friday = 5 |
|||
const diffToFriday = (5 - day + 7) % 7; |
|||
thisFriday.setDate(today.getDate() + diffToFriday); |
|||
|
|||
/* ============================= |
|||
FORMAT YYYY-MM-DD |
|||
============================= */ |
|||
const formatDate = (d) => d.toISOString().split("T")[0]; |
|||
|
|||
const minDate = formatDate(lastSaturday); |
|||
const maxDate = formatDate(thisFriday); |
|||
|
|||
/* ============================= |
|||
APPLY LIMITS |
|||
============================= */ |
|||
$("#date") |
|||
.attr("min", minDate) |
|||
.attr("max", maxDate) |
|||
.val(formatDate(today)); |
|||
// 🔒 BLOCK MANUAL TYPING (BUT ALLOW CALENDAR) |
|||
$("#date").on("keydown paste", function (e) { |
|||
e.preventDefault(); |
|||
}); |
|||
}); |
|||
|
|||
$(document).ready(function () { |
|||
const isTwoWeightFacility = |
|||
$("body").data("two-weight") === true || |
|||
$("body").data("two-weight") === "true"; |
|||
|
|||
console.log($("body").data("two-weight")); |
|||
|
|||
|
|||
if (isTwoWeightFacility) { |
|||
$("#weight2Div").show(); |
|||
} else { |
|||
$("#weight2Div").hide(); |
|||
$("#weight1").val(""); |
|||
} |
|||
}); |
|||
|
|||
|
|||
$(document).ready(function () { |
|||
const today = new Date().toISOString().split('T')[0]; |
|||
$("#date").val(today); |
|||
}); |
|||
|
|||
$("#resetBtn").on("click", function () { |
|||
location.reload(); |
|||
}); |
|||
|
|||
// Load zones when page loads |
|||
$(document).ready(function () { |
|||
|
|||
$.ajax({ |
|||
url: "/swm/api/dropdown/getzoneslist", |
|||
type: "GET", |
|||
dataType: "json", |
|||
success: function (data) { |
|||
|
|||
let zoneDropdown = $("#zones"); |
|||
zoneDropdown.empty(); |
|||
zoneDropdown.append("<option value=''>Select Zone</option>"); |
|||
|
|||
$.each(data, function (index, item) { |
|||
zoneDropdown.append( |
|||
`<option value="${item.id}">${item.zone_name}</option>` |
|||
); |
|||
}); |
|||
}, |
|||
error: function (xhr, status, error) { |
|||
console.error("Error fetching zones:", error); |
|||
} |
|||
}); |
|||
|
|||
}); |
|||
|
|||
|
|||
|
|||
$("#submitBtn").on("click", function (e) { |
|||
e.preventDefault(); |
|||
|
|||
const facilityTypeId = $("#facilityTypeId").val(); // ✅ dynamic |
|||
const zoneId = $("#zones").val(); |
|||
const reqDate = $("#date").val(); |
|||
const weight = $("#weight").val(); |
|||
const weight1 = $("#weight1").val(); |
|||
const createdBy = $("#userName").val(); |
|||
|
|||
// 🔴 Client-side validations |
|||
if (!zoneId) { |
|||
Swal.fire("Validation Error", "Please select zone", "warning"); |
|||
return; |
|||
} |
|||
|
|||
if (!reqDate) { |
|||
Swal.fire("Validation Error", "Date is required", "warning"); |
|||
return; |
|||
} |
|||
|
|||
if (!weight || weight <= 0) { |
|||
Swal.fire("Validation Error", "Weight must be greater than zero", "warning"); |
|||
return; |
|||
} |
|||
|
|||
// ⚠️ Note: |
|||
// Facility type 5 validation is done in BACKEND |
|||
// because facilityTypeId is derived after login |
|||
|
|||
$.ajax({ |
|||
url: "/swm/api/admin/addfacility", |
|||
type: "POST", |
|||
data: { |
|||
facilityTypeId: facilityTypeId, |
|||
zoneId: zoneId, |
|||
reqDate: reqDate, |
|||
weight: weight, |
|||
weight1: weight1, // backend will ignore if not needed |
|||
createdBy: createdBy |
|||
}, |
|||
beforeSend: function () { |
|||
Swal.fire({ |
|||
title: "Saving...", |
|||
text: "Please wait", |
|||
allowOutsideClick: false, |
|||
didOpen: () => Swal.showLoading() |
|||
}); |
|||
}, |
|||
success: function (response) { |
|||
Swal.fire("Success", response.message, "success"); |
|||
|
|||
// Reset fields |
|||
$("#weight").val(""); |
|||
$("#weight1").val(""); |
|||
}, |
|||
error: function (xhr) { |
|||
let msg = "Something went wrong"; |
|||
|
|||
if (xhr.responseJSON && xhr.responseJSON.message) { |
|||
msg = xhr.responseJSON.message; |
|||
} |
|||
|
|||
Swal.fire("Error", msg, "error"); |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
|
|||
|
|||
function loadTable() { |
|||
|
|||
let officer_name = $("#userName").val(); |
|||
let startDate = $("#startDate").val(); |
|||
let endDate = $("#endDate").val(); |
|||
|
|||
if ($.fn.DataTable.isDataTable('#QaqcDatatable')) { |
|||
$('#QaqcDatatable').DataTable().clear().destroy(); |
|||
} |
|||
|
|||
table = $('#QaqcDatatable').DataTable({ |
|||
processing: true, |
|||
responsive: true, |
|||
scrollY: '50vh', |
|||
dom: 'Bfrtip', // 🔥 ENABLE BUTTONS |
|||
|
|||
ajax: { |
|||
//url: "/gcc/api/flagpoleregistration/getAllDetails", |
|||
type: "GET", |
|||
data: { |
|||
userLogin: officer_name, |
|||
startDate: startDate, |
|||
endDate: endDate |
|||
}, |
|||
dataSrc: function (json) { |
|||
|
|||
const data = json.data || []; |
|||
|
|||
// 🔹 Dashboard counts |
|||
let pending = 0, approved = 0, rejected = 0; |
|||
|
|||
data.forEach(r => { |
|||
if (!r.rdo_status) pending++; |
|||
else if (r.rdo_status === 'APPROVED') approved++; |
|||
else if (r.rdo_status === 'REJECTED') rejected++; |
|||
}); |
|||
|
|||
$("#totalrequest").text(data.length); |
|||
$("#pendingdecision").text(pending); |
|||
$("#approved").text(approved); |
|||
$("#rejected").text(rejected); |
|||
|
|||
return data; // ✅ already unique per refid |
|||
} |
|||
}, |
|||
|
|||
columns: [ |
|||
{ |
|||
data: null, |
|||
className: "text-center", |
|||
render: (d, t, r, m) => m.row + 1 |
|||
}, |
|||
{ |
|||
data: "applicant_name", |
|||
className: "text-center" |
|||
}, |
|||
{ |
|||
data: "refid", |
|||
className: "text-center" |
|||
}, |
|||
{ |
|||
data: null, |
|||
className: "text-center", |
|||
render: row => { |
|||
if (!row.streets || row.streets.length === 0) return "-"; |
|||
return `${row.streets[0].zone} / ${row.streets[0].ward}`; |
|||
} |
|||
}, |
|||
{ |
|||
data: "event_name", |
|||
className: "text-center" |
|||
}, |
|||
{ |
|||
data: "event_date", |
|||
className: "text-center", |
|||
render: d => new Date(d).toLocaleDateString("en-GB") |
|||
}, |
|||
{ |
|||
data: "total_cost", |
|||
className: "text-center", |
|||
render: d => d.toLocaleString("en-GB") |
|||
}, |
|||
{ |
|||
data: "rdo_status", |
|||
className: "text-center", |
|||
render: d => { |
|||
if (!d) |
|||
return `<span class="badge bg-warning text-dark">Pending</span>`; |
|||
if (d === 'APPROVED') |
|||
return `<span class="badge bg-success">Approved</span>`; |
|||
return `<span class="badge bg-danger">Rejected</span>`; |
|||
} |
|||
}, |
|||
{ |
|||
data: null, |
|||
className: "text-center", |
|||
render: row => |
|||
`<button class="btn btn-primary btn-sm viewBtn" |
|||
data-refid="${row.refid}"> |
|||
View |
|||
</button>` |
|||
} |
|||
] |
|||
}); |
|||
} |
|||
|
|||
|
|||
// 🔹 View button action |
|||
|
|||
// Destroy previous instance if exists |
|||
if ($.fn.DataTable.isDataTable('#QaqcDatatable')) { |
|||
$('#QaqcDatatable').DataTable().clear().destroy(); |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
$('#QaqcDatatable').on("click", ".viewBtn", function () { |
|||
|
|||
// 🔹 Get full row data from DataTable |
|||
const record = table.row($(this).closest('tr')).data(); |
|||
|
|||
if (!record) { |
|||
alert("No details found"); |
|||
return; |
|||
} |
|||
|
|||
populateModal(record); |
|||
$("#detailsModal").modal("show"); |
|||
}); |
|||
|
|||
|
|||
function populateModal(record) { |
|||
|
|||
// HEADER |
|||
$("#modalTitle").html(`Application Details - ${record.applicant_name}`); |
|||
$("#modalSubTitle").html( |
|||
`Ref ID: ${record.refid} - ${record.streets.length} Streets` |
|||
); |
|||
|
|||
$("#detailsModal").data("refid", record.refid); |
|||
|
|||
// 🔹 Streets |
|||
let streetHtml = ""; |
|||
|
|||
record.streets.forEach((s, i) => { |
|||
streetHtml += ` |
|||
<div class="card-section"> |
|||
<div class="section-title">Street ${i + 1}</div> |
|||
|
|||
<div class="row mb-2"> |
|||
<div class="col-md-4"> |
|||
<div class="label-text">Street Name</div> |
|||
<div class="value-text">${s.street_name}</div> |
|||
</div> |
|||
<div class="col-md-4"> |
|||
<div class="label-text">Zone</div> |
|||
<div class="value-text">${s.zone}</div> |
|||
</div> |
|||
<div class="col-md-4"> |
|||
<div class="label-text">Ward</div> |
|||
<div class="value-text">${s.ward}</div> |
|||
</div> |
|||
<div class="col-md-4"> |
|||
<div class="label-text">No. of Poles</div> |
|||
<div class="value-text">${s.no_of_poles}</div> |
|||
</div> |
|||
|
|||
|
|||
<div class="col-md-4"> |
|||
<div class="label-text">Height</div> |
|||
<div class="value-text">${s.height}</div> |
|||
</div> |
|||
|
|||
<div class="col-md-4"> |
|||
<div class="label-text">Flag Material</div> |
|||
<div class="value-text">${s.flag_material}</div> |
|||
</div> |
|||
|
|||
<div class="col-md-4"> |
|||
<div class="label-text">Pole Material</div> |
|||
<div class="value-text">${s.pole_material}</div> |
|||
</div> |
|||
|
|||
</div> |
|||
|
|||
|
|||
</div>`; |
|||
}); |
|||
|
|||
let historyHtml = ""; |
|||
|
|||
if (record.history && record.history.length > 0) { |
|||
|
|||
historyHtml += ` |
|||
<div class="card-section"> |
|||
<div class="section-title">Application History</div> |
|||
`; |
|||
|
|||
record.history.forEach((h, index) => { |
|||
historyHtml += ` |
|||
<div class="row mb-2 border-bottom pb-2"> |
|||
<div class="col-md-4"> |
|||
<div class="label-text">Action Date</div> |
|||
<div class="value-text">${h.action_date}</div> |
|||
</div> |
|||
|
|||
<div class="col-md-3"> |
|||
<div class="label-text">Department</div> |
|||
<div class="value-text">${h.department_name}</div> |
|||
</div> |
|||
|
|||
|
|||
|
|||
<div class="col-md-2"> |
|||
<div class="label-text">Status</div> |
|||
<div class="value-text">${h.status}</div> |
|||
</div> |
|||
|
|||
|
|||
<div class="col-md-2"> |
|||
<div class="label-text">RDO Status</div> |
|||
<div class="value-text"> |
|||
${record.rdo_status || "-"} |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
${h.remarks ? ` |
|||
<div class="col-md-12 mt-1"> |
|||
<div class="label-text">Remarks</div> |
|||
<div class="value-text">${h.remarks}</div> |
|||
</div>` : ""} |
|||
</div> |
|||
`; |
|||
}); |
|||
|
|||
historyHtml += `</div>`; |
|||
} |
|||
|
|||
let decisionHtml = ""; |
|||
|
|||
// 🔹 Show decision buttons ONLY if pending |
|||
if (!record.rdo_status) { |
|||
decisionHtml = ` |
|||
<div class="rdo-box"> |
|||
<div class="section-title">Department Decision</div> |
|||
|
|||
<textarea id="rdoRemarks" class="form-control mb-3" |
|||
rows="4" placeholder="Enter remarks..."></textarea> |
|||
|
|||
<div class="d-flex justify-content-between"> |
|||
<button class="btn btn-success btn-big" |
|||
onclick="submitRdoDecision('APPROVED')">Approve</button> |
|||
|
|||
<button class="btn btn-danger btn-big" |
|||
onclick="submitRdoDecision('REJECTED')">Reject</button> |
|||
</div> |
|||
</div>`; |
|||
} |
|||
|
|||
|
|||
|
|||
let html = ` |
|||
<div class="card-section"> |
|||
<div class="section-title">Applicant Information</div> |
|||
|
|||
<div class="row mb-2"> |
|||
<div class="col-md-6"> |
|||
<div class="label-text">Applicant Name</div> |
|||
<div class="value-text">${record.applicant_name}</div> |
|||
</div> |
|||
<div class="col-md-6"> |
|||
<div class="label-text">Mobile Number</div> |
|||
<div class="value-text">${record.mobile_number}</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="row mb-2"> |
|||
<div class="col-md-6"> |
|||
<div class="label-text">Event Type</div> |
|||
<div class="value-text">${record.event_name}</div> |
|||
</div> |
|||
<div class="col-md-6"> |
|||
<div class="label-text">Event Date</div> |
|||
<div class="value-text"> |
|||
${new Date(record.event_date).toLocaleDateString("en-GB")} |
|||
</div> |
|||
</div> |
|||
<div class="col-md-6"> |
|||
<div class="label-text">Address</div> |
|||
<div class="value-text"> |
|||
${record.applicant_address} |
|||
</div> |
|||
</div> |
|||
<div class="col-md-6"> |
|||
<div class="label-text">Total Cost</div> |
|||
<div class="value-text"> |
|||
${record.total_cost.toLocaleString("en-GB")} |
|||
</div> |
|||
</div> |
|||
<div class="col-md-6"> |
|||
<div class="label-text">No. of Days</div> |
|||
<div class="value-text">${record.no_of_days}</div> |
|||
</div> |
|||
<div class="col-md-6"> |
|||
<div class="label-text">Event Description</div> |
|||
<div class="value-text">${record.event_desc}</div> |
|||
</div> |
|||
|
|||
</div> |
|||
|
|||
<div class="row mb-2"> |
|||
<div class="col-md-6"> |
|||
<div class="label-text">Applied Date</div> |
|||
<div class="value-text">${record.cdate}</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
|
|||
${streetHtml} |
|||
${historyHtml} |
|||
${decisionHtml} |
|||
|
|||
`; |
|||
|
|||
|
|||
|
|||
$("#modalContent").html(html); |
|||
} |
|||
|
|||
|
|||
|
|||
</script> |
|||
</body> |
|||
|
|||
</html> |
|||
@ -1,416 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en" xmlns:th="http://www.thymeleaf.org"> |
|||
|
|||
<head th:replace="~{fragments/modules/base/head :: head}"></head> |
|||
<style> |
|||
.width1 { |
|||
width: 120px; |
|||
} |
|||
|
|||
.width2 { |
|||
width: 150px; |
|||
} |
|||
|
|||
.modal-label { |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.modal-value { |
|||
color: #444; |
|||
} |
|||
|
|||
.modal-section-title { |
|||
font-size: 1.2rem; |
|||
font-weight: bold; |
|||
margin-top: 20px; |
|||
margin-bottom: 10px; |
|||
border-bottom: 2px solid #dee2e6; |
|||
padding-bottom: 5px; |
|||
} |
|||
|
|||
|
|||
.modal-title-big { |
|||
font-size: 20px; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
.modal-subtext { |
|||
color: #b4c5d3; |
|||
font-size: 13px; |
|||
} |
|||
|
|||
.card-section { |
|||
background: white; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
margin-bottom: 25px; |
|||
border: 1px solid #eee; |
|||
} |
|||
|
|||
.section-title { |
|||
font-weight: 700; |
|||
color: #333; |
|||
margin-bottom: 15px; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.label-text { |
|||
font-size: 13px; |
|||
color: #6c757d; |
|||
} |
|||
|
|||
.value-text { |
|||
font-size: 15px; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.info-block { |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
|
|||
.badge-status { |
|||
background: #ffd9b3; |
|||
color: #a65c00; |
|||
padding: 6px 10px; |
|||
border-radius: 5px; |
|||
font-size: 13px; |
|||
|
|||
} |
|||
|
|||
.btn-big { |
|||
padding: 12px 25px; |
|||
border-radius: 8px; |
|||
width: 200px; |
|||
} |
|||
|
|||
.rdo-box { |
|||
border: 1px solid #eee; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
} |
|||
</style> |
|||
|
|||
<body th:attr="data-two-weight=${isTwoWeightFacility}"> |
|||
|
|||
<div class="wrapper"> |
|||
<!-- header top menu Start --> |
|||
<header th:replace="~{fragments/modules/base/header :: header}"></header> |
|||
<!-- header top menu end --> |
|||
<div class="page-wrap"> |
|||
<!--=============== Left Menu side Start ================--> |
|||
<div th:replace="~{fragments/modules/base/menu :: menu}"></div> |
|||
<!--=============== Left side End ================--> |
|||
<div class="main-content"> |
|||
<div class="container-fluid"> |
|||
<div class="page-header"> |
|||
<div class="row align-items-end"> |
|||
<div class="col-lg-6"> |
|||
<div class="page-header-title"> |
|||
<i class="fa fa-list-alt bg-blue"></i> |
|||
<div class="d-inline"> |
|||
<h5>SWD CDWaste Facilities Add Details List</h5> |
|||
<span> CDWaste Add Details</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-6"> |
|||
<nav class="breadcrumb-container" aria-label="breadcrumb"> |
|||
<ol class="breadcrumb"> |
|||
<li class="breadcrumb-item"> |
|||
<a href="/swm/index"><i class="ik ik-home"></i></a> |
|||
</li> |
|||
<li class="breadcrumb-item" aria-current="page">SWD CDWaste Facilities Add |
|||
Details List |
|||
</li> |
|||
<li class="breadcrumb-item active" aria-current="page">CDWaste Add Details</li> |
|||
</ol> |
|||
</nav> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="row mt-4"> |
|||
|
|||
<div class="col-md-12"> |
|||
<div class="card"> |
|||
<div class="card-header d-flex justify-content-between align-items-center fw-bold"> |
|||
<h3 class="mb-0"> SWD CDWaste Add Details : <span th:text="${officer_name}"></span> |
|||
</h3> |
|||
<input type="hidden" id="userName" th:value="${officer_name}"> |
|||
</div> |
|||
|
|||
<div class="card-body"> |
|||
<div class="row"> |
|||
<div class="col-md-3"> |
|||
<label for="date" class="form-label" |
|||
style="font-size: medium;">Date:</label><span class="text-danger">*</span> |
|||
<input type="date" id="date" class="form-control"> |
|||
</div> |
|||
<div class="col-md-3"> |
|||
<label for="zones" class="form-label">Zones <span |
|||
class="text-danger">*</span> |
|||
</label> <select id="zones" class="form-control"> |
|||
<option value="">Select days</option> |
|||
|
|||
</select> |
|||
</div> |
|||
|
|||
<div class="col-md-3"> |
|||
|
|||
<label for="weight" class="form-label">Enter Weight:(in MT)</label><span class="text-danger">*</span> |
|||
<input type="number" class="form-control" id="weight"> |
|||
</div> |
|||
|
|||
<input type="hidden" id="facilityTypeId" th:value="${facilityTypeId}"> |
|||
|
|||
|
|||
<!-- SECOND WEIGHT (TC) --> |
|||
<div class="col-md-3" id="weight2Div" style="display:none;"> |
|||
<label for="weight1">Enter Weight (TC)</label><span |
|||
class="text-danger">*</span> |
|||
<input type="number" class="form-control" id="weight1"> |
|||
</div> |
|||
|
|||
<div class="col-md-3" id="weightTypeDiv"> |
|||
<label class="form-label">Location<span class="text-danger">*</span></label> |
|||
<select id="facilitytype" class="form-control"> |
|||
<option value="">Select</option> |
|||
<option value="KDG">KDG</option> |
|||
<option value="PDG">PDG</option> |
|||
</select> |
|||
</div> |
|||
|
|||
|
|||
<div class="col-md-3" style="margin-top: 30px;"> |
|||
<button id="submitBtn" class="btn btn-primary">Submit</button> |
|||
<button id="resetBtn" class="btn btn-secondary">Reset</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
<div id="pageLoader" |
|||
style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); z-index: 9999; text-align: center;"> |
|||
<div style="position: relative; top: 50%; transform: translateY(-50%);"> |
|||
<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;"> |
|||
<span class="sr-only">Loading...</span> |
|||
</div> |
|||
<!-- Add the 'Please wait' text below the spinner --> |
|||
<p style="margin-top: 1rem; font-size: 1.2rem; color: #007bff;">Please wait...</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div th:replace="~{fragments/modules/base/app_module_menu_box :: div}"></div> |
|||
|
|||
<footer th:replace="~{fragments/modules/base/footer :: footer}"></footer> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Details Modal --> |
|||
<div class="modal fade" id="detailsModal" tabindex="-1" aria-hidden="true"> |
|||
<div class="modal-dialog modal-xl modal-dialog-scrollable"> |
|||
<div class="modal-content"> |
|||
|
|||
<div class="modal-header" style="background:#2f3e54; color:white;"> |
|||
<div> |
|||
<h4 class="modal-title-big" id="modalTitle"></h4> |
|||
<div id="modalSubTitle" class="modal-subtext"></div> |
|||
</div> |
|||
|
|||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span |
|||
aria-hidden="true">×</span></button> |
|||
</div> |
|||
|
|||
<div class="modal-body"> |
|||
|
|||
<div id="modalContent"></div> |
|||
|
|||
<div class="text-center mt-4"> |
|||
<button type="button" class="btn btn-primary btn-big" data-dismiss="modal" |
|||
style="background:#2f3e54;">Close</button> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
<script th:replace="~{fragments/modules/base/script :: script}"></script> |
|||
<script type="text/javascript"> |
|||
|
|||
$(document).ready(function () { |
|||
|
|||
const today = new Date(); |
|||
const day = today.getDay(); // 0=Sun, 1=Mon, ..., 6=Sat |
|||
|
|||
/* ============================= |
|||
LAST SATURDAY |
|||
============================= */ |
|||
const lastSaturday = new Date(today); |
|||
const diffToLastSaturday = (day >= 6) ? day - 6 : day + 1; |
|||
lastSaturday.setDate(today.getDate() - diffToLastSaturday); |
|||
|
|||
/* ============================= |
|||
THIS WEEK FRIDAY |
|||
============================= */ |
|||
const thisFriday = new Date(today); |
|||
const diffToFriday = (5 - day + 7) % 7; |
|||
thisFriday.setDate(today.getDate() + diffToFriday); |
|||
|
|||
/* ============================= |
|||
FORMAT YYYY-MM-DD |
|||
============================= */ |
|||
const formatDate = d => d.toISOString().split("T")[0]; |
|||
|
|||
$("#date") |
|||
.attr("min", formatDate(lastSaturday)) |
|||
.attr("max", formatDate(thisFriday)) |
|||
.val(formatDate(today)) |
|||
// 🔒 BLOCK MANUAL TYPING (BUT ALLOW CALENDAR) |
|||
$("#date").on("keydown paste", function (e) { |
|||
e.preventDefault(); |
|||
}); |
|||
}); |
|||
|
|||
|
|||
$(document).ready(function () { |
|||
const isTwoWeightFacility = |
|||
$("body").data("two-weight") === true || |
|||
$("body").data("two-weight") === "true"; |
|||
|
|||
console.log($("body").data("two-weight")); |
|||
|
|||
|
|||
if (isTwoWeightFacility) { |
|||
$("#weight2Div").show(); |
|||
} else { |
|||
$("#weight2Div").hide(); |
|||
$("#weight1").val(""); |
|||
} |
|||
}); |
|||
|
|||
|
|||
$(document).ready(function () { |
|||
const today = new Date().toISOString().split('T')[0]; |
|||
$("#date").val(today); |
|||
}); |
|||
|
|||
$("#resetBtn").on("click", function () { |
|||
location.reload(); |
|||
}); |
|||
|
|||
// Load zones when page loads |
|||
$(document).ready(function () { |
|||
|
|||
$.ajax({ |
|||
url: "/swm/api/dropdown/getzoneslist", |
|||
type: "GET", |
|||
dataType: "json", |
|||
success: function (data) { |
|||
|
|||
let zoneDropdown = $("#zones"); |
|||
zoneDropdown.empty(); |
|||
zoneDropdown.append("<option value=''>Select Zone</option>"); |
|||
|
|||
$.each(data, function (index, item) { |
|||
zoneDropdown.append( |
|||
`<option value="${item.id}">${item.zone_name}</option>` |
|||
); |
|||
}); |
|||
}, |
|||
error: function (xhr, status, error) { |
|||
console.error("Error fetching zones:", error); |
|||
} |
|||
}); |
|||
|
|||
}); |
|||
|
|||
|
|||
|
|||
$("#submitBtn").on("click", function (e) { |
|||
e.preventDefault(); |
|||
|
|||
const facilityTypeId = $("#facilityTypeId").val(); // ✅ dynamic |
|||
const zoneId = $("#zones").val(); |
|||
const reqDate = $("#date").val(); |
|||
const weight = $("#weight").val(); |
|||
const weight1 = $("#weight1").val(); |
|||
const weightType = $("#facilitytype").val(); |
|||
const createdBy = $("#userName").val(); |
|||
|
|||
// 🔴 Client-side validations |
|||
if (!zoneId) { |
|||
Swal.fire("Validation Error", "Please select zone", "warning"); |
|||
return; |
|||
} |
|||
|
|||
if (!reqDate) { |
|||
Swal.fire("Validation Error", "Date is required", "warning"); |
|||
return; |
|||
} |
|||
|
|||
if (!weight || weight <= 0) { |
|||
Swal.fire("Validation Error", "Weight must be greater than zero", "warning"); |
|||
return; |
|||
} |
|||
|
|||
// ⚠️ Note: |
|||
// Facility type 5 validation is done in BACKEND |
|||
// because facilityTypeId is derived after login |
|||
|
|||
$.ajax({ |
|||
url: "/swm/api/admin/addfacility", |
|||
type: "POST", |
|||
data: { |
|||
facilityTypeId: facilityTypeId, |
|||
zoneId: zoneId, |
|||
reqDate: reqDate, |
|||
weight: weight, |
|||
weight1: weight1, |
|||
weightType: weightType, |
|||
createdBy: createdBy // backend will ignore if not needed |
|||
}, |
|||
beforeSend: function () { |
|||
Swal.fire({ |
|||
title: "Saving...", |
|||
text: "Please wait", |
|||
allowOutsideClick: false, |
|||
didOpen: () => Swal.showLoading() |
|||
}); |
|||
}, |
|||
success: function (response) { |
|||
Swal.fire("Success", response.message, "success"); |
|||
|
|||
// Reset fields |
|||
$("#weight").val(""); |
|||
$("#weight1").val(""); |
|||
}, |
|||
error: function (xhr) { |
|||
let msg = "Something went wrong"; |
|||
|
|||
if (xhr.responseJSON && xhr.responseJSON.message) { |
|||
msg = xhr.responseJSON.message; |
|||
} |
|||
|
|||
Swal.fire("Error", msg, "error"); |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
|
|||
</script> |
|||
</body> |
|||
|
|||
</html> |
|||
@ -1,764 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en" xmlns:th="http://www.thymeleaf.org"> |
|||
|
|||
<head th:replace="~{fragments/modules/base/head :: head}"></head> |
|||
<style> |
|||
.width1 { |
|||
width: 120px; |
|||
} |
|||
|
|||
.width2 { |
|||
width: 150px; |
|||
} |
|||
|
|||
.modal-label { |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.modal-value { |
|||
color: #444; |
|||
} |
|||
|
|||
.modal-section-title { |
|||
font-size: 1.2rem; |
|||
font-weight: bold; |
|||
margin-top: 20px; |
|||
margin-bottom: 10px; |
|||
border-bottom: 2px solid #dee2e6; |
|||
padding-bottom: 5px; |
|||
} |
|||
|
|||
|
|||
.modal-title-big { |
|||
font-size: 20px; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
.modal-subtext { |
|||
color: #b4c5d3; |
|||
font-size: 13px; |
|||
} |
|||
|
|||
.card-section { |
|||
background: white; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
margin-bottom: 25px; |
|||
border: 1px solid #eee; |
|||
} |
|||
|
|||
.section-title { |
|||
font-weight: 700; |
|||
color: #333; |
|||
margin-bottom: 15px; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.label-text { |
|||
font-size: 13px; |
|||
color: #6c757d; |
|||
} |
|||
|
|||
.value-text { |
|||
font-size: 15px; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.info-block { |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
|
|||
.badge-status { |
|||
background: #ffd9b3; |
|||
color: #a65c00; |
|||
padding: 6px 10px; |
|||
border-radius: 5px; |
|||
font-size: 13px; |
|||
|
|||
} |
|||
|
|||
.btn-big { |
|||
padding: 12px 25px; |
|||
border-radius: 8px; |
|||
width: 200px; |
|||
} |
|||
|
|||
.rdo-box { |
|||
border: 1px solid #eee; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
} |
|||
</style> |
|||
|
|||
<body> |
|||
|
|||
<div class="wrapper"> |
|||
<!-- header top menu Start --> |
|||
<header th:replace="~{fragments/modules/base/header :: header}"></header> |
|||
<!-- header top menu end --> |
|||
<div class="page-wrap"> |
|||
<!--=============== Left Menu side Start ================--> |
|||
<div th:replace="~{fragments/modules/base/menu :: menu}"></div> |
|||
<!--=============== Left side End ================--> |
|||
<div class="main-content"> |
|||
<div class="container-fluid"> |
|||
<div class="page-header"> |
|||
<div class="row align-items-end"> |
|||
<div class="col-lg-6"> |
|||
<div class="page-header-title"> |
|||
<i class="fa fa-list-alt bg-blue"></i> |
|||
<div class="d-inline"> |
|||
<h5>SWD Facilities Reports</h5> |
|||
<span>Reports</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-6"> |
|||
<nav class="breadcrumb-container" aria-label="breadcrumb"> |
|||
<ol class="breadcrumb"> |
|||
<li class="breadcrumb-item"> |
|||
<a href="/swm/index"><i class="ik ik-home"></i></a> |
|||
</li> |
|||
<li class="breadcrumb-item" aria-current="page">SWD Facilities Reports</li> |
|||
<li class="breadcrumb-item active" aria-current="page">Reports</li> |
|||
</ol> |
|||
</nav> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="row mt-4"> |
|||
<div class="col-md-12"> |
|||
<div class="card shadow-sm"> |
|||
|
|||
<!-- CARD HEADER --> |
|||
<div class="card-header d-flex justify-content-between align-items-center fw-bold"> |
|||
<h3 class="mb-0"> SWD Facilities Reports : <span th:text="${officer_name}"></span> |
|||
</h3> |
|||
<input type="hidden" id="userName" th:value="${officer_name}"> |
|||
</div> |
|||
|
|||
<!-- FILTER SECTION --> |
|||
<div class="card-body pb-0"> |
|||
<div class="row align-items-end g-3 mb-3"> |
|||
<div class="col-md-3"> |
|||
<label class="form-label">From Date</label><span |
|||
class="text-danger">*</span> |
|||
<input type="date" id="fromDate" class="form-control"> |
|||
</div> |
|||
|
|||
<div class="col-md-3"> |
|||
<label class="form-label">To Date</label><span class="text-danger">*</span> |
|||
<input type="date" id="toDate" class="form-control"> |
|||
</div> |
|||
|
|||
<div class="col-md-3"> |
|||
<button id="searchBtn" class="btn btn-primary w-100"> |
|||
Search |
|||
</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- TABLE SECTION --> |
|||
<div class="card-body pt-0"> |
|||
<div class="table-responsive"> |
|||
|
|||
<!-- Logged-in username --> |
|||
<input type="hidden" id="userName" th:value="${officer_name}"> |
|||
|
|||
<table id="QaqcDatatable" |
|||
class="table table-striped table-bordered table-hover dataTable" |
|||
width="100%"> |
|||
|
|||
<thead class="thead-dark"> |
|||
<!-- MAIN GROUP HEADERS --> |
|||
<tr class="text-center"> |
|||
<th rowspan="2">S.No</th> |
|||
<th rowspan="2">Zone</th> |
|||
|
|||
<th colspan="3" class="grp-mcc">MCC</th> |
|||
<th colspan="3" class="grp-windrow">Windrow</th> |
|||
<th colspan="3" class="grp-biocng">Bio-CNG</th> |
|||
<th colspan="3" class="grp-biogas">Bio-GAS</th> |
|||
<th colspan="3" class="grp-incinerator">Incinerator</th> |
|||
<th colspan="3" class="grp-baling">Plasting Baling Centre</th> |
|||
<th colspan="3" class="grp-gwtc">GW & TC Waste</th> |
|||
<th colspan="3" class="grp-cd">C&D Waste Processing Centre</th> |
|||
|
|||
</tr> |
|||
|
|||
<!-- SUB HEADERS --> |
|||
<tr class="text-center"> |
|||
<th class="mcc">Target</th> |
|||
<th class="mcc">Achieved</th> |
|||
<th class="mcc">%</th> |
|||
<th class="windrow">Target</th> |
|||
<th class="windrow">Achieved</th> |
|||
<th class="windrow">%</th> |
|||
<th class="biocng">Target</th> |
|||
<th class="biocng">Achieved</th> |
|||
<th class="biocng">%</th> |
|||
<th class="biogas">Target</th> |
|||
<th class="biogas">Achieved</th> |
|||
<th class="biogas">%</th> |
|||
<th class="gwtc">Target</th> |
|||
<th class="gwtc">Achieved</th> |
|||
<th class="gwtc">%</th> |
|||
<th class="incinerator">Target</th> |
|||
<th class="incinerator">Achieved</th> |
|||
<th class="incinerator">%</th> |
|||
<th class="baling">Target</th> |
|||
<th class="baling">Achieved</th> |
|||
<th class="baling">%</th> |
|||
|
|||
|
|||
<th class="cd">Target</th> |
|||
<th class="cd">Achieved</th> |
|||
<th class="cd">%</th> |
|||
</tr> |
|||
</thead> |
|||
<tfoot> |
|||
<tr class="fw-bold text-center"> |
|||
<th colspan="2">TOTAL</th> |
|||
|
|||
<!-- MCC --> |
|||
<th class="mcc"></th> |
|||
<th class="mcc"></th> |
|||
<th class="mcc"></th> |
|||
|
|||
<!-- Windrow --> |
|||
<th class="windrow"></th> |
|||
<th class="windrow"></th> |
|||
<th class="windrow"></th> |
|||
|
|||
<!-- Bio-CNG --> |
|||
<th class="biocng"></th> |
|||
<th class="biocng"></th> |
|||
<th class="biocng"></th> |
|||
|
|||
<!-- Bio-GAS --> |
|||
<th class="biogas"></th> |
|||
<th class="biogas"></th> |
|||
<th class="biogas"></th> |
|||
|
|||
|
|||
|
|||
|
|||
<!-- Incinerator --> |
|||
<th class="incinerator"></th> |
|||
<th class="incinerator"></th> |
|||
<th class="incinerator"></th> |
|||
|
|||
<!-- Baling --> |
|||
<th class="baling"></th> |
|||
<th class="baling"></th> |
|||
<th class="baling"></th> |
|||
|
|||
<th class="gwtc"></th> |
|||
<th class="gwtc"></th> |
|||
<th class="gwtc"></th> |
|||
|
|||
|
|||
<!-- C&D --> |
|||
<th class="cd"></th> |
|||
<th class="cd"></th> |
|||
<th class="cd"></th> |
|||
</tr> |
|||
</tfoot> |
|||
|
|||
|
|||
<tbody></tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
</div> |
|||
</div> |
|||
<div id="pageLoader" |
|||
style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); z-index: 9999; text-align: center;"> |
|||
<div style="position: relative; top: 50%; transform: translateY(-50%);"> |
|||
<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;"> |
|||
<span class="sr-only">Loading...</span> |
|||
</div> |
|||
<!-- Add the 'Please wait' text below the spinner --> |
|||
<p style="margin-top: 1rem; font-size: 1.2rem; color: #007bff;">Please wait...</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div th:replace="~{fragments/modules/base/app_module_menu_box :: div}"></div> |
|||
|
|||
<footer th:replace="~{fragments/modules/base/footer :: footer}"></footer> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Details Modal --> |
|||
<div class="modal fade" id="detailsModal" tabindex="-1" aria-hidden="true"> |
|||
<div class="modal-dialog modal-xl modal-dialog-scrollable"> |
|||
<div class="modal-content"> |
|||
|
|||
<div class="modal-header" style="background:#2f3e54; color:white;"> |
|||
<div> |
|||
<h4 class="modal-title-big" id="modalTitle"></h4> |
|||
<div id="modalSubTitle" class="modal-subtext"></div> |
|||
</div> |
|||
|
|||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span |
|||
aria-hidden="true">×</span></button> |
|||
</div> |
|||
|
|||
<div class="modal-body"> |
|||
|
|||
<div id="modalContent"></div> |
|||
|
|||
<div class="text-center mt-4"> |
|||
<button type="button" class="btn btn-primary btn-big" data-dismiss="modal" |
|||
style="background:#2f3e54;">Close</button> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
<script th:replace="~{fragments/modules/base/script :: script}"></script> |
|||
<script type="text/javascript"> |
|||
|
|||
let table; |
|||
|
|||
$(document).ready(function () { |
|||
|
|||
table = $('#QaqcDatatable').DataTable({ |
|||
data: [], |
|||
ordering: false, |
|||
searching: true, |
|||
info: true, |
|||
paging: true, |
|||
pageLength: 15, // ✅ show 15 rows |
|||
lengthMenu: [15, 25, 50, 100], // ✅ optional dropdown |
|||
scrollX: true, |
|||
responsive: false, |
|||
dom: 'Bftip', |
|||
|
|||
buttons: [ |
|||
{ |
|||
extend: 'excelHtml5', |
|||
text: 'Excel', |
|||
title: 'Gcc Swm Report' |
|||
}, |
|||
{ |
|||
extend: 'pdfHtml5', |
|||
orientation: 'landscape', |
|||
pageSize: 'A3', |
|||
title: 'Gcc Swm Report' |
|||
}, |
|||
{ |
|||
extend: 'csvHtml5', |
|||
text: 'CSV' |
|||
} |
|||
], |
|||
|
|||
// columns: [ |
|||
// { data: "sno", defaultContent: "" }, |
|||
// { data: "zone", defaultContent: "" }, |
|||
|
|||
// { data: "MCC_target", defaultContent: 0 }, |
|||
// { data: "MCC_achieved", defaultContent: 0 }, |
|||
// { data: "MCC_percentage", defaultContent: "0%" }, |
|||
|
|||
// { data: "Windrow_target", defaultContent: 0 }, |
|||
// { data: "Windrow_achieved", defaultContent: 0 }, |
|||
// { data: "Windrow_percentage", defaultContent: "0%" }, |
|||
|
|||
// { data: "Bio-CNG_target", defaultContent: 0 }, |
|||
// { data: "Bio-CNG_achieved", defaultContent: 0 }, |
|||
// { data: "Bio-CNG_percentage", defaultContent: "0%" }, |
|||
|
|||
// { data: "Bio-GAS_target", defaultContent: 0 }, |
|||
// { data: "Bio-GAS_achieved", defaultContent: 0 }, |
|||
// { data: "Bio-GAS_percentage", defaultContent: "0%" }, |
|||
|
|||
|
|||
|
|||
// { data: "Incinerator_target", defaultContent: 0 }, |
|||
// { data: "Incinerator_achieved", defaultContent: 0 }, |
|||
// { data: "Incinerator_percentage", defaultContent: "0%" }, |
|||
|
|||
// { data: "Plasting Baling Centre_target", defaultContent: 0 }, |
|||
// { data: "Plasting Baling Centre_achieved", defaultContent: 0 }, |
|||
// { data: "Plasting Baling Centre_percentage", defaultContent: "0%" }, |
|||
|
|||
// { data: "GWTC_target", defaultContent: 0 }, |
|||
// { data: "GWTC_achieved", defaultContent: 0 }, |
|||
// { data: "GWTC_percentage", defaultContent: "0%" }, |
|||
|
|||
|
|||
// { data: "CD_target", defaultContent: 0 }, |
|||
// { data: "CD_achieved", defaultContent: 0 }, |
|||
// { data: "CD_percentage", defaultContent: "0%" } |
|||
|
|||
|
|||
|
|||
// ], |
|||
columns: [ |
|||
{ data: "sno" }, |
|||
{ data: "zone" }, |
|||
|
|||
{ data: "mcc_target", defaultContent: 0 }, |
|||
{ data: "mcc_achieved", defaultContent: 0 }, |
|||
{ data: "mcc_percentage", defaultContent: "0%" }, |
|||
|
|||
{ data: "windrow_target", defaultContent: 0 }, |
|||
{ data: "windrow_achieved", defaultContent: 0 }, |
|||
{ data: "windrow_percentage", defaultContent: "0%" }, |
|||
|
|||
{ data: "biocng_target", defaultContent: 0 }, |
|||
{ data: "biocng_achieved", defaultContent: 0 }, |
|||
{ data: "biocng_percentage", defaultContent: "0%" }, |
|||
|
|||
{ data: "biogas_target", defaultContent: 0 }, |
|||
{ data: "biogas_achieved", defaultContent: 0 }, |
|||
{ data: "biogas_percentage", defaultContent: "0%" }, |
|||
|
|||
|
|||
{ data: "incinerator_target", defaultContent: 0 }, |
|||
{ data: "incinerator_achieved", defaultContent: 0 }, |
|||
{ data: "incinerator_percentage", defaultContent: "0%" }, |
|||
|
|||
{ data: "baling_target", defaultContent: 0 }, |
|||
{ data: "baling_achieved", defaultContent: 0 }, |
|||
{ data: "baling_percentage", defaultContent: "0%" }, |
|||
|
|||
{ data: "gwtc_target", defaultContent: 0 }, |
|||
{ data: "gwtc_achieved", defaultContent: 0 }, |
|||
{ data: "gwtc_percentage", defaultContent: "0%" }, |
|||
|
|||
|
|||
{ data: "cd_target", defaultContent: 0 }, |
|||
{ data: "cd_achieved", defaultContent: 0 }, |
|||
{ data: "cd_percentage", defaultContent: "0%" } |
|||
], |
|||
|
|||
|
|||
/* ================= FOOTER TOTAL ================= */ |
|||
footerCallback: function () { |
|||
|
|||
const api = this.api(); |
|||
|
|||
function sum(colIdx) { |
|||
return api |
|||
.column(colIdx, { page: 'current' }) |
|||
.data() |
|||
.reduce((a, b) => { |
|||
const x = parseFloat(a) || 0; |
|||
const y = parseFloat(String(b).replace('%', '')) || 0; |
|||
return x + y; |
|||
}, 0) |
|||
.toFixed(2); |
|||
} |
|||
|
|||
const targetAchievedCols = [ |
|||
2, 3, // MCC |
|||
5, 6, // Windrow |
|||
8, 9, // Bio-CNG |
|||
11, 12, // Bio-GAS |
|||
14, 15, // Incinerator |
|||
17, 18, // Baling |
|||
20, 21, // gwtc |
|||
23, 24 // C&D |
|||
]; |
|||
|
|||
targetAchievedCols.forEach(idx => { |
|||
if (api.column(idx).visible()) { |
|||
$(api.column(idx).footer()).html(sum(idx)); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
}); |
|||
|
|||
// 🔥 Hide/Show facility columns based on username |
|||
applyFacilityVisibility(); |
|||
|
|||
$("#searchBtn").on("click", loadLoginWiseReport); |
|||
}); |
|||
|
|||
function normalizeFacilityName(facility) { |
|||
const map = { |
|||
// MCC |
|||
"MCC": "mcc", |
|||
|
|||
// Windrow |
|||
"Windrow": "windrow", |
|||
|
|||
// Bio-CNG |
|||
"Bio-CNG": "biocng", |
|||
|
|||
// Bio-GAS |
|||
"Bio-GAS": "biogas", |
|||
|
|||
// Incinerator |
|||
"Incinerator": "incinerator", |
|||
|
|||
// Baling |
|||
"Plasting Baling Centre": "baling", |
|||
"Plastic Baling Centre": "baling", |
|||
|
|||
// 🔥 GW & TC (THIS IS THE FIX) |
|||
"GW & TC Waste": "gwtc", |
|||
"GW & TC Waste Processing Centre": "gwtc", |
|||
"GW TC Waste": "gwtc", |
|||
|
|||
// C&D |
|||
"C&D Waste Processing Centre": "cd", |
|||
"C & D Waste Processing Centre": "cd", |
|||
"C&D Waste": "cd", |
|||
"SWM C&D": "cd" |
|||
}; |
|||
|
|||
return map[facility] || facility.toLowerCase().replace(/[^a-z]/g, ""); |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
// function applyFacilityVisibility() { |
|||
|
|||
// const username = $("#userName").val().toLowerCase(); |
|||
|
|||
// // hide all facility columns |
|||
// table.columns([...Array(26).keys()].slice(2)).visible(false); |
|||
|
|||
|
|||
// // hide all headers |
|||
// $('.grp-mcc,.grp-windrow,.grp-biocng,.grp-biogas,.grp-incinerator,.grp-baling,.grp-gwtc,.grp-cd').hide(); |
|||
// $('.mcc,.windrow,.biocng,.biogas,.incinerator,.baling,.gwtc,.cd').hide(); |
|||
|
|||
// const map = { |
|||
// "mcc": { cols: [2, 3, 4], cls: "mcc", grp: "grp-mcc" }, |
|||
// "windrow": { cols: [5, 6, 7], cls: "windrow", grp: "grp-windrow" }, |
|||
// "biocng": { cols: [8, 9, 10], cls: "biocng", grp: "grp-biocng" }, |
|||
// "biogas": { cols: [11, 12, 13], cls: "biogas", grp: "grp-biogas" }, |
|||
// "incinerator": { cols: [14, 15, 16], cls: "incinerator", grp: "grp-incinerator" }, |
|||
// "baling": { cols: [17, 18, 19], cls: "baling", grp: "grp-baling" }, |
|||
// // ✅ ADD THIS (CRITICAL FIX) |
|||
// "pbc": { cols: [17, 18, 19], cls: "baling", grp: "grp-baling" }, |
|||
|
|||
// // ✅ GW & TC |
|||
// "gw": { cols: [20, 21, 22], cls: "gwtc", grp: "grp-gwtc" }, |
|||
// "tc": { cols: [20, 21, 22], cls: "gwtc", grp: "grp-gwtc" }, |
|||
// "gwtc": { cols: [20, 21, 22], cls: "gwtc", grp: "grp-gwtc" }, |
|||
// // ✅ C&D |
|||
// "cd": { cols: [23, 24, 25], cls: "cd", grp: "grp-cd" }, |
|||
// "c&d": { cols: [23, 24, 25], cls: "cd", grp: "grp-cd" } |
|||
// }; |
|||
|
|||
// Object.keys(map).forEach(key => { |
|||
// if (username.includes(key)) { |
|||
// table.columns(map[key].cols).visible(true); |
|||
// $('.' + map[key].cls).show(); |
|||
// $('.' + map[key].grp).show(); |
|||
// } |
|||
// }); |
|||
|
|||
// table.columns.adjust().draw(false); |
|||
// } |
|||
|
|||
function applyFacilityVisibility() { |
|||
|
|||
const username = $("#userName").val().toLowerCase(); |
|||
|
|||
// hide all columns except S.No & Zone |
|||
table.columns().visible(false); |
|||
table.columns([0, 1]).visible(true); |
|||
|
|||
// hide all headers |
|||
$('.grp-mcc,.grp-windrow,.grp-biocng,.grp-biogas,.grp-incinerator,.grp-baling,.grp-gwtc,.grp-cd').hide(); |
|||
$('.mcc,.windrow,.biocng,.biogas,.incinerator,.baling,.gwtc,.cd').hide(); |
|||
|
|||
const map = { |
|||
"mcc": { cols: [2, 3, 4], cls: "mcc", grp: "grp-mcc" }, |
|||
"windrow": { cols: [5, 6, 7], cls: "windrow", grp: "grp-windrow" }, |
|||
|
|||
// 🔥 FIX: support bio_cng login |
|||
"bio_cng": { cols: [8, 9, 10], cls: "biocng", grp: "grp-biocng" }, |
|||
"biocng": { cols: [8, 9, 10], cls: "biocng", grp: "grp-biocng" }, |
|||
|
|||
"bio_gas": { cols: [11, 12, 13], cls: "biogas", grp: "grp-biogas" }, |
|||
"biogas": { cols: [11, 12, 13], cls: "biogas", grp: "grp-biogas" }, |
|||
"incinerator": { cols: [14, 15, 16], cls: "incinerator", grp: "grp-incinerator" }, |
|||
|
|||
"baling": { cols: [17, 18, 19], cls: "baling", grp: "grp-baling" }, |
|||
"pbc": { cols: [17, 18, 19], cls: "baling", grp: "grp-baling" }, |
|||
|
|||
"gwtc_waste": { cols: [20, 21, 22], cls: "gwtc", grp: "grp-gwtc" }, |
|||
"gw": { cols: [20, 21, 22], cls: "gwtc", grp: "grp-gwtc" }, |
|||
"tc": { cols: [20, 21, 22], cls: "gwtc", grp: "grp-gwtc" }, |
|||
|
|||
"cd": { cols: [23, 24, 25], cls: "cd", grp: "grp-cd" }, |
|||
"c&d": { cols: [23, 24, 25], cls: "cd", grp: "grp-cd" } |
|||
}; |
|||
|
|||
Object.keys(map).forEach(key => { |
|||
if (username.includes(key)) { |
|||
table.columns(map[key].cols).visible(true); |
|||
$('.' + map[key].cls).show(); |
|||
$('.' + map[key].grp).show(); |
|||
} |
|||
}); |
|||
|
|||
table.columns.adjust().draw(false); |
|||
} |
|||
|
|||
|
|||
|
|||
// function renderZoneTable(data) { |
|||
|
|||
// const zoneMap = {}; |
|||
|
|||
// data.forEach(row => { |
|||
// const zone = row.zone; |
|||
// const facility = row.facility; // MCC / Windrow / etc |
|||
|
|||
// if (!zoneMap[zone]) { |
|||
// zoneMap[zone] = { |
|||
// zone: zone |
|||
// }; |
|||
// } |
|||
|
|||
// // Target |
|||
// zoneMap[zone][facility + "_target"] = |
|||
// row.target !== null ? row.target : 0; |
|||
|
|||
// // Achieved |
|||
// zoneMap[zone][facility + "_achieved"] = |
|||
// row.achieved !== null ? row.achieved : 0; |
|||
|
|||
// // Percentage |
|||
// zoneMap[zone][facility + "_percentage"] = |
|||
// row.percentage !== null ? row.percentage + "%" : "0%"; |
|||
// }); |
|||
|
|||
// let i = 1; |
|||
// const tableData = Object.values(zoneMap).map(row => ({ |
|||
// sno: i++, |
|||
// ...row |
|||
// })); |
|||
|
|||
// table.clear().rows.add(tableData).draw(); |
|||
// } |
|||
|
|||
// function renderZoneTable(data) { |
|||
|
|||
// const zoneMap = {}; |
|||
|
|||
// data.forEach(row => { |
|||
// const zone = row.zone; |
|||
// const facility = normalizeFacilityName(row.facility); |
|||
|
|||
// if (!zoneMap[zone]) { |
|||
// zoneMap[zone] = { zone }; |
|||
// } |
|||
|
|||
// zoneMap[zone][facility + "_target"] = row.target ?? 0; |
|||
// zoneMap[zone][facility + "_achieved"] = row.achieved ?? 0; |
|||
// zoneMap[zone][facility + "_percentage"] = |
|||
// row.percentage != null ? row.percentage + "%" : "0%"; |
|||
// }); |
|||
|
|||
// let i = 1; |
|||
// const tableData = Object.values(zoneMap).map(r => ({ |
|||
// sno: i++, |
|||
// ...r |
|||
// })); |
|||
|
|||
// table.clear().rows.add(tableData).draw(); |
|||
// } |
|||
|
|||
function renderZoneTable(data) { |
|||
|
|||
const zoneMap = {}; |
|||
|
|||
data.forEach(row => { |
|||
const zone = row.zone; |
|||
const facilityKey = normalizeFacilityName(row.facility); |
|||
|
|||
if (!zoneMap[zone]) { |
|||
zoneMap[zone] = { zone }; |
|||
} |
|||
|
|||
zoneMap[zone][facilityKey + "_target"] = row.target ?? 0; |
|||
zoneMap[zone][facilityKey + "_achieved"] = row.achieved ?? 0; |
|||
zoneMap[zone][facilityKey + "_percentage"] = |
|||
row.percentage != null ? row.percentage + "%" : "0%"; |
|||
}); |
|||
|
|||
let i = 1; |
|||
const tableData = Object.values(zoneMap).map(r => ({ |
|||
sno: i++, |
|||
...r |
|||
})); |
|||
|
|||
table.clear().rows.add(tableData).draw(); |
|||
} |
|||
|
|||
|
|||
|
|||
function loadLoginWiseReport() { |
|||
|
|||
const fromDate = $("#fromDate").val(); |
|||
const toDate = $("#toDate").val(); |
|||
const username = $("#userName").val(); |
|||
|
|||
if (!fromDate || !toDate) { |
|||
Swal.fire("Validation", "Select both dates", "warning"); |
|||
return; |
|||
} |
|||
|
|||
$.ajax({ |
|||
url: "/swm/api/facilities/reports", |
|||
type: "GET", |
|||
data: { |
|||
username: username, |
|||
fromDate: fromDate, |
|||
toDate: toDate |
|||
}, |
|||
beforeSend: function () { |
|||
Swal.fire({ |
|||
title: "Loading...", |
|||
allowOutsideClick: false, |
|||
didOpen: () => Swal.showLoading() |
|||
}); |
|||
}, |
|||
success: function (res) { |
|||
console.log(res); |
|||
Swal.close(); |
|||
renderZoneTable(res.data); |
|||
}, |
|||
error: function () { |
|||
Swal.fire("Error", "Failed to load report", "error"); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
|
|||
|
|||
</script> |
|||
</body> |
|||
|
|||
</html> |
|||
@ -1,447 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en" xmlns:th="http://www.thymeleaf.org"> |
|||
|
|||
<head th:replace="~{fragments/modules/base/head :: head}"></head> |
|||
<style> |
|||
.width1 { |
|||
width: 120px; |
|||
} |
|||
|
|||
.width2 { |
|||
width: 150px; |
|||
} |
|||
|
|||
.modal-label { |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.modal-value { |
|||
color: #444; |
|||
} |
|||
|
|||
.modal-section-title { |
|||
font-size: 1.2rem; |
|||
font-weight: bold; |
|||
margin-top: 20px; |
|||
margin-bottom: 10px; |
|||
border-bottom: 2px solid #dee2e6; |
|||
padding-bottom: 5px; |
|||
} |
|||
|
|||
|
|||
.modal-title-big { |
|||
font-size: 20px; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
.modal-subtext { |
|||
color: #b4c5d3; |
|||
font-size: 13px; |
|||
} |
|||
|
|||
.card-section { |
|||
background: white; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
margin-bottom: 25px; |
|||
border: 1px solid #eee; |
|||
} |
|||
|
|||
.section-title { |
|||
font-weight: 700; |
|||
color: #333; |
|||
margin-bottom: 15px; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.label-text { |
|||
font-size: 13px; |
|||
color: #6c757d; |
|||
} |
|||
|
|||
.value-text { |
|||
font-size: 15px; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.info-block { |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
|
|||
.badge-status { |
|||
background: #ffd9b3; |
|||
color: #a65c00; |
|||
padding: 6px 10px; |
|||
border-radius: 5px; |
|||
font-size: 13px; |
|||
|
|||
} |
|||
|
|||
.btn-big { |
|||
padding: 12px 25px; |
|||
border-radius: 8px; |
|||
width: 200px; |
|||
} |
|||
|
|||
.rdo-box { |
|||
border: 1px solid #eee; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
} |
|||
</style> |
|||
|
|||
<body> |
|||
|
|||
<div class="wrapper"> |
|||
<!-- header top menu Start --> |
|||
<header th:replace="~{fragments/modules/base/header :: header}"></header> |
|||
<!-- header top menu end --> |
|||
<div class="page-wrap"> |
|||
<!--=============== Left Menu side Start ================--> |
|||
<div th:replace="~{fragments/modules/base/menu :: menu}"></div> |
|||
<!--=============== Left side End ================--> |
|||
<div class="main-content"> |
|||
<div class="container-fluid"> |
|||
<div class="page-header"> |
|||
<div class="row align-items-end"> |
|||
<div class="col-lg-6"> |
|||
<div class="page-header-title"> |
|||
<i class="fa fa-list-alt bg-blue"></i> |
|||
<div class="d-inline"> |
|||
<h5>SWD GW&TC Waste Facilities Add Details List</h5> |
|||
<span>GW&TC Waste Add Details</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-6"> |
|||
<nav class="breadcrumb-container" aria-label="breadcrumb"> |
|||
<ol class="breadcrumb"> |
|||
<li class="breadcrumb-item"> |
|||
<a href="/swm/index"><i class="ik ik-home"></i></a> |
|||
</li> |
|||
<li class="breadcrumb-item" aria-current="page">SWD GW&TC Waste Facilities Add |
|||
Details List |
|||
</li> |
|||
<li class="breadcrumb-item active" aria-current="page">GW&TC Waste Add Details |
|||
</li> |
|||
</ol> |
|||
</nav> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="row mt-4"> |
|||
|
|||
<div class="col-md-12"> |
|||
<div class="card"> |
|||
<div class="card-header d-flex justify-content-between align-items-center fw-bold"> |
|||
<h3 class="mb-0"> SWD GW&TC Waste Add Details : <span |
|||
th:text="${officer_name}"></span></h3> |
|||
<input type="hidden" id="userName" th:value="${officer_name}"> |
|||
</div> |
|||
|
|||
<div class="card-body"> |
|||
<div class="row"> |
|||
<div class="col-md-3"> |
|||
<label for="date" class="form-label" |
|||
style="font-size: medium;">Date:</label><span |
|||
class="text-danger">*</span> |
|||
<input type="date" id="date" class="form-control"> |
|||
</div> |
|||
<div class="col-md-3"> |
|||
<label for="zones" class="form-label">Zones <span |
|||
class="text-danger">*</span> |
|||
</label> <select id="zones" class="form-control"> |
|||
<option value="">Select zones</option> |
|||
|
|||
</select> |
|||
</div> |
|||
|
|||
|
|||
|
|||
<div class="col-md-3"> |
|||
|
|||
<label for="weight" class="form-label">Enter Weight for Garden |
|||
Waste:(in MT)</label><span class="text-danger">*</span> |
|||
<input type="number" class="form-control" id="weight"> |
|||
</div> |
|||
|
|||
<input type="hidden" id="facilityTypeId" th:value="${facilityTypeId}"> |
|||
|
|||
|
|||
<!-- SECOND WEIGHT (TC) --> |
|||
<div class="col-md-3"> |
|||
<label for="weight1" class="form-label">Enter Weight Tender Coconut:(in |
|||
MT)</label><span class="text-danger">*</span> |
|||
<input type="number" class="form-control" id="weight1"> |
|||
</div> |
|||
|
|||
|
|||
<div class="col-md-3" id="weightTypeDiv"> |
|||
<label class="form-label">Location<span class="text-danger">*</span></label> |
|||
<select id="facilitytype" class="form-control"> |
|||
<option value="">Select</option> |
|||
<option value="KDG">KDG</option> |
|||
<option value="PDG">PDG</option> |
|||
</select> |
|||
</div> |
|||
|
|||
<div class="col-md-3" style="margin-top: 30px;"> |
|||
<button id="submitBtn" class="btn btn-primary">Submit</button> |
|||
<button id="resetBtn" class="btn btn-secondary">Reset</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
<div id="pageLoader" |
|||
style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); z-index: 9999; text-align: center;"> |
|||
<div style="position: relative; top: 50%; transform: translateY(-50%);"> |
|||
<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;"> |
|||
<span class="sr-only">Loading...</span> |
|||
</div> |
|||
<!-- Add the 'Please wait' text below the spinner --> |
|||
<p style="margin-top: 1rem; font-size: 1.2rem; color: #007bff;">Please wait...</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div th:replace="~{fragments/modules/base/app_module_menu_box :: div}"></div> |
|||
|
|||
<footer th:replace="~{fragments/modules/base/footer :: footer}"></footer> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Details Modal --> |
|||
<div class="modal fade" id="detailsModal" tabindex="-1" aria-hidden="true"> |
|||
<div class="modal-dialog modal-xl modal-dialog-scrollable"> |
|||
<div class="modal-content"> |
|||
|
|||
<div class="modal-header" style="background:#2f3e54; color:white;"> |
|||
<div> |
|||
<h4 class="modal-title-big" id="modalTitle"></h4> |
|||
<div id="modalSubTitle" class="modal-subtext"></div> |
|||
</div> |
|||
|
|||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span |
|||
aria-hidden="true">×</span></button> |
|||
</div> |
|||
|
|||
<div class="modal-body"> |
|||
|
|||
<div id="modalContent"></div> |
|||
|
|||
<div class="text-center mt-4"> |
|||
<button type="button" class="btn btn-primary btn-big" data-dismiss="modal" |
|||
style="background:#2f3e54;">Close</button> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
<script th:replace="~{fragments/modules/base/script :: script}"></script> |
|||
<script type="text/javascript"> |
|||
|
|||
$(document).ready(function () { |
|||
|
|||
const today = new Date(); |
|||
const day = today.getDay(); // 0=Sun, 1=Mon, ..., 6=Sat |
|||
|
|||
/* ============================= |
|||
LAST SATURDAY |
|||
============================= */ |
|||
const lastSaturday = new Date(today); |
|||
|
|||
// If today is Saturday (6) → today |
|||
// Else → go back to previous Saturday |
|||
const diffToLastSaturday = (day >= 6) |
|||
? day - 6 |
|||
: day + 1; |
|||
|
|||
lastSaturday.setDate(today.getDate() - diffToLastSaturday); |
|||
|
|||
/* ============================= |
|||
THIS WEEK FRIDAY |
|||
============================= */ |
|||
const thisFriday = new Date(today); |
|||
|
|||
// Friday = 5 |
|||
const diffToFriday = (5 - day + 7) % 7; |
|||
thisFriday.setDate(today.getDate() + diffToFriday); |
|||
|
|||
/* ============================= |
|||
FORMAT YYYY-MM-DD |
|||
============================= */ |
|||
const formatDate = (d) => d.toISOString().split("T")[0]; |
|||
|
|||
const minDate = formatDate(lastSaturday); |
|||
const maxDate = formatDate(thisFriday); |
|||
|
|||
/* ============================= |
|||
APPLY LIMITS |
|||
============================= */ |
|||
$("#date") |
|||
.attr("min", minDate) |
|||
.attr("max", maxDate) |
|||
.val(formatDate(today)); |
|||
|
|||
// 🔒 BLOCK MANUAL TYPING (BUT ALLOW CALENDAR) |
|||
$("#date").on("keydown paste", function (e) { |
|||
e.preventDefault(); |
|||
}); |
|||
}); |
|||
|
|||
$(document).ready(function () { |
|||
const isTwoWeightFacility = |
|||
$("body").data("two-weight") === true || |
|||
$("body").data("two-weight") === "true"; |
|||
|
|||
console.log($("body").data("two-weight")); |
|||
|
|||
|
|||
if (isTwoWeightFacility) { |
|||
$("#weight2Div").show(); |
|||
|
|||
} else { |
|||
$("#weight2Div").hide(); |
|||
$("#weight1").val(""); |
|||
|
|||
} |
|||
}); |
|||
|
|||
|
|||
$(document).ready(function () { |
|||
const today = new Date().toISOString().split('T')[0]; |
|||
$("#date").val(today); |
|||
}); |
|||
|
|||
$("#resetBtn").on("click", function () { |
|||
location.reload(); |
|||
}); |
|||
|
|||
// Load zones when page loads |
|||
$(document).ready(function () { |
|||
|
|||
$.ajax({ |
|||
url: "/swm/api/dropdown/getzoneslist", |
|||
type: "GET", |
|||
dataType: "json", |
|||
success: function (data) { |
|||
|
|||
let zoneDropdown = $("#zones"); |
|||
zoneDropdown.empty(); |
|||
zoneDropdown.append("<option value=''>Select Zone</option>"); |
|||
|
|||
$.each(data, function (index, item) { |
|||
zoneDropdown.append( |
|||
`<option value="${item.id}">${item.zone_name}</option>` |
|||
); |
|||
}); |
|||
}, |
|||
error: function (xhr, status, error) { |
|||
console.error("Error fetching zones:", error); |
|||
} |
|||
}); |
|||
|
|||
}); |
|||
|
|||
|
|||
|
|||
$("#submitBtn").on("click", function (e) { |
|||
e.preventDefault(); |
|||
|
|||
const facilityTypeId = $("#facilityTypeId").val(); // ✅ dynamic |
|||
const zoneId = $("#zones").val(); |
|||
const reqDate = $("#date").val(); |
|||
const weight = $("#weight").val(); |
|||
const weight1 = $("#weight1").val(); |
|||
const createdBy = $("#userName").val(); |
|||
const weightType = $("#facilitytype").val(); |
|||
|
|||
// 🔴 Client-side validations |
|||
if (!zoneId) { |
|||
Swal.fire("Validation Error", "Please select zone", "warning"); |
|||
return; |
|||
} |
|||
|
|||
if (!reqDate) { |
|||
Swal.fire("Validation Error", "Date is required", "warning"); |
|||
return; |
|||
} |
|||
|
|||
if (!weight || weight == "") { |
|||
Swal.fire("Validation Error", "Weight is required", "warning"); |
|||
return; |
|||
} |
|||
// if (!weight || weight <= 0) { |
|||
// Swal.fire("Validation Error", "Weight must be greater than zero", "warning"); |
|||
// return; |
|||
// } |
|||
|
|||
// ⚠️ Note: |
|||
// Facility type 5 validation is done in BACKEND |
|||
// because facilityTypeId is derived after login |
|||
|
|||
$.ajax({ |
|||
url: "/swm/api/admin/addfacility", |
|||
type: "POST", |
|||
data: { |
|||
facilityTypeId: facilityTypeId, |
|||
zoneId: zoneId, |
|||
reqDate: reqDate, |
|||
weight: weight, |
|||
weight1: weight1, |
|||
weightType: weightType, |
|||
createdBy: createdBy // backend will ignore if not needed |
|||
}, |
|||
beforeSend: function () { |
|||
Swal.fire({ |
|||
title: "Saving...", |
|||
text: "Please wait", |
|||
allowOutsideClick: false, |
|||
didOpen: () => Swal.showLoading() |
|||
}); |
|||
}, |
|||
success: function (response) { |
|||
Swal.fire("Success", response.message, "success"); |
|||
|
|||
// Reset fields |
|||
$("#weight").val(""); |
|||
$("#weight1").val(""); |
|||
}, |
|||
error: function (xhr) { |
|||
let msg = "Something went wrong"; |
|||
|
|||
if (xhr.responseJSON && xhr.responseJSON.message) { |
|||
msg = xhr.responseJSON.message; |
|||
} |
|||
|
|||
Swal.fire("Error", msg, "error"); |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
|
|||
</script> |
|||
</body> |
|||
|
|||
</html> |
|||
@ -1,421 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en" xmlns:th="http://www.thymeleaf.org"> |
|||
|
|||
<head th:replace="~{fragments/modules/base/head :: head}"></head> |
|||
<style> |
|||
.width1 { |
|||
width: 120px; |
|||
} |
|||
|
|||
.width2 { |
|||
width: 150px; |
|||
} |
|||
|
|||
.modal-label { |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.modal-value { |
|||
color: #444; |
|||
} |
|||
|
|||
.modal-section-title { |
|||
font-size: 1.2rem; |
|||
font-weight: bold; |
|||
margin-top: 20px; |
|||
margin-bottom: 10px; |
|||
border-bottom: 2px solid #dee2e6; |
|||
padding-bottom: 5px; |
|||
} |
|||
|
|||
|
|||
.modal-title-big { |
|||
font-size: 20px; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
.modal-subtext { |
|||
color: #b4c5d3; |
|||
font-size: 13px; |
|||
} |
|||
|
|||
.card-section { |
|||
background: white; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
margin-bottom: 25px; |
|||
border: 1px solid #eee; |
|||
} |
|||
|
|||
.section-title { |
|||
font-weight: 700; |
|||
color: #333; |
|||
margin-bottom: 15px; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.label-text { |
|||
font-size: 13px; |
|||
color: #6c757d; |
|||
} |
|||
|
|||
.value-text { |
|||
font-size: 15px; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.info-block { |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
|
|||
.badge-status { |
|||
background: #ffd9b3; |
|||
color: #a65c00; |
|||
padding: 6px 10px; |
|||
border-radius: 5px; |
|||
font-size: 13px; |
|||
|
|||
} |
|||
|
|||
.btn-big { |
|||
padding: 12px 25px; |
|||
border-radius: 8px; |
|||
width: 200px; |
|||
} |
|||
|
|||
.rdo-box { |
|||
border: 1px solid #eee; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
} |
|||
</style> |
|||
|
|||
<body th:attr="data-two-weight=${isTwoWeightFacility}"> |
|||
|
|||
<div class="wrapper"> |
|||
<!-- header top menu Start --> |
|||
<header th:replace="~{fragments/modules/base/header :: header}"></header> |
|||
<!-- header top menu end --> |
|||
<div class="page-wrap"> |
|||
<!--=============== Left Menu side Start ================--> |
|||
<div th:replace="~{fragments/modules/base/menu :: menu}"></div> |
|||
<!--=============== Left side End ================--> |
|||
<div class="main-content"> |
|||
<div class="container-fluid"> |
|||
<div class="page-header"> |
|||
<div class="row align-items-end"> |
|||
<div class="col-lg-6"> |
|||
<div class="page-header-title"> |
|||
<i class="fa fa-list-alt bg-blue"></i> |
|||
<div class="d-inline"> |
|||
<h5>SWD Incinerator Facilities Add Details List</h5> |
|||
<span>Incinerator Add Details</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-6"> |
|||
<nav class="breadcrumb-container" aria-label="breadcrumb"> |
|||
<ol class="breadcrumb"> |
|||
<li class="breadcrumb-item"> |
|||
<a href="/swm/index"><i class="ik ik-home"></i></a> |
|||
</li> |
|||
<li class="breadcrumb-item" aria-current="page">SWD Incinerator Facilities Add |
|||
Details List |
|||
</li> |
|||
<li class="breadcrumb-item active" aria-current="page">Incinerator Add Details |
|||
</li> |
|||
</ol> |
|||
</nav> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="row mt-4"> |
|||
|
|||
<div class="col-md-12"> |
|||
<div class="card"> |
|||
<div class="card-header d-flex justify-content-between align-items-center fw-bold"> |
|||
<h3 class="mb-0"> SWD Incinerator Add Details : <span |
|||
th:text="${officer_name}"></span></h3> |
|||
<input type="hidden" id="userName" th:value="${officer_name}"> |
|||
</div> |
|||
|
|||
<div class="card-body"> |
|||
<div class="row"> |
|||
<div class="col-md-3"> |
|||
<label for="date" class="form-label" |
|||
style="font-size: medium;">Date:</label><span |
|||
class="text-danger">*</span> |
|||
<input type="date" id="date" class="form-control"> |
|||
</div> |
|||
<div class="col-md-3"> |
|||
<label for="zones" class="form-label">Zones <span |
|||
class="text-danger">*</span> |
|||
</label> <select id="zones" class="form-control"> |
|||
<option value="">Select days</option> |
|||
|
|||
</select> |
|||
</div> |
|||
|
|||
<div class="col-md-3"> |
|||
|
|||
<label for="weight" class="form-label">Enter Weight:(in MT)</label><span |
|||
class="text-danger">*</span> |
|||
<input type="number" class="form-control" id="weight"> |
|||
</div> |
|||
|
|||
<input type="hidden" id="facilityTypeId" th:value="${facilityTypeId}"> |
|||
|
|||
|
|||
<!-- SECOND WEIGHT (TC) --> |
|||
<div class="col-md-3" id="weight2Div" style="display:none;"> |
|||
<label for="weight1">Enter Weight (TC)</label><span |
|||
class="text-danger">*</span> |
|||
<input type="number" class="form-control" id="weight1"> |
|||
</div> |
|||
|
|||
<div class="col-md-3" style="margin-top: 30px;"> |
|||
<button id="submitBtn" class="btn btn-primary">Submit</button> |
|||
<button id="resetBtn" class="btn btn-secondary">Reset</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
<div id="pageLoader" |
|||
style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); z-index: 9999; text-align: center;"> |
|||
<div style="position: relative; top: 50%; transform: translateY(-50%);"> |
|||
<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;"> |
|||
<span class="sr-only">Loading...</span> |
|||
</div> |
|||
<!-- Add the 'Please wait' text below the spinner --> |
|||
<p style="margin-top: 1rem; font-size: 1.2rem; color: #007bff;">Please wait...</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div th:replace="~{fragments/modules/base/app_module_menu_box :: div}"></div> |
|||
|
|||
<footer th:replace="~{fragments/modules/base/footer :: footer}"></footer> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Details Modal --> |
|||
<div class="modal fade" id="detailsModal" tabindex="-1" aria-hidden="true"> |
|||
<div class="modal-dialog modal-xl modal-dialog-scrollable"> |
|||
<div class="modal-content"> |
|||
|
|||
<div class="modal-header" style="background:#2f3e54; color:white;"> |
|||
<div> |
|||
<h4 class="modal-title-big" id="modalTitle"></h4> |
|||
<div id="modalSubTitle" class="modal-subtext"></div> |
|||
</div> |
|||
|
|||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span |
|||
aria-hidden="true">×</span></button> |
|||
</div> |
|||
|
|||
<div class="modal-body"> |
|||
|
|||
<div id="modalContent"></div> |
|||
|
|||
<div class="text-center mt-4"> |
|||
<button type="button" class="btn btn-primary btn-big" data-dismiss="modal" |
|||
style="background:#2f3e54;">Close</button> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
<script th:replace="~{fragments/modules/base/script :: script}"></script> |
|||
<script type="text/javascript"> |
|||
|
|||
$(document).ready(function () { |
|||
|
|||
const today = new Date(); |
|||
const day = today.getDay(); // 0=Sun, 1=Mon, ..., 6=Sat |
|||
|
|||
/* ============================= |
|||
LAST SATURDAY |
|||
============================= */ |
|||
const lastSaturday = new Date(today); |
|||
|
|||
// If today is Saturday (6) → today |
|||
// Else → go back to previous Saturday |
|||
const diffToLastSaturday = (day >= 6) |
|||
? day - 6 |
|||
: day + 1; |
|||
|
|||
lastSaturday.setDate(today.getDate() - diffToLastSaturday); |
|||
|
|||
/* ============================= |
|||
THIS WEEK FRIDAY |
|||
============================= */ |
|||
const thisFriday = new Date(today); |
|||
|
|||
// Friday = 5 |
|||
const diffToFriday = (5 - day + 7) % 7; |
|||
thisFriday.setDate(today.getDate() + diffToFriday); |
|||
|
|||
/* ============================= |
|||
FORMAT YYYY-MM-DD |
|||
============================= */ |
|||
const formatDate = (d) => d.toISOString().split("T")[0]; |
|||
|
|||
const minDate = formatDate(lastSaturday); |
|||
const maxDate = formatDate(thisFriday); |
|||
|
|||
/* ============================= |
|||
APPLY LIMITS |
|||
============================= */ |
|||
$("#date") |
|||
.attr("min", minDate) |
|||
.attr("max", maxDate) |
|||
.val(formatDate(today)); |
|||
|
|||
// 🔒 BLOCK MANUAL TYPING (BUT ALLOW CALENDAR) |
|||
$("#date").on("keydown paste", function (e) { |
|||
e.preventDefault(); |
|||
}); |
|||
}); |
|||
|
|||
$(document).ready(function () { |
|||
const isTwoWeightFacility = |
|||
$("body").data("two-weight") === true || |
|||
$("body").data("two-weight") === "true"; |
|||
|
|||
console.log($("body").data("two-weight")); |
|||
|
|||
|
|||
if (isTwoWeightFacility) { |
|||
$("#weight2Div").show(); |
|||
} else { |
|||
$("#weight2Div").hide(); |
|||
$("#weight1").val(""); |
|||
} |
|||
}); |
|||
|
|||
|
|||
$(document).ready(function () { |
|||
const today = new Date().toISOString().split('T')[0]; |
|||
$("#date").val(today); |
|||
}); |
|||
|
|||
$("#resetBtn").on("click", function () { |
|||
location.reload(); |
|||
}); |
|||
|
|||
// Load zones when page loads |
|||
$(document).ready(function () { |
|||
|
|||
$.ajax({ |
|||
url: "/swm/api/dropdown/getzoneslist", |
|||
type: "GET", |
|||
dataType: "json", |
|||
success: function (data) { |
|||
|
|||
let zoneDropdown = $("#zones"); |
|||
zoneDropdown.empty(); |
|||
zoneDropdown.append("<option value=''>Select Zone</option>"); |
|||
|
|||
$.each(data, function (index, item) { |
|||
zoneDropdown.append( |
|||
`<option value="${item.id}">${item.zone_name}</option>` |
|||
); |
|||
}); |
|||
}, |
|||
error: function (xhr, status, error) { |
|||
console.error("Error fetching zones:", error); |
|||
} |
|||
}); |
|||
|
|||
}); |
|||
|
|||
|
|||
|
|||
$("#submitBtn").on("click", function (e) { |
|||
e.preventDefault(); |
|||
|
|||
const facilityTypeId = $("#facilityTypeId").val(); // ✅ dynamic |
|||
const zoneId = $("#zones").val(); |
|||
const reqDate = $("#date").val(); |
|||
const weight = $("#weight").val(); |
|||
const weight1 = $("#weight1").val(); |
|||
const createdBy = $("#userName").val(); |
|||
|
|||
// 🔴 Client-side validations |
|||
if (!zoneId) { |
|||
Swal.fire("Validation Error", "Please select zone", "warning"); |
|||
return; |
|||
} |
|||
|
|||
if (!reqDate) { |
|||
Swal.fire("Validation Error", "Date is required", "warning"); |
|||
return; |
|||
} |
|||
|
|||
if (!weight || weight <= 0) { |
|||
Swal.fire("Validation Error", "Weight must be greater than zero", "warning"); |
|||
return; |
|||
} |
|||
|
|||
// ⚠️ Note: |
|||
// Facility type 5 validation is done in BACKEND |
|||
// because facilityTypeId is derived after login |
|||
|
|||
$.ajax({ |
|||
url: "/swm/api/admin/addfacility", |
|||
type: "POST", |
|||
data: { |
|||
facilityTypeId: facilityTypeId, |
|||
zoneId: zoneId, |
|||
reqDate: reqDate, |
|||
weight: weight, |
|||
weight1: weight1, |
|||
createdBy: createdBy // backend will ignore if not needed |
|||
}, |
|||
beforeSend: function () { |
|||
Swal.fire({ |
|||
title: "Saving...", |
|||
text: "Please wait", |
|||
allowOutsideClick: false, |
|||
didOpen: () => Swal.showLoading() |
|||
}); |
|||
}, |
|||
success: function (response) { |
|||
Swal.fire("Success", response.message, "success"); |
|||
|
|||
// Reset fields |
|||
$("#weight").val(""); |
|||
$("#weight1").val(""); |
|||
}, |
|||
error: function (xhr) { |
|||
let msg = "Something went wrong"; |
|||
|
|||
if (xhr.responseJSON && xhr.responseJSON.message) { |
|||
msg = xhr.responseJSON.message; |
|||
} |
|||
|
|||
Swal.fire("Error", msg, "error"); |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
|
|||
</script> |
|||
</body> |
|||
|
|||
</html> |
|||
@ -1,428 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en" xmlns:th="http://www.thymeleaf.org"> |
|||
|
|||
<head th:replace="~{fragments/modules/base/head :: head}"></head> |
|||
<style> |
|||
.width1 { |
|||
width: 120px; |
|||
} |
|||
|
|||
.width2 { |
|||
width: 150px; |
|||
} |
|||
|
|||
.modal-label { |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.modal-value { |
|||
color: #444; |
|||
} |
|||
|
|||
.modal-section-title { |
|||
font-size: 1.2rem; |
|||
font-weight: bold; |
|||
margin-top: 20px; |
|||
margin-bottom: 10px; |
|||
border-bottom: 2px solid #dee2e6; |
|||
padding-bottom: 5px; |
|||
} |
|||
|
|||
|
|||
.modal-title-big { |
|||
font-size: 20px; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
.modal-subtext { |
|||
color: #b4c5d3; |
|||
font-size: 13px; |
|||
} |
|||
|
|||
.card-section { |
|||
background: white; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
margin-bottom: 25px; |
|||
border: 1px solid #eee; |
|||
} |
|||
|
|||
.section-title { |
|||
font-weight: 700; |
|||
color: #333; |
|||
margin-bottom: 15px; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.label-text { |
|||
font-size: 13px; |
|||
color: #6c757d; |
|||
} |
|||
|
|||
.value-text { |
|||
font-size: 15px; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.info-block { |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
|
|||
.badge-status { |
|||
background: #ffd9b3; |
|||
color: #a65c00; |
|||
padding: 6px 10px; |
|||
border-radius: 5px; |
|||
font-size: 13px; |
|||
|
|||
} |
|||
|
|||
.btn-big { |
|||
padding: 12px 25px; |
|||
border-radius: 8px; |
|||
width: 200px; |
|||
} |
|||
|
|||
.rdo-box { |
|||
border: 1px solid #eee; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
} |
|||
</style> |
|||
|
|||
<body th:attr="data-two-weight=${isTwoWeightFacility}"> |
|||
|
|||
<div class="wrapper"> |
|||
<!-- header top menu Start --> |
|||
<header th:replace="~{fragments/modules/base/header :: header}"></header> |
|||
<!-- header top menu end --> |
|||
<div class="page-wrap"> |
|||
<!--=============== Left Menu side Start ================--> |
|||
<div th:replace="~{fragments/modules/base/menu :: menu}"></div> |
|||
<!--=============== Left side End ================--> |
|||
<div class="main-content"> |
|||
<div class="container-fluid"> |
|||
<div class="page-header"> |
|||
<div class="row align-items-end"> |
|||
<div class="col-lg-6"> |
|||
<div class="page-header-title"> |
|||
<i class="fa fa-list-alt bg-blue"></i> |
|||
<div class="d-inline"> |
|||
<h5>SWD MCC Facilities Add Details List</h5> |
|||
<span> MCC Add Details</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-6"> |
|||
<nav class="breadcrumb-container" aria-label="breadcrumb"> |
|||
<ol class="breadcrumb"> |
|||
<li class="breadcrumb-item"> |
|||
<a href="/swm/index"><i class="ik ik-home"></i></a> |
|||
</li> |
|||
<li class="breadcrumb-item" aria-current="page">SWD MCC Facilities Add Details |
|||
List |
|||
</li> |
|||
<li class="breadcrumb-item active" aria-current="page">MCC Add Details</li> |
|||
</ol> |
|||
</nav> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="row mt-4"> |
|||
|
|||
<div class="col-md-12"> |
|||
<div class="card"> |
|||
<div class="card-header d-flex justify-content-between align-items-center fw-bold"> |
|||
<h3 class="mb-0"> SWM MCC Add Details : <span th:text="${officer_name}"></span></h3> |
|||
<input type="hidden" id="userName" th:value="${officer_name}"> |
|||
</div> |
|||
|
|||
<div class="card-body"> |
|||
<div class="row"> |
|||
<!-- <div class="col-md-3"> |
|||
<label for="date" class="form-label" |
|||
style="font-size: medium;">Date:</label> |
|||
<input type="date" id="date" class="form-control" readonly> |
|||
</div> --> |
|||
<div class="col-md-3"> |
|||
<label for="date" class="form-label" style="font-size: medium;"> |
|||
Date: |
|||
</label><span class="text-danger">*</span> |
|||
<input type="date" id="date" class="form-control"> |
|||
</div> |
|||
|
|||
<div class="col-md-3"> |
|||
<label for="zones" class="form-label">Zones <span |
|||
class="text-danger">*</span> |
|||
</label> <select id="zones" class="form-control"> |
|||
<option value="">Select zones</option> |
|||
|
|||
</select> |
|||
</div> |
|||
|
|||
<div class="col-md-3"> |
|||
|
|||
<label for="weight" class="form-label">Enter Weight:(in MT)</label><span |
|||
class="text-danger">*</span> |
|||
<input type="number" class="form-control" id="weight"> |
|||
</div> |
|||
|
|||
<input type="hidden" id="facilityTypeId" th:value="${facilityTypeId}"> |
|||
|
|||
|
|||
<!-- SECOND WEIGHT (TC) --> |
|||
<div class="col-md-3" id="weight2Div" style="display:none;"> |
|||
<label for="weight1">Enter Weight (TC)</label><span |
|||
class="text-danger">*</span> |
|||
<input type="number" class="form-control" id="weight1"> |
|||
</div> |
|||
|
|||
<div class="col-md-3" style="margin-top: 30px;"> |
|||
<button id="submitBtn" class="btn btn-primary">Submit</button> |
|||
<button id="resetBtn" class="btn btn-secondary">Reset</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
<div id="pageLoader" |
|||
style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); z-index: 9999; text-align: center;"> |
|||
<div style="position: relative; top: 50%; transform: translateY(-50%);"> |
|||
<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;"> |
|||
<span class="sr-only">Loading...</span> |
|||
</div> |
|||
<!-- Add the 'Please wait' text below the spinner --> |
|||
<p style="margin-top: 1rem; font-size: 1.2rem; color: #007bff;">Please wait...</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div th:replace="~{fragments/modules/base/app_module_menu_box :: div}"></div> |
|||
|
|||
<footer th:replace="~{fragments/modules/base/footer :: footer}"></footer> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Details Modal --> |
|||
<div class="modal fade" id="detailsModal" tabindex="-1" aria-hidden="true"> |
|||
<div class="modal-dialog modal-xl modal-dialog-scrollable"> |
|||
<div class="modal-content"> |
|||
|
|||
<div class="modal-header" style="background:#2f3e54; color:white;"> |
|||
<div> |
|||
<h4 class="modal-title-big" id="modalTitle"></h4> |
|||
<div id="modalSubTitle" class="modal-subtext"></div> |
|||
</div> |
|||
|
|||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span |
|||
aria-hidden="true">×</span></button> |
|||
</div> |
|||
|
|||
<div class="modal-body"> |
|||
|
|||
<div id="modalContent"></div> |
|||
|
|||
<div class="text-center mt-4"> |
|||
<button type="button" class="btn btn-primary btn-big" data-dismiss="modal" |
|||
style="background:#2f3e54;">Close</button> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
<script th:replace="~{fragments/modules/base/script :: script}"></script> |
|||
<script type="text/javascript"> |
|||
|
|||
|
|||
$(document).ready(function () { |
|||
|
|||
const today = new Date(); |
|||
const day = today.getDay(); // 0=Sun, 1=Mon, ..., 6=Sat |
|||
|
|||
/* ============================= |
|||
LAST SATURDAY |
|||
============================= */ |
|||
const lastSaturday = new Date(today); |
|||
|
|||
// If today is Saturday (6) → today |
|||
// Else → go back to previous Saturday |
|||
const diffToLastSaturday = (day >= 6) |
|||
? day - 6 |
|||
: day + 1; |
|||
|
|||
lastSaturday.setDate(today.getDate() - diffToLastSaturday); |
|||
|
|||
/* ============================= |
|||
THIS WEEK FRIDAY |
|||
============================= */ |
|||
const thisFriday = new Date(today); |
|||
|
|||
// Friday = 5 |
|||
const diffToFriday = (5 - day + 7) % 7; |
|||
thisFriday.setDate(today.getDate() + diffToFriday); |
|||
|
|||
/* ============================= |
|||
FORMAT YYYY-MM-DD |
|||
============================= */ |
|||
const formatDate = (d) => d.toISOString().split("T")[0]; |
|||
|
|||
const minDate = formatDate(lastSaturday); |
|||
const maxDate = formatDate(thisFriday); |
|||
|
|||
/* ============================= |
|||
APPLY LIMITS |
|||
============================= */ |
|||
$("#date") |
|||
.attr("min", minDate) |
|||
.attr("max", maxDate) |
|||
.val(formatDate(today)); |
|||
|
|||
// 🔒 BLOCK MANUAL TYPING (BUT ALLOW CALENDAR) |
|||
$("#date").on("keydown paste", function (e) { |
|||
e.preventDefault(); |
|||
}); |
|||
}); |
|||
|
|||
|
|||
|
|||
$(document).ready(function () { |
|||
const isTwoWeightFacility = |
|||
$("body").data("two-weight") === true || |
|||
$("body").data("two-weight") === "true"; |
|||
|
|||
console.log($("body").data("two-weight")); |
|||
|
|||
|
|||
if (isTwoWeightFacility) { |
|||
$("#weight2Div").show(); |
|||
} else { |
|||
$("#weight2Div").hide(); |
|||
$("#weight1").val(""); |
|||
} |
|||
}); |
|||
|
|||
|
|||
$(document).ready(function () { |
|||
const today = new Date().toISOString().split('T')[0]; |
|||
$("#date").val(today); |
|||
}); |
|||
|
|||
$("#resetBtn").on("click", function () { |
|||
location.reload(); |
|||
}); |
|||
|
|||
// Load zones when page loads |
|||
$(document).ready(function () { |
|||
|
|||
$.ajax({ |
|||
url: "/swm/api/dropdown/getzoneslist", |
|||
type: "GET", |
|||
dataType: "json", |
|||
success: function (data) { |
|||
|
|||
let zoneDropdown = $("#zones"); |
|||
zoneDropdown.empty(); |
|||
zoneDropdown.append("<option value=''>Select Zone</option>"); |
|||
|
|||
$.each(data, function (index, item) { |
|||
zoneDropdown.append( |
|||
`<option value="${item.id}">${item.zone_name}</option>` |
|||
); |
|||
}); |
|||
}, |
|||
error: function (xhr, status, error) { |
|||
console.error("Error fetching zones:", error); |
|||
} |
|||
}); |
|||
|
|||
}); |
|||
|
|||
|
|||
|
|||
$("#submitBtn").on("click", function (e) { |
|||
e.preventDefault(); |
|||
const facilityTypeId = $("#facilityTypeId").val(); // ✅ dynamic |
|||
const zoneId = $("#zones").val(); |
|||
const reqDate = $("#date").val(); |
|||
const weight = $("#weight").val(); |
|||
const weight1 = $("#weight1").val(); |
|||
const createdBy = $("#userName").val(); |
|||
|
|||
// 🔴 Client-side validations |
|||
if (!zoneId) { |
|||
Swal.fire("Validation Error", "Please select zone", "warning"); |
|||
return; |
|||
} |
|||
|
|||
if (!reqDate) { |
|||
Swal.fire("Validation Error", "Date is required", "warning"); |
|||
return; |
|||
} |
|||
|
|||
if (!weight || weight <= 0) { |
|||
Swal.fire("Validation Error", "Weight must be greater than zero", "warning"); |
|||
return; |
|||
} |
|||
|
|||
// ⚠️ Note: |
|||
// Facility type 5 validation is done in BACKEND |
|||
// because facilityTypeId is derived after login |
|||
|
|||
$.ajax({ |
|||
url: "/swm/api/admin/addfacility", |
|||
type: "POST", |
|||
data: { |
|||
facilityTypeId: facilityTypeId, |
|||
zoneId: zoneId, |
|||
reqDate: reqDate, |
|||
weight: weight, |
|||
weight1: weight1, |
|||
createdBy: createdBy // backend will ignore if not needed |
|||
}, |
|||
beforeSend: function () { |
|||
Swal.fire({ |
|||
title: "Saving...", |
|||
text: "Please wait", |
|||
allowOutsideClick: false, |
|||
didOpen: () => Swal.showLoading() |
|||
}); |
|||
}, |
|||
success: function (response) { |
|||
Swal.fire("Success", response.message, "success"); |
|||
|
|||
// Reset fields |
|||
$("#weight").val(""); |
|||
$("#weight1").val(""); |
|||
}, |
|||
error: function (xhr) { |
|||
let msg = "Something went wrong"; |
|||
|
|||
if (xhr.responseJSON && xhr.responseJSON.message) { |
|||
msg = xhr.responseJSON.message; |
|||
} |
|||
|
|||
Swal.fire("Error", msg, "error"); |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
|
|||
|
|||
</script> |
|||
</body> |
|||
|
|||
</html> |
|||
@ -1,424 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en" xmlns:th="http://www.thymeleaf.org"> |
|||
|
|||
<head th:replace="~{fragments/modules/base/head :: head}"></head> |
|||
<style> |
|||
.width1 { |
|||
width: 120px; |
|||
} |
|||
|
|||
.width2 { |
|||
width: 150px; |
|||
} |
|||
|
|||
.modal-label { |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.modal-value { |
|||
color: #444; |
|||
} |
|||
|
|||
.modal-section-title { |
|||
font-size: 1.2rem; |
|||
font-weight: bold; |
|||
margin-top: 20px; |
|||
margin-bottom: 10px; |
|||
border-bottom: 2px solid #dee2e6; |
|||
padding-bottom: 5px; |
|||
} |
|||
|
|||
|
|||
.modal-title-big { |
|||
font-size: 20px; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
.modal-subtext { |
|||
color: #b4c5d3; |
|||
font-size: 13px; |
|||
} |
|||
|
|||
.card-section { |
|||
background: white; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
margin-bottom: 25px; |
|||
border: 1px solid #eee; |
|||
} |
|||
|
|||
.section-title { |
|||
font-weight: 700; |
|||
color: #333; |
|||
margin-bottom: 15px; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.label-text { |
|||
font-size: 13px; |
|||
color: #6c757d; |
|||
} |
|||
|
|||
.value-text { |
|||
font-size: 15px; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.info-block { |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
|
|||
.badge-status { |
|||
background: #ffd9b3; |
|||
color: #a65c00; |
|||
padding: 6px 10px; |
|||
border-radius: 5px; |
|||
font-size: 13px; |
|||
|
|||
} |
|||
|
|||
.btn-big { |
|||
padding: 12px 25px; |
|||
border-radius: 8px; |
|||
width: 200px; |
|||
} |
|||
|
|||
.rdo-box { |
|||
border: 1px solid #eee; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
} |
|||
</style> |
|||
|
|||
<body th:attr="data-two-weight=${isTwoWeightFacility}"> |
|||
|
|||
<div class="wrapper"> |
|||
<!-- header top menu Start --> |
|||
<header th:replace="~{fragments/modules/base/header :: header}"></header> |
|||
<!-- header top menu end --> |
|||
<div class="page-wrap"> |
|||
<!--=============== Left Menu side Start ================--> |
|||
<div th:replace="~{fragments/modules/base/menu :: menu}"></div> |
|||
<!--=============== Left side End ================--> |
|||
<div class="main-content"> |
|||
<div class="container-fluid"> |
|||
<div class="page-header"> |
|||
<div class="row align-items-end"> |
|||
<div class="col-lg-6"> |
|||
<div class="page-header-title"> |
|||
<i class="fa fa-list-alt bg-blue"></i> |
|||
<div class="d-inline"> |
|||
<h5>SWD MRF OR RRC Facilities Add Details List</h5> |
|||
<span> MRF OR RRC Add Details</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-6"> |
|||
<nav class="breadcrumb-container" aria-label="breadcrumb"> |
|||
<ol class="breadcrumb"> |
|||
<li class="breadcrumb-item"> |
|||
<a href="/swm/index"><i class="ik ik-home"></i></a> |
|||
</li> |
|||
<li class="breadcrumb-item" aria-current="page">SWD MRF OR RRC Facilities Add |
|||
Details List |
|||
</li> |
|||
<li class="breadcrumb-item active" aria-current="page">MRF OR RRC Add Details |
|||
</li> |
|||
</ol> |
|||
</nav> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="row mt-4"> |
|||
|
|||
<div class="col-md-12"> |
|||
<div class="card"> |
|||
<div class="card-header d-flex justify-content-between align-items-center fw-bold"> |
|||
<h3 class="mb-0"> SWD MRF OR RRC Add Details : <span |
|||
th:text="${officer_name}"></span></h3> |
|||
<input type="hidden" id="userName" th:value="${officer_name}"> |
|||
</div> |
|||
|
|||
<div class="card-body"> |
|||
<div class="row"> |
|||
<div class="col-md-3"> |
|||
<label for="date" class="form-label" |
|||
style="font-size: medium;">Date:</label> |
|||
<input type="date" id="date" class="form-control"> |
|||
</div> |
|||
<div class="col-md-3"> |
|||
<label for="zones" class="form-label">Zones <span |
|||
class="text-danger">*</span> |
|||
</label> <select id="zones" class="form-control"> |
|||
<option value="">Select days</option> |
|||
|
|||
</select> |
|||
</div> |
|||
|
|||
<div class="col-md-3"> |
|||
|
|||
<label for="weight" class="form-label">Enter Weight:(in MT)</label> |
|||
<input type="number" class="form-control" id="weight"> |
|||
</div> |
|||
|
|||
<input type="hidden" id="facilityTypeId" th:value="${facilityTypeId}"> |
|||
|
|||
|
|||
<!-- SECOND WEIGHT (TC) --> |
|||
<div class="col-md-3" id="weight2Div" style="display:none;"> |
|||
<label for="weight1">Enter Weight (TC)</label> |
|||
<input type="number" class="form-control" id="weight1"> |
|||
</div> |
|||
|
|||
<div class="col-md-3" style="margin-top: 30px;"> |
|||
<button id="submitBtn" class="btn btn-primary">Submit</button> |
|||
<button id="resetBtn" class="btn btn-secondary">Reset</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
<div id="pageLoader" |
|||
style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); z-index: 9999; text-align: center;"> |
|||
<div style="position: relative; top: 50%; transform: translateY(-50%);"> |
|||
<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;"> |
|||
<span class="sr-only">Loading...</span> |
|||
</div> |
|||
<!-- Add the 'Please wait' text below the spinner --> |
|||
<p style="margin-top: 1rem; font-size: 1.2rem; color: #007bff;">Please wait...</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div th:replace="~{fragments/modules/base/app_module_menu_box :: div}"></div> |
|||
|
|||
<footer th:replace="~{fragments/modules/base/footer :: footer}"></footer> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Details Modal --> |
|||
<div class="modal fade" id="detailsModal" tabindex="-1" aria-hidden="true"> |
|||
<div class="modal-dialog modal-xl modal-dialog-scrollable"> |
|||
<div class="modal-content"> |
|||
|
|||
<div class="modal-header" style="background:#2f3e54; color:white;"> |
|||
<div> |
|||
<h4 class="modal-title-big" id="modalTitle"></h4> |
|||
<div id="modalSubTitle" class="modal-subtext"></div> |
|||
</div> |
|||
|
|||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span |
|||
aria-hidden="true">×</span></button> |
|||
</div> |
|||
|
|||
<div class="modal-body"> |
|||
|
|||
<div id="modalContent"></div> |
|||
|
|||
<div class="text-center mt-4"> |
|||
<button type="button" class="btn btn-primary btn-big" data-dismiss="modal" |
|||
style="background:#2f3e54;">Close</button> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
<script th:replace="~{fragments/modules/base/script :: script}"></script> |
|||
<script type="text/javascript"> |
|||
|
|||
$(document).ready(function () { |
|||
|
|||
const today = new Date(); |
|||
const day = today.getDay(); // 0=Sun, 1=Mon, ..., 6=Sat |
|||
|
|||
/* ============================= |
|||
LAST SATURDAY |
|||
============================= */ |
|||
const lastSaturday = new Date(today); |
|||
|
|||
// If today is Saturday (6) → today |
|||
// Else → go back to previous Saturday |
|||
const diffToLastSaturday = (day >= 6) |
|||
? day - 6 |
|||
: day + 1; |
|||
|
|||
lastSaturday.setDate(today.getDate() - diffToLastSaturday); |
|||
|
|||
/* ============================= |
|||
THIS WEEK FRIDAY |
|||
============================= */ |
|||
const thisFriday = new Date(today); |
|||
|
|||
// Friday = 5 |
|||
const diffToFriday = (5 - day + 7) % 7; |
|||
thisFriday.setDate(today.getDate() + diffToFriday); |
|||
|
|||
/* ============================= |
|||
FORMAT YYYY-MM-DD |
|||
============================= */ |
|||
const formatDate = (d) => d.toISOString().split("T")[0]; |
|||
|
|||
const minDate = formatDate(lastSaturday); |
|||
const maxDate = formatDate(thisFriday); |
|||
|
|||
/* ============================= |
|||
APPLY LIMITS |
|||
============================= */ |
|||
$("#date") |
|||
.attr("min", minDate) |
|||
.attr("max", maxDate) |
|||
.val(formatDate(today)); |
|||
|
|||
// 🔒 BLOCK MANUAL TYPING (BUT ALLOW CALENDAR) |
|||
$("#date").on("keydown paste", function (e) { |
|||
e.preventDefault(); |
|||
}); |
|||
}); |
|||
|
|||
$(document).ready(function () { |
|||
const isTwoWeightFacility = |
|||
$("body").data("two-weight") === true || |
|||
$("body").data("two-weight") === "true"; |
|||
|
|||
console.log($("body").data("two-weight")); |
|||
|
|||
|
|||
if (isTwoWeightFacility) { |
|||
$("#weight2Div").show(); |
|||
} else { |
|||
$("#weight2Div").hide(); |
|||
$("#weight1").val(""); |
|||
} |
|||
}); |
|||
|
|||
|
|||
$(document).ready(function () { |
|||
const today = new Date().toISOString().split('T')[0]; |
|||
$("#date").val(today); |
|||
}); |
|||
|
|||
$("#resetBtn").on("click", function () { |
|||
location.reload(); |
|||
}); |
|||
|
|||
// Load zones when page loads |
|||
$(document).ready(function () { |
|||
|
|||
$.ajax({ |
|||
url: "/swm/api/dropdown/getzoneslist", |
|||
type: "GET", |
|||
dataType: "json", |
|||
success: function (data) { |
|||
|
|||
let zoneDropdown = $("#zones"); |
|||
zoneDropdown.empty(); |
|||
zoneDropdown.append("<option value=''>Select Zone</option>"); |
|||
|
|||
$.each(data, function (index, item) { |
|||
zoneDropdown.append( |
|||
`<option value="${item.id}">${item.zone_name}</option>` |
|||
); |
|||
}); |
|||
}, |
|||
error: function (xhr, status, error) { |
|||
console.error("Error fetching zones:", error); |
|||
} |
|||
}); |
|||
|
|||
}); |
|||
|
|||
|
|||
|
|||
$("#submitBtn").on("click", function (e) { |
|||
e.preventDefault(); |
|||
|
|||
const facilityTypeId = $("#facilityTypeId").val(); // ✅ dynamic |
|||
const zoneId = $("#zones").val(); |
|||
const reqDate = $("#date").val(); |
|||
const weight = $("#weight").val(); |
|||
const weight1 = $("#weight1").val(); |
|||
const createdBy = $("#userName").val(); |
|||
|
|||
// 🔴 Client-side validations |
|||
if (!zoneId) { |
|||
Swal.fire("Validation Error", "Please select zone", "warning"); |
|||
return; |
|||
} |
|||
|
|||
if (!reqDate) { |
|||
Swal.fire("Validation Error", "Date is required", "warning"); |
|||
return; |
|||
} |
|||
|
|||
if (!weight || weight <= 0) { |
|||
Swal.fire("Validation Error", "Weight must be greater than zero", "warning"); |
|||
return; |
|||
} |
|||
|
|||
// ⚠️ Note: |
|||
// Facility type 5 validation is done in BACKEND |
|||
// because facilityTypeId is derived after login |
|||
|
|||
$.ajax({ |
|||
url: "/swm/api/admin/addfacility", |
|||
type: "POST", |
|||
data: { |
|||
facilityTypeId: facilityTypeId, |
|||
zoneId: zoneId, |
|||
reqDate: reqDate, |
|||
weight: weight, |
|||
weight1: weight1, |
|||
createdBy: createdBy // backend will ignore if not needed |
|||
}, |
|||
beforeSend: function () { |
|||
Swal.fire({ |
|||
title: "Saving...", |
|||
text: "Please wait", |
|||
allowOutsideClick: false, |
|||
didOpen: () => Swal.showLoading() |
|||
}); |
|||
}, |
|||
success: function (response) { |
|||
Swal.fire("Success", response.message, "success"); |
|||
|
|||
// Reset fields |
|||
$("#weight").val(""); |
|||
$("#weight1").val(""); |
|||
}, |
|||
error: function (xhr) { |
|||
let msg = "Something went wrong"; |
|||
|
|||
if (xhr.responseJSON && xhr.responseJSON.message) { |
|||
msg = xhr.responseJSON.message; |
|||
} |
|||
|
|||
Swal.fire("Error", msg, "error"); |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
|
|||
</script> |
|||
</body> |
|||
|
|||
</html> |
|||
@ -1,418 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en" xmlns:th="http://www.thymeleaf.org"> |
|||
|
|||
<head th:replace="~{fragments/modules/base/head :: head}"></head> |
|||
<style> |
|||
.width1 { |
|||
width: 120px; |
|||
} |
|||
|
|||
.width2 { |
|||
width: 150px; |
|||
} |
|||
|
|||
.modal-label { |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.modal-value { |
|||
color: #444; |
|||
} |
|||
|
|||
.modal-section-title { |
|||
font-size: 1.2rem; |
|||
font-weight: bold; |
|||
margin-top: 20px; |
|||
margin-bottom: 10px; |
|||
border-bottom: 2px solid #dee2e6; |
|||
padding-bottom: 5px; |
|||
} |
|||
|
|||
|
|||
.modal-title-big { |
|||
font-size: 20px; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
.modal-subtext { |
|||
color: #b4c5d3; |
|||
font-size: 13px; |
|||
} |
|||
|
|||
.card-section { |
|||
background: white; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
margin-bottom: 25px; |
|||
border: 1px solid #eee; |
|||
} |
|||
|
|||
.section-title { |
|||
font-weight: 700; |
|||
color: #333; |
|||
margin-bottom: 15px; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.label-text { |
|||
font-size: 13px; |
|||
color: #6c757d; |
|||
} |
|||
|
|||
.value-text { |
|||
font-size: 15px; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.info-block { |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
|
|||
.badge-status { |
|||
background: #ffd9b3; |
|||
color: #a65c00; |
|||
padding: 6px 10px; |
|||
border-radius: 5px; |
|||
font-size: 13px; |
|||
|
|||
} |
|||
|
|||
.btn-big { |
|||
padding: 12px 25px; |
|||
border-radius: 8px; |
|||
width: 200px; |
|||
} |
|||
|
|||
.rdo-box { |
|||
border: 1px solid #eee; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
} |
|||
</style> |
|||
|
|||
<body th:attr="data-two-weight=${isTwoWeightFacility}"> |
|||
|
|||
<div class="wrapper"> |
|||
<!-- header top menu Start --> |
|||
<header th:replace="~{fragments/modules/base/header :: header}"></header> |
|||
<!-- header top menu end --> |
|||
<div class="page-wrap"> |
|||
<!--=============== Left Menu side Start ================--> |
|||
<div th:replace="~{fragments/modules/base/menu :: menu}"></div> |
|||
<!--=============== Left side End ================--> |
|||
<div class="main-content"> |
|||
<div class="container-fluid"> |
|||
<div class="page-header"> |
|||
<div class="row align-items-end"> |
|||
<div class="col-lg-6"> |
|||
<div class="page-header-title"> |
|||
<i class="fa fa-list-alt bg-blue"></i> |
|||
<div class="d-inline"> |
|||
<h5>SWD Plasting Baling Facilities Add Details List</h5> |
|||
<span>Plasting Baling Add Details</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-6"> |
|||
<nav class="breadcrumb-container" aria-label="breadcrumb"> |
|||
<ol class="breadcrumb"> |
|||
<li class="breadcrumb-item"> |
|||
<a href="/swm/index"><i class="ik ik-home"></i></a> |
|||
</li> |
|||
<li class="breadcrumb-item" aria-current="page">SWD Plasting Baling Facilities |
|||
Add Details List |
|||
</li> |
|||
<li class="breadcrumb-item active" aria-current="page">Plasting Baling Add |
|||
Details</li> |
|||
</ol> |
|||
</nav> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="row mt-4"> |
|||
|
|||
<div class="col-md-12"> |
|||
<div class="card"> |
|||
<div class="card-header d-flex justify-content-between align-items-center fw-bold"> |
|||
<h3 class="mb-0"> SWD Plasting Baling Add Details : <span |
|||
th:text="${officer_name}"></span></h3> |
|||
<input type="hidden" id="userName" th:value="${officer_name}"> |
|||
</div> |
|||
|
|||
<div class="card-body"> |
|||
<div class="row"> |
|||
<div class="col-md-3"> |
|||
<label for="date" class="form-label" |
|||
style="font-size: medium;">Date:</label><span |
|||
class="text-danger">*</span> |
|||
<input type="date" id="date" class="form-control"> |
|||
</div> |
|||
<div class="col-md-3"> |
|||
<label for="zones" class="form-label">Zones <span |
|||
class="text-danger">*</span> |
|||
</label> <select id="zones" class="form-control"> |
|||
<option value="">Select days</option> |
|||
|
|||
</select> |
|||
</div> |
|||
<input type="hidden" id="facilityTypeId" th:value="${facilityTypeId}"> |
|||
|
|||
|
|||
<div class="col-md-3"> |
|||
|
|||
<label for="weight" class="form-label">Enter Weight:(in MT)</label><span |
|||
class="text-danger">*</span> |
|||
<input type="number" class="form-control" id="weight"> |
|||
</div> |
|||
|
|||
<!-- SECOND WEIGHT (TC) --> |
|||
<div class="col-md-3" id="weight2Div" style="display:none;"> |
|||
<label for="weight1">Enter Weight (TC)</label><span |
|||
class="text-danger">*</span> |
|||
<input type="number" class="form-control" id="weight1"> |
|||
</div> |
|||
|
|||
<div class="col-md-3" style="margin-top: 30px;"> |
|||
<button id="submitBtn" class="btn btn-primary">Submit</button> |
|||
<button id="resetBtn" class="btn btn-secondary">Reset</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
<div id="pageLoader" |
|||
style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); z-index: 9999; text-align: center;"> |
|||
<div style="position: relative; top: 50%; transform: translateY(-50%);"> |
|||
<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;"> |
|||
<span class="sr-only">Loading...</span> |
|||
</div> |
|||
<!-- Add the 'Please wait' text below the spinner --> |
|||
<p style="margin-top: 1rem; font-size: 1.2rem; color: #007bff;">Please wait...</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div th:replace="~{fragments/modules/base/app_module_menu_box :: div}"></div> |
|||
|
|||
<footer th:replace="~{fragments/modules/base/footer :: footer}"></footer> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Details Modal --> |
|||
<div class="modal fade" id="detailsModal" tabindex="-1" aria-hidden="true"> |
|||
<div class="modal-dialog modal-xl modal-dialog-scrollable"> |
|||
<div class="modal-content"> |
|||
|
|||
<div class="modal-header" style="background:#2f3e54; color:white;"> |
|||
<div> |
|||
<h4 class="modal-title-big" id="modalTitle"></h4> |
|||
<div id="modalSubTitle" class="modal-subtext"></div> |
|||
</div> |
|||
|
|||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span |
|||
aria-hidden="true">×</span></button> |
|||
</div> |
|||
|
|||
<div class="modal-body"> |
|||
|
|||
<div id="modalContent"></div> |
|||
|
|||
<div class="text-center mt-4"> |
|||
<button type="button" class="btn btn-primary btn-big" data-dismiss="modal" |
|||
style="background:#2f3e54;">Close</button> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
<script th:replace="~{fragments/modules/base/script :: script}"></script> |
|||
<script type="text/javascript"> |
|||
|
|||
$(document).ready(function () { |
|||
|
|||
const today = new Date(); |
|||
const day = today.getDay(); // 0=Sun, 1=Mon, ..., 6=Sat |
|||
|
|||
/* ============================= |
|||
LAST SATURDAY |
|||
============================= */ |
|||
const lastSaturday = new Date(today); |
|||
|
|||
// If today is Saturday (6) → today |
|||
// Else → go back to previous Saturday |
|||
const diffToLastSaturday = (day >= 6) |
|||
? day - 6 |
|||
: day + 1; |
|||
|
|||
lastSaturday.setDate(today.getDate() - diffToLastSaturday); |
|||
|
|||
/* ============================= |
|||
THIS WEEK FRIDAY |
|||
============================= */ |
|||
const thisFriday = new Date(today); |
|||
|
|||
// Friday = 5 |
|||
const diffToFriday = (5 - day + 7) % 7; |
|||
thisFriday.setDate(today.getDate() + diffToFriday); |
|||
|
|||
/* ============================= |
|||
FORMAT YYYY-MM-DD |
|||
============================= */ |
|||
const formatDate = (d) => d.toISOString().split("T")[0]; |
|||
|
|||
const minDate = formatDate(lastSaturday); |
|||
const maxDate = formatDate(thisFriday); |
|||
|
|||
/* ============================= |
|||
APPLY LIMITS |
|||
============================= */ |
|||
$("#date") |
|||
.attr("min", minDate) |
|||
.attr("max", maxDate) |
|||
.val(formatDate(today)); |
|||
// 🔒 BLOCK MANUAL TYPING (BUT ALLOW CALENDAR) |
|||
$("#date").on("keydown paste", function (e) { |
|||
e.preventDefault(); |
|||
}); |
|||
}); |
|||
|
|||
$(document).ready(function () { |
|||
const isTwoWeightFacility = |
|||
$("body").data("two-weight") === true || |
|||
$("body").data("two-weight") === "true"; |
|||
|
|||
console.log($("body").data("two-weight")); |
|||
|
|||
|
|||
if (isTwoWeightFacility) { |
|||
$("#weight2Div").show(); |
|||
} else { |
|||
$("#weight2Div").hide(); |
|||
$("#weight1").val(""); |
|||
} |
|||
}); |
|||
|
|||
|
|||
$(document).ready(function () { |
|||
const today = new Date().toISOString().split('T')[0]; |
|||
$("#date").val(today); |
|||
}); |
|||
|
|||
$("#resetBtn").on("click", function () { |
|||
location.reload(); |
|||
}); |
|||
|
|||
// Load zones when page loads |
|||
$(document).ready(function () { |
|||
|
|||
$.ajax({ |
|||
url: "/swm/api/dropdown/getzoneslist", |
|||
type: "GET", |
|||
dataType: "json", |
|||
success: function (data) { |
|||
|
|||
let zoneDropdown = $("#zones"); |
|||
zoneDropdown.empty(); |
|||
zoneDropdown.append("<option value=''>Select Zone</option>"); |
|||
|
|||
$.each(data, function (index, item) { |
|||
zoneDropdown.append( |
|||
`<option value="${item.id}">${item.zone_name}</option>` |
|||
); |
|||
}); |
|||
}, |
|||
error: function (xhr, status, error) { |
|||
console.error("Error fetching zones:", error); |
|||
} |
|||
}); |
|||
|
|||
}); |
|||
|
|||
|
|||
|
|||
$("#submitBtn").on("click", function (e) { |
|||
e.preventDefault(); |
|||
|
|||
const facilityTypeId = $("#facilityTypeId").val(); // ✅ dynamic |
|||
const zoneId = $("#zones").val(); |
|||
const reqDate = $("#date").val(); |
|||
const weight = $("#weight").val(); |
|||
const weight1 = $("#weight1").val(); |
|||
const createdBy = $("#userName").val(); |
|||
|
|||
// 🔴 Client-side validations |
|||
if (!zoneId) { |
|||
Swal.fire("Validation Error", "Please select zone", "warning"); |
|||
return; |
|||
} |
|||
|
|||
if (!reqDate) { |
|||
Swal.fire("Validation Error", "Date is required", "warning"); |
|||
return; |
|||
} |
|||
|
|||
if (!weight || weight <= 0) { |
|||
Swal.fire("Validation Error", "Weight must be greater than zero", "warning"); |
|||
return; |
|||
} |
|||
|
|||
// ⚠️ Note: |
|||
// Facility type 5 validation is done in BACKEND |
|||
// because facilityTypeId is derived after login |
|||
|
|||
$.ajax({ |
|||
url: "/swm/api/admin/addfacility", |
|||
type: "POST", |
|||
data: { |
|||
facilityTypeId: facilityTypeId, |
|||
zoneId: zoneId, |
|||
reqDate: reqDate, |
|||
weight: weight, |
|||
weight1: weight1, |
|||
createdBy: createdBy // backend will ignore if not needed |
|||
}, |
|||
beforeSend: function () { |
|||
Swal.fire({ |
|||
title: "Saving...", |
|||
text: "Please wait", |
|||
allowOutsideClick: false, |
|||
didOpen: () => Swal.showLoading() |
|||
}); |
|||
}, |
|||
success: function (response) { |
|||
Swal.fire("Success", response.message, "success"); |
|||
|
|||
// Reset fields |
|||
$("#weight").val(""); |
|||
$("#weight1").val(""); |
|||
}, |
|||
error: function (xhr) { |
|||
let msg = "Something went wrong"; |
|||
|
|||
if (xhr.responseJSON && xhr.responseJSON.message) { |
|||
msg = xhr.responseJSON.message; |
|||
} |
|||
|
|||
Swal.fire("Error", msg, "error"); |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
</script> |
|||
</body> |
|||
|
|||
</html> |
|||
@ -1,944 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en" xmlns:th="http://www.thymeleaf.org"> |
|||
|
|||
<head th:replace="~{fragments/modules/base/head :: head}"></head> |
|||
<style> |
|||
.width1 { |
|||
width: 120px; |
|||
} |
|||
|
|||
.width2 { |
|||
width: 150px; |
|||
} |
|||
|
|||
.modal-label { |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.modal-value { |
|||
color: #444; |
|||
} |
|||
|
|||
.modal-section-title { |
|||
font-size: 1.2rem; |
|||
font-weight: bold; |
|||
margin-top: 20px; |
|||
margin-bottom: 10px; |
|||
border-bottom: 2px solid #dee2e6; |
|||
padding-bottom: 5px; |
|||
} |
|||
|
|||
|
|||
.modal-title-big { |
|||
font-size: 20px; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
.modal-subtext { |
|||
color: #b4c5d3; |
|||
font-size: 13px; |
|||
} |
|||
|
|||
.card-section { |
|||
background: white; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
margin-bottom: 25px; |
|||
border: 1px solid #eee; |
|||
} |
|||
|
|||
.section-title { |
|||
font-weight: 700; |
|||
color: #333; |
|||
margin-bottom: 15px; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.label-text { |
|||
font-size: 13px; |
|||
color: #6c757d; |
|||
} |
|||
|
|||
.value-text { |
|||
font-size: 15px; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.info-block { |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
|
|||
.badge-status { |
|||
background: #ffd9b3; |
|||
color: #a65c00; |
|||
padding: 6px 10px; |
|||
border-radius: 5px; |
|||
font-size: 13px; |
|||
|
|||
} |
|||
|
|||
.btn-big { |
|||
padding: 12px 25px; |
|||
border-radius: 8px; |
|||
width: 200px; |
|||
} |
|||
|
|||
.rdo-box { |
|||
border: 1px solid #eee; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
} |
|||
</style> |
|||
|
|||
<body> |
|||
|
|||
<div class="wrapper"> |
|||
<!-- header top menu Start --> |
|||
<header th:replace="~{fragments/modules/base/header :: header}"></header> |
|||
<!-- header top menu end --> |
|||
<div class="page-wrap"> |
|||
<!--=============== Left Menu side Start ================--> |
|||
<div th:replace="~{fragments/modules/base/menu :: menu}"></div> |
|||
<!--=============== Left side End ================--> |
|||
<div class="main-content"> |
|||
<div class="container-fluid"> |
|||
<div class="page-header"> |
|||
<div class="row align-items-end"> |
|||
<div class="col-lg-6"> |
|||
<div class="page-header-title"> |
|||
<i class="fa fa-list-alt bg-blue"></i> |
|||
<div class="d-inline"> |
|||
<h5>SWD Facilities Reports</h5> |
|||
<span>Reports</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-6"> |
|||
<nav class="breadcrumb-container" aria-label="breadcrumb"> |
|||
<ol class="breadcrumb"> |
|||
<li class="breadcrumb-item"> |
|||
<a href="/swm/index"><i class="ik ik-home"></i></a> |
|||
</li> |
|||
<li class="breadcrumb-item" aria-current="page">SWD Facilities Reports</li> |
|||
<li class="breadcrumb-item active" aria-current="page">Reports</li> |
|||
</ol> |
|||
</nav> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="row mt-4"> |
|||
<div class="col-md-12"> |
|||
<div class="card shadow-sm"> |
|||
|
|||
<!-- CARD HEADER --> |
|||
<div class="card-header d-flex justify-content-between align-items-center fw-bold"> |
|||
<h3 class="mb-0"> SWD Facilities Reports : <span th:text="${officer_name}"></span> |
|||
</h3> |
|||
<input type="hidden" id="userName" th:value="${officer_name}"> |
|||
</div> |
|||
|
|||
<!-- FILTER SECTION --> |
|||
<!-- <div class="card-body pb-0"> |
|||
<div class="row align-items-end g-3 mb-3"> |
|||
<div class="col-md-3"> |
|||
<label class="form-label">From Date</label> |
|||
<input type="date" id="fromDate" class="form-control"> |
|||
</div> |
|||
|
|||
<div class="col-md-3"> |
|||
<label class="form-label">To Date</label> |
|||
<input type="date" id="toDate" class="form-control"> |
|||
</div> |
|||
|
|||
<div class="col-md-3"> |
|||
<label class="form-label">date</label> |
|||
<input type="date" id="singleDate" class="form-control"> |
|||
</div> |
|||
|
|||
<div class="col-md-3"> |
|||
<label class="form-label">Report type</label> |
|||
<select> |
|||
< </select> |
|||
<option></option> |
|||
<input type="date" id="singleDate" class="form-control"> |
|||
</div> |
|||
|
|||
<div class="col-md-3"> |
|||
<button id="searchBtn" class="btn btn-primary w-100"> |
|||
Search |
|||
</button> |
|||
</div> |
|||
</div> |
|||
</div> --> |
|||
|
|||
<div class="card-body pb-0"> |
|||
<div class="row align-items-end g-3 mb-3"> |
|||
|
|||
<!-- From Date --> |
|||
<div class="col-md-3 d-none" id="fromDateDiv"> |
|||
<label class="form-label">From Date</label><span |
|||
class="text-danger">*</span> |
|||
<input type="date" id="fromDate" class="form-control"> |
|||
</div> |
|||
|
|||
<!-- To Date --> |
|||
<div class="col-md-3 d-none" id="toDateDiv"> |
|||
<label class="form-label">To Date</label><span class="text-danger">*</span> |
|||
<input type="date" id="toDate" class="form-control"> |
|||
</div> |
|||
|
|||
<!-- Single Date --> |
|||
<div class="col-md-3 d-none" id="singleDateDiv"> |
|||
<label class="form-label">Date</label> <span class="text-danger">*</span> |
|||
</label> |
|||
<input type="date" id="singleDate" class="form-control"> |
|||
</div> |
|||
|
|||
<!-- Report Type --> |
|||
<div class="col-md-3"> |
|||
<label class="form-label">Report Type</label> <span |
|||
class="text-danger">*</span> |
|||
</label> |
|||
<select id="reportType" class="form-control"> |
|||
<option value="">Select</option> |
|||
<option value="DAY">Day Wise</option> |
|||
<option value="MONTH">Month Wise/Date Range</option> |
|||
</select> |
|||
</div> |
|||
|
|||
<!-- Search --> |
|||
<div class="col-md-3"> |
|||
<button id="searchBtn" class="btn btn-primary w-100"> |
|||
Search |
|||
</button> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
<!-- TABLE SECTION --> |
|||
<div class="card-body pt-0"> |
|||
<div class="table-responsive"> |
|||
<!-- <table id="QaqcDatatable" |
|||
class="table table-striped table-bordered table-hover dataTable" |
|||
role="grid"> |
|||
<thead class="thead-dark"> |
|||
<tr role="row"> |
|||
<th class="text-center">S.No</th> |
|||
<th class="text-center no-sort">Zone Name</th> |
|||
<th class="text-center no-sort">MCC (%)</th> |
|||
<th class="text-center no-sort">Windrow (%)</th> |
|||
<th class="text-center no-sort">BioCng (%)</th> |
|||
<th class="text-center no-sort">Horticulture (%)</th> |
|||
<th class="text-center no-sort">Incinerator (%)</th> |
|||
<th class="text-center no-sort">Baling center (%)</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> </tbody> |
|||
</table> --> |
|||
|
|||
<table id="QaqcDatatable" |
|||
class="table table-striped table-bordered table-hover dataTable" |
|||
width="100%"> |
|||
|
|||
<thead class="thead-dark"> |
|||
<!-- ROW 1 : MAIN GROUP HEADERS --> |
|||
<!-- <tr class="text-center"> |
|||
<th colspan="23" class="text-center">Average month wise report</th> |
|||
</tr> --> |
|||
<tr class="text-center"> |
|||
|
|||
<th rowspan="2">S.No</th> |
|||
<th rowspan="2">Zone</th> |
|||
|
|||
<th colspan="3">MCC</th> |
|||
<th colspan="3">Windrow</th> |
|||
<th colspan="3">Bio-CNG</th> |
|||
<th colspan="3">Bio-GAS</th> |
|||
<th colspan="3">Horticulture</th> |
|||
<th colspan="3">Incinerator</th> |
|||
<th colspan="3">Plasting Baling Centre</th> |
|||
</tr> |
|||
|
|||
<!-- ROW 2 : SUB HEADERS --> |
|||
<tr class="text-center"> |
|||
<th>Target</th> |
|||
<th>Achieved</th> |
|||
<th>%</th> |
|||
|
|||
<th>Target</th> |
|||
<th>Achieved</th> |
|||
<th>%</th> |
|||
|
|||
<th>Target</th> |
|||
<th>Achieved</th> |
|||
<th>%</th> |
|||
|
|||
<th>Target</th> |
|||
<th>Achieved</th> |
|||
<th>%</th> |
|||
|
|||
<th>Target</th> |
|||
<th>Achieved</th> |
|||
<th>%</th> |
|||
|
|||
<th>Target</th> |
|||
<th>Achieved</th> |
|||
<th>%</th> |
|||
|
|||
<th>Target</th> |
|||
<th>Achieved</th> |
|||
<th>%</th> |
|||
</tr> |
|||
</thead> |
|||
<tfoot> |
|||
<tr class="text-center fw-bold"> |
|||
<th colspan="2">TOTAL</th> |
|||
|
|||
<th></th> |
|||
<th></th> |
|||
<th></th> <!-- MCC --> |
|||
<th></th> |
|||
<th></th> |
|||
<th></th> <!-- Windrow --> |
|||
<th></th> |
|||
<th></th> |
|||
<th></th> <!-- Bio-CNG --> |
|||
<th></th> |
|||
<th></th> |
|||
<th></th> <!-- Bio-GAS --> |
|||
<th></th> |
|||
<th></th> |
|||
<th></th> <!-- Horticulture / GW&TC --> |
|||
<th></th> |
|||
<th></th> |
|||
<th></th> <!-- Incinerator --> |
|||
<th></th> |
|||
<th></th> |
|||
<th></th> <!-- Plastic Baling --> |
|||
</tr> |
|||
</tfoot> |
|||
|
|||
|
|||
<tbody></tbody> |
|||
</table> |
|||
|
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
</div> |
|||
</div> |
|||
<div id="pageLoader" |
|||
style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); z-index: 9999; text-align: center;"> |
|||
<div style="position: relative; top: 50%; transform: translateY(-50%);"> |
|||
<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;"> |
|||
<span class="sr-only">Loading...</span> |
|||
</div> |
|||
<!-- Add the 'Please wait' text below the spinner --> |
|||
<p style="margin-top: 1rem; font-size: 1.2rem; color: #007bff;">Please wait...</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div th:replace="~{fragments/modules/base/app_module_menu_box :: div}"></div> |
|||
|
|||
<footer th:replace="~{fragments/modules/base/footer :: footer}"></footer> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Details Modal --> |
|||
<div class="modal fade" id="detailsModal" tabindex="-1" aria-hidden="true"> |
|||
<div class="modal-dialog modal-xl modal-dialog-scrollable"> |
|||
<div class="modal-content"> |
|||
|
|||
<div class="modal-header" style="background:#2f3e54; color:white;"> |
|||
<div> |
|||
<h4 class="modal-title-big" id="modalTitle"></h4> |
|||
<div id="modalSubTitle" class="modal-subtext"></div> |
|||
</div> |
|||
|
|||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span |
|||
aria-hidden="true">×</span></button> |
|||
</div> |
|||
|
|||
<div class="modal-body"> |
|||
|
|||
<div id="modalContent"></div> |
|||
|
|||
<div class="text-center mt-4"> |
|||
<button type="button" class="btn btn-primary btn-big" data-dismiss="modal" |
|||
style="background:#2f3e54;">Close</button> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
<script th:replace="~{fragments/modules/base/script :: script}"></script> |
|||
<script type="text/javascript"> |
|||
|
|||
|
|||
|
|||
let table; |
|||
|
|||
$(document).ready(function () { |
|||
|
|||
table = $('#QaqcDatatable').DataTable({ |
|||
data: [], |
|||
ordering: false, |
|||
searching: true, |
|||
info: true, |
|||
paging: true, |
|||
pageLength: 15, // show 15 rows |
|||
lengthMenu: [15, 25, 50, 100], // optional dropdown |
|||
scrollX: true, |
|||
responsive: false, |
|||
dom: 'Bftip', |
|||
|
|||
buttons: [ |
|||
|
|||
/* ===================== EXCEL (SIMPLE & SAFE) ===================== */ |
|||
{ |
|||
extend: 'excelHtml5', |
|||
text: 'Excel', |
|||
title: 'Gcc Swm Report', |
|||
filename: 'Gcc Swm Report', |
|||
exportOptions: { |
|||
format: { |
|||
header: function (data, columnIdx) { |
|||
|
|||
const headers = [ |
|||
'S.No', |
|||
'Zone', |
|||
|
|||
'MCC Target', |
|||
'MCC Achieved', |
|||
'MCC %', |
|||
|
|||
'Windrow Target', |
|||
'Windrow Achieved', |
|||
'Windrow %', |
|||
|
|||
'Bio-CNG Target', |
|||
'Bio-CNG Achieved', |
|||
'Bio-CNG %', |
|||
|
|||
'Bio-GAS Target', |
|||
'Bio-GAS Achieved', |
|||
'Bio-GAS %', |
|||
|
|||
'Incinerator Target', |
|||
'Incinerator Achieved', |
|||
'Incinerator %', |
|||
|
|||
'GW & TC Waste Target', |
|||
'GW & TC Waste Achieved', |
|||
'GW & TC Waste %', |
|||
|
|||
'Plasting Baling Centre Target', |
|||
'Plasting Baling Centre Achieved', |
|||
'Plasting Baling Centre %' |
|||
]; |
|||
|
|||
return headers[columnIdx]; |
|||
} |
|||
} |
|||
}, |
|||
customize: function (xlsx) { |
|||
|
|||
const sheet = xlsx.xl.worksheets['sheet1.xml']; |
|||
const api = $('#QaqcDatatable').DataTable(); |
|||
|
|||
// Helper to get footer text safely |
|||
function footerVal(colIdx) { |
|||
const footer = api.column(colIdx).footer(); |
|||
return footer ? footer.innerText.trim() : '0'; |
|||
} |
|||
|
|||
// Build TOTAL row (MUST match column order) |
|||
const totalRow = [ |
|||
'TOTAL', '', |
|||
|
|||
footerVal(2), footerVal(3), footerVal(4), |
|||
footerVal(5), footerVal(6), footerVal(7), |
|||
footerVal(8), footerVal(9), footerVal(10), |
|||
footerVal(11), footerVal(12), footerVal(13), |
|||
footerVal(14), footerVal(15), footerVal(16), |
|||
footerVal(17), footerVal(18), footerVal(19), |
|||
footerVal(20), footerVal(21), footerVal(22) |
|||
]; |
|||
|
|||
// Convert TOTAL row to Excel XML |
|||
let rowXml = '<row>'; |
|||
totalRow.forEach(val => { |
|||
rowXml += `<c t="inlineStr"><is><t>${val}</t></is></c>`; |
|||
}); |
|||
rowXml += '</row>'; |
|||
|
|||
// Append TOTAL row at the end of sheet |
|||
const sheetData = sheet.getElementsByTagName('sheetData')[0]; |
|||
sheetData.innerHTML += rowXml; |
|||
} |
|||
}, |
|||
|
|||
|
|||
|
|||
/* ===================== PDF ===================== */ |
|||
{ |
|||
extend: 'pdfHtml5', |
|||
orientation: 'landscape', |
|||
pageSize: 'A3', |
|||
title: 'Gcc Swm Report' |
|||
}, |
|||
|
|||
/* ===================== CSV ===================== */ |
|||
{ |
|||
extend: 'csvHtml5', |
|||
text: 'CSV', |
|||
title: '' |
|||
} |
|||
], |
|||
|
|||
columns: [ |
|||
{ data: "sno" }, |
|||
{ data: "zone" }, |
|||
|
|||
{ data: "MCC_target" }, |
|||
{ data: "MCC_achieved" }, |
|||
{ data: "MCC_percentage" }, |
|||
|
|||
{ data: "Windrow_target" }, |
|||
{ data: "Windrow_achieved" }, |
|||
{ data: "Windrow_percentage" }, |
|||
|
|||
{ data: "Bio-CNG_target" }, |
|||
{ data: "Bio-CNG_achieved" }, |
|||
{ data: "Bio-CNG_percentage" }, |
|||
|
|||
{ data: "Bio-GAS_target" }, |
|||
{ data: "Bio-GAS_achieved" }, |
|||
{ data: "Bio-GAS_percentage" }, |
|||
|
|||
{ data: "Incinerator_target" }, |
|||
{ data: "Incinerator_achieved" }, |
|||
{ data: "Incinerator_percentage" }, |
|||
|
|||
{ data: "GW & TC Waste_target" }, |
|||
{ data: "GW & TC Waste_achieved" }, |
|||
{ data: "GW & TC Waste_percentage" }, |
|||
|
|||
{ data: "Plasting Baling Centre_target" }, |
|||
{ data: "Plasting Baling Centre_achieved" }, |
|||
{ data: "Plasting Baling Centre_percentage" } |
|||
], |
|||
|
|||
footerCallback: function () { |
|||
|
|||
const api = this.api(); |
|||
|
|||
// Sum helper |
|||
function sum(colIdx) { |
|||
return api |
|||
.column(colIdx, { page: 'current' }) |
|||
.data() |
|||
.reduce((a, b) => { |
|||
const x = parseFloat(a) || 0; |
|||
const y = parseFloat(b) || 0; |
|||
return x + y; |
|||
}, 0); |
|||
} |
|||
|
|||
// Facility-wise column mapping |
|||
const facilities = [ |
|||
{ target: 2, achieved: 3, percent: 4 }, // MCC |
|||
{ target: 5, achieved: 6, percent: 7 }, // Windrow |
|||
{ target: 8, achieved: 9, percent: 10 }, // Bio-CNG |
|||
{ target: 11, achieved: 12, percent: 13 },// Bio-GAS |
|||
{ target: 14, achieved: 15, percent: 16 },// GW & TC Waste |
|||
{ target: 17, achieved: 18, percent: 19 },// Incinerator |
|||
{ target: 20, achieved: 21, percent: 22 } // Plastic Baling Centre |
|||
]; |
|||
|
|||
facilities.forEach(f => { |
|||
|
|||
const totalTarget = sum(f.target); |
|||
const totalAchieved = sum(f.achieved); |
|||
|
|||
// Write totals |
|||
$(api.column(f.target).footer()).html(totalTarget.toFixed(2)); |
|||
$(api.column(f.achieved).footer()).html(totalAchieved.toFixed(2)); |
|||
|
|||
// Percentage calculation |
|||
let percent = 0; |
|||
if (totalTarget > 0) { |
|||
percent = (totalAchieved / totalTarget) * 100; |
|||
} |
|||
|
|||
$(api.column(f.percent).footer()).html(percent.toFixed(2) + '%'); |
|||
}); |
|||
} |
|||
|
|||
|
|||
}); |
|||
|
|||
$("#searchBtn").on("click", loadReport); |
|||
}); |
|||
|
|||
|
|||
|
|||
$(document).ready(function () { |
|||
|
|||
$("#reportType").on("change", function () { |
|||
|
|||
const type = $(this).val(); |
|||
|
|||
// Hide all first |
|||
$("#singleDateDiv").addClass("d-none"); |
|||
$("#fromDateDiv, #toDateDiv").addClass("d-none"); |
|||
|
|||
// Clear values |
|||
$("#singleDate, #fromDate, #toDate").val(""); |
|||
|
|||
if (type === "DAY") { |
|||
// Day wise → show single date |
|||
$("#singleDateDiv").removeClass("d-none"); |
|||
} |
|||
else if (type === "MONTH") { |
|||
// Month wise → show from & to date |
|||
$("#fromDateDiv, #toDateDiv").removeClass("d-none"); |
|||
} |
|||
}); |
|||
|
|||
}); |
|||
|
|||
// function loadReport() { |
|||
|
|||
// const fromDate = $("#fromDate").val(); |
|||
// const toDate = $("#toDate").val(); |
|||
|
|||
// if (!fromDate || !toDate) { |
|||
// Swal.fire("Validation Error", "Please select both dates", "warning"); |
|||
// return; |
|||
// } |
|||
|
|||
// $.ajax({ |
|||
// url: "/swm/api/admin/reports", |
|||
// type: "GET", |
|||
// data: { fromDate, toDate }, |
|||
// beforeSend: function () { |
|||
// Swal.fire({ |
|||
// title: "Loading...", |
|||
// allowOutsideClick: false, |
|||
// didOpen: () => Swal.showLoading() |
|||
// }); |
|||
// }, |
|||
// success: function (res) { |
|||
// Swal.close(); |
|||
// renderZoneTable(res.data); |
|||
// }, |
|||
// error: function () { |
|||
// Swal.fire("Error", "Failed to load report", "error"); |
|||
// } |
|||
// }); |
|||
// } |
|||
|
|||
function getDateDiffInDays(fromDate, toDate) { |
|||
const start = new Date(fromDate); |
|||
const end = new Date(toDate); |
|||
|
|||
// +1 because inclusive (01 to 10 = 10 days) |
|||
return Math.floor((end - start) / (1000 * 60 * 60 * 24)) + 1; |
|||
} |
|||
|
|||
|
|||
// function renderZoneTableMonthWise(data, fromDate, toDate) { |
|||
|
|||
// const zoneMap = {}; |
|||
// const dayCount = getDateDiffInDays(fromDate, toDate); |
|||
|
|||
// data.forEach(row => { |
|||
|
|||
// const z = row.zone; |
|||
// const f = row.facility; |
|||
|
|||
// if (!zoneMap[z]) { |
|||
// zoneMap[z] = { zone: z }; |
|||
// } |
|||
|
|||
// const dailyTarget = Number(row.target || 0); |
|||
// const totalAchieved = Number(row.achieved || 0); |
|||
|
|||
// // Overall target for selected date range |
|||
// const overallTarget = dailyTarget * dayCount; |
|||
|
|||
// // Raw percentage |
|||
// let percent = 0; |
|||
// if (overallTarget > 0) { |
|||
// percent = (totalAchieved / overallTarget) * 100; |
|||
// } |
|||
|
|||
// // ✅ CAP percentage to max 100 |
|||
// percent = Math.min(percent, 100); |
|||
|
|||
// // Store values (2 decimal places) |
|||
// zoneMap[z][f + "_target"] = overallTarget.toFixed(2); |
|||
// zoneMap[z][f + "_achieved"] = totalAchieved.toFixed(2); |
|||
// zoneMap[z][f + "_percentage"] = percent.toFixed(2) + "%"; |
|||
// }); |
|||
|
|||
// let i = 1; |
|||
// const tableData = Object.values(zoneMap).map(r => ({ |
|||
// sno: i++, |
|||
// ...r |
|||
// })); |
|||
|
|||
// table.clear().rows.add(tableData).draw(); |
|||
// } |
|||
|
|||
function renderZoneTableMonthWise(data, fromDate, toDate) { |
|||
|
|||
const zoneMap = {}; |
|||
const dayCount = getDateDiffInDays(fromDate, toDate); |
|||
|
|||
data.forEach(row => { |
|||
|
|||
const z = row.zone; |
|||
const f = row.facility; |
|||
|
|||
if (!zoneMap[z]) { |
|||
zoneMap[z] = { zone: z }; |
|||
} |
|||
|
|||
const dailyTarget = Number(row.target || 0); |
|||
const perDayAchieved = Number(row.achieved || 0); |
|||
|
|||
// 🔹 INTERNAL TOTALS (as per your explanation) |
|||
const totalTarget = dailyTarget * dayCount; |
|||
const totalAchieved = perDayAchieved * dayCount; |
|||
|
|||
// 🔹 AVERAGES SHOWN IN TABLE |
|||
const avgTarget = |
|||
dayCount > 0 ? (totalTarget / dayCount) : 0; |
|||
|
|||
const avgAchieved = |
|||
dayCount > 0 ? (totalAchieved / dayCount) : 0; |
|||
|
|||
// 🔹 PERCENTAGE (based on averages) |
|||
let percent = 0; |
|||
if (avgTarget > 0) { |
|||
percent = (avgAchieved / avgTarget) * 100; |
|||
} |
|||
|
|||
// 🔹 Cap at 100% |
|||
percent = Math.min(percent, 100); |
|||
|
|||
// 🔹 Store values (2 decimals) |
|||
zoneMap[z][f + "_target"] = avgTarget.toFixed(2); |
|||
zoneMap[z][f + "_achieved"] = avgAchieved.toFixed(2); |
|||
zoneMap[z][f + "_percentage"] = percent.toFixed(2) + "%"; |
|||
}); |
|||
|
|||
let i = 1; |
|||
const tableData = Object.values(zoneMap).map(r => ({ |
|||
sno: i++, |
|||
...r |
|||
})); |
|||
|
|||
table.clear().rows.add(tableData).draw(); |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
function loadReport() { |
|||
|
|||
const reportType = $("#reportType").val(); |
|||
|
|||
if (!reportType) { |
|||
Swal.fire("Validation Error", "Please select Report Type", "warning"); |
|||
return; |
|||
} |
|||
|
|||
let url = ""; |
|||
let data = {}; |
|||
|
|||
// ================= DAY WISE ================= |
|||
if (reportType === "DAY") { |
|||
|
|||
const singleDate = $("#singleDate").val(); |
|||
|
|||
if (!singleDate) { |
|||
Swal.fire("Validation Error", "Please select Date", "warning"); |
|||
return; |
|||
} |
|||
|
|||
url = "/swm/api/admin/singledayreports"; |
|||
data = { Date: singleDate }; |
|||
|
|||
} |
|||
// ================= MONTH / DATE RANGE ================= |
|||
else if (reportType === "MONTH") { |
|||
|
|||
const fromDate = $("#fromDate").val(); |
|||
const toDate = $("#toDate").val(); |
|||
|
|||
if (!fromDate || !toDate) { |
|||
Swal.fire("Validation Error", "Please select From & To Date", "warning"); |
|||
return; |
|||
} |
|||
|
|||
url = "/swm/api/admin/reports"; |
|||
data = { fromDate, toDate }; |
|||
} |
|||
|
|||
$.ajax({ |
|||
url: url, |
|||
type: "GET", |
|||
data: data, |
|||
beforeSend: function () { |
|||
Swal.fire({ |
|||
title: "Loading...", |
|||
allowOutsideClick: false, |
|||
didOpen: () => Swal.showLoading() |
|||
}); |
|||
}, |
|||
success: function (res) { |
|||
|
|||
Swal.close(); |
|||
|
|||
// ✅ SEPARATE RENDERING BASED ON REPORT TYPE |
|||
if (reportType === "MONTH") { |
|||
renderZoneTableMonthWise( |
|||
res.data, |
|||
$("#fromDate").val(), |
|||
$("#toDate").val() |
|||
); |
|||
} else { |
|||
renderZoneTable(res.data); // DAY wise (existing) |
|||
} |
|||
}, |
|||
error: function () { |
|||
Swal.fire("Error", "Failed to load report", "error"); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
|
|||
|
|||
function renderZoneTable(data) { |
|||
|
|||
const zoneMap = {}; |
|||
|
|||
data.forEach(row => { |
|||
const z = row.zone; |
|||
const f = row.facility; |
|||
|
|||
if (!zoneMap[z]) zoneMap[z] = { zone: z }; |
|||
|
|||
zoneMap[z][f + "_target"] = row.target ?? 0; |
|||
zoneMap[z][f + "_achieved"] = row.achieved ?? 0; |
|||
zoneMap[z][f + "_percentage"] = |
|||
row.percentage != null ? row.percentage + "%" : "0%"; |
|||
}); |
|||
|
|||
let i = 1; |
|||
const tableData = Object.values(zoneMap).map(r => ({ |
|||
sno: i++, |
|||
...r |
|||
})); |
|||
|
|||
table.clear().rows.add(tableData).draw(); |
|||
} |
|||
|
|||
|
|||
// function renderZoneTable(data) { |
|||
|
|||
// const zoneMap = {}; |
|||
|
|||
// data.forEach(row => { |
|||
|
|||
// const z = row.zone; |
|||
// const f = row.facility; |
|||
|
|||
// if (!zoneMap[z]) { |
|||
// zoneMap[z] = { zone: z }; |
|||
// } |
|||
|
|||
// // Create facility bucket |
|||
// if (!zoneMap[z][f]) { |
|||
// zoneMap[z][f] = { |
|||
// dailyTarget: 0, |
|||
// totalAchieved: 0, |
|||
// dayCount: 0 |
|||
// }; |
|||
// } |
|||
|
|||
// const fac = zoneMap[z][f]; |
|||
|
|||
// // DAILY target from API |
|||
// fac.dailyTarget = Number(row.target || 0); |
|||
|
|||
// // EACH ROW = ONE DAY |
|||
// fac.dayCount += 1; |
|||
|
|||
// // SUM achieved |
|||
// fac.totalAchieved += Number(row.achieved || 0); |
|||
// }); |
|||
|
|||
// let i = 1; |
|||
// const tableData = []; |
|||
|
|||
// Object.values(zoneMap).forEach(z => { |
|||
|
|||
// const row = { |
|||
// sno: i++, |
|||
// zone: z.zone |
|||
// }; |
|||
|
|||
// Object.keys(z).forEach(f => { |
|||
|
|||
// if (f === "zone") return; |
|||
|
|||
// const fac = z[f]; |
|||
|
|||
// // ✅ MONTH TARGET = daily target × no of days |
|||
// const totalTarget = fac.dailyTarget * fac.dayCount; |
|||
|
|||
// const percent = |
|||
// totalTarget > 0 |
|||
// ? ((fac.totalAchieved / totalTarget) * 100).toFixed(2) |
|||
// : "0.00"; |
|||
|
|||
// row[f + "_target"] = totalTarget.toFixed(2); |
|||
// row[f + "_achieved"] = fac.totalAchieved.toFixed(2); |
|||
// row[f + "_percentage"] = percent + "%"; |
|||
// }); |
|||
|
|||
// tableData.push(row); |
|||
// }); |
|||
|
|||
// table.clear().rows.add(tableData).draw(); |
|||
// } |
|||
|
|||
|
|||
</script> |
|||
</body> |
|||
|
|||
</html> |
|||
@ -1,442 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en" xmlns:th="http://www.thymeleaf.org"> |
|||
|
|||
<head th:replace="~{fragments/modules/base/head :: head}"></head> |
|||
<style> |
|||
.width1 { |
|||
width: 120px; |
|||
} |
|||
|
|||
.width2 { |
|||
width: 150px; |
|||
} |
|||
|
|||
.modal-label { |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.modal-value { |
|||
color: #444; |
|||
} |
|||
|
|||
.modal-section-title { |
|||
font-size: 1.2rem; |
|||
font-weight: bold; |
|||
margin-top: 20px; |
|||
margin-bottom: 10px; |
|||
border-bottom: 2px solid #dee2e6; |
|||
padding-bottom: 5px; |
|||
} |
|||
|
|||
|
|||
.modal-title-big { |
|||
font-size: 20px; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
.modal-subtext { |
|||
color: #b4c5d3; |
|||
font-size: 13px; |
|||
} |
|||
|
|||
.card-section { |
|||
background: white; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
margin-bottom: 25px; |
|||
border: 1px solid #eee; |
|||
} |
|||
|
|||
.section-title { |
|||
font-weight: 700; |
|||
color: #333; |
|||
margin-bottom: 15px; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.label-text { |
|||
font-size: 13px; |
|||
color: #6c757d; |
|||
} |
|||
|
|||
.value-text { |
|||
font-size: 15px; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.info-block { |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
|
|||
.badge-status { |
|||
background: #ffd9b3; |
|||
color: #a65c00; |
|||
padding: 6px 10px; |
|||
border-radius: 5px; |
|||
font-size: 13px; |
|||
|
|||
} |
|||
|
|||
.btn-big { |
|||
padding: 12px 25px; |
|||
border-radius: 8px; |
|||
width: 200px; |
|||
} |
|||
|
|||
.rdo-box { |
|||
border: 1px solid #eee; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
} |
|||
</style> |
|||
|
|||
<body th:data-two-weight="${isTwoWeightFacility}" th:data-weight-type="${isWeightTypeFacility}"> |
|||
|
|||
|
|||
<div class="wrapper"> |
|||
<!-- header top menu Start --> |
|||
<header th:replace="~{fragments/modules/base/header :: header}"></header> |
|||
<!-- header top menu end --> |
|||
<div class="page-wrap"> |
|||
<!--=============== Left Menu side Start ================--> |
|||
<div th:replace="~{fragments/modules/base/menu :: menu}"></div> |
|||
<!--=============== Left side End ================--> |
|||
<div class="main-content"> |
|||
<div class="container-fluid"> |
|||
<div class="page-header"> |
|||
<div class="row align-items-end"> |
|||
<div class="col-lg-6"> |
|||
<div class="page-header-title"> |
|||
<i class="fa fa-list-alt bg-blue"></i> |
|||
<div class="d-inline"> |
|||
<h5>SWD Facilities Add Details List</h5> |
|||
<span>Add Details</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-6"> |
|||
<nav class="breadcrumb-container" aria-label="breadcrumb"> |
|||
<ol class="breadcrumb"> |
|||
<li class="breadcrumb-item"> |
|||
<a href="/swm/index"><i class="ik ik-home"></i></a> |
|||
</li> |
|||
<li class="breadcrumb-item" aria-current="page">SWD Facilities Add Details List |
|||
</li> |
|||
<li class="breadcrumb-item active" aria-current="page">Add Details</li> |
|||
</ol> |
|||
</nav> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="row mt-4"> |
|||
|
|||
<div class="col-md-12"> |
|||
<div class="card"> |
|||
<div class="card-header d-flex justify-content-between align-items-center fw-bold"> |
|||
<h3 class="mb-0"> SWM Add Details : <span th:text="${officer_name}"></span></h3> |
|||
<input type="hidden" id="userName" th:value="${officer_name}"> |
|||
</div> |
|||
|
|||
<div class="card-body"> |
|||
<div class="row"> |
|||
<div class="col-md-3"> |
|||
<label for="date" class="form-label" |
|||
style="font-size: medium;">Date:</label><span |
|||
class="text-danger">*</span> |
|||
<input type="date" id="date" class="form-control"> |
|||
</div> |
|||
<div class="col-md-3"> |
|||
<label for="zones" class="form-label">Zones <span |
|||
class="text-danger">*</span> |
|||
</label> |
|||
<select id="zones" class="form-control"> |
|||
<option value="">Select days</option> |
|||
|
|||
</select> |
|||
</div> |
|||
|
|||
<input type="hidden" id="facilityTypeId" th:value="${facilityTypeId}"> |
|||
|
|||
<div class="col-md-3"> |
|||
|
|||
<label for="weight" class="form-label">Enter Weight(in MT):</label><span |
|||
class="text-danger">*</span> |
|||
<input type="number" class="form-control" id="weight"> |
|||
</div> |
|||
|
|||
<!-- SECOND WEIGHT (TC) --> |
|||
<div class="col-md-3" id="weight2Div" style="display:none;"> |
|||
<label for="weight1" class="form-label">Enter Weight(Tender |
|||
Coconut):</label><span class="text-danger">*</span> |
|||
<input type="number" class="form-control" id="weight1"> |
|||
</div> |
|||
|
|||
<div class="col-md-3" id="facilityTypeDiv" style="display:none;"> |
|||
<label for="facilitytype" class="form-label"> |
|||
Location <span class="text-danger">*</span> |
|||
</label> |
|||
<select id="facilitytype" class="form-control"> |
|||
<option value="">Select location</option> |
|||
<option value="KDG">KDG</option> |
|||
<option value="PDG">PDG</option> |
|||
</select> |
|||
</div> |
|||
|
|||
|
|||
<div class="col-md-3" style="margin-top: 30px;"> |
|||
<button id="submitBtn" class="btn btn-primary">Submit</button> |
|||
<button id="resetBtn" class="btn btn-secondary">Reset</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
<div id="pageLoader" |
|||
style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); z-index: 9999; text-align: center;"> |
|||
<div style="position: relative; top: 50%; transform: translateY(-50%);"> |
|||
<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;"> |
|||
<span class="sr-only">Loading...</span> |
|||
</div> |
|||
<!-- Add the 'Please wait' text below the spinner --> |
|||
<p style="margin-top: 1rem; font-size: 1.2rem; color: #007bff;">Please wait...</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div th:replace="~{fragments/modules/base/app_module_menu_box :: div}"></div> |
|||
|
|||
<footer th:replace="~{fragments/modules/base/footer :: footer}"></footer> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Details Modal --> |
|||
<div class="modal fade" id="detailsModal" tabindex="-1" aria-hidden="true"> |
|||
<div class="modal-dialog modal-xl modal-dialog-scrollable"> |
|||
<div class="modal-content"> |
|||
|
|||
<div class="modal-header" style="background:#2f3e54; color:white;"> |
|||
<div> |
|||
<h4 class="modal-title-big" id="modalTitle"></h4> |
|||
<div id="modalSubTitle" class="modal-subtext"></div> |
|||
</div> |
|||
|
|||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span |
|||
aria-hidden="true">×</span></button> |
|||
</div> |
|||
|
|||
<div class="modal-body"> |
|||
|
|||
<div id="modalContent"></div> |
|||
|
|||
<div class="text-center mt-4"> |
|||
<button type="button" class="btn btn-primary btn-big" data-dismiss="modal" |
|||
style="background:#2f3e54;">Close</button> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
<script th:replace="~{fragments/modules/base/script :: script}"></script> |
|||
<script type="text/javascript"> |
|||
|
|||
$(document).ready(function () { |
|||
|
|||
const isTwoWeightFacility = |
|||
$("body").data("two-weight") === true || |
|||
$("body").data("two-weight") === "true"; |
|||
|
|||
const isWeightTypeFacility = |
|||
$("body").data("weight-type") === true || |
|||
$("body").data("weight-type") === "true"; |
|||
// GW & TC + PBC / C&D → show KDG / PDG |
|||
|
|||
if (isTwoWeightFacility) { |
|||
$("#weight2Div").show(); |
|||
$("#weightTypeDiv").show(); |
|||
} else { |
|||
$("#weight2Div").hide(); |
|||
$("#weightTypeDiv").hide(); |
|||
$("#weight1").val(""); |
|||
$("#facilitytype").val(""); |
|||
} |
|||
|
|||
if (isWeightTypeFacility) { |
|||
$("#facilityTypeDiv").show(); |
|||
} else { |
|||
$("#facilityTypeDiv").hide(); |
|||
$("#facilitytype").val(""); |
|||
} |
|||
}); |
|||
|
|||
|
|||
|
|||
//$(document).ready(function () { |
|||
// const today = new Date().toISOString().split('T')[0]; |
|||
//$("#date").val(today); |
|||
//}); |
|||
|
|||
$(document).ready(function () { |
|||
|
|||
const today = new Date(); |
|||
const yyyyMmDd = today.toISOString().split('T')[0]; |
|||
|
|||
const yesterday = new Date(); |
|||
yesterday.setDate(today.getDate() - 1); |
|||
const yyyMmDdYesterday = yesterday.toISOString().split('T')[0]; |
|||
|
|||
const $date = $("#date"); |
|||
|
|||
// set default date |
|||
$date.val(yyyyMmDd); |
|||
|
|||
// allow only yesterday and today |
|||
$date.attr("min", yyyMmDdYesterday); |
|||
$date.attr("max", yyyyMmDd); |
|||
|
|||
// 🚫 block manual typing & paste |
|||
$date.on("keydown paste", function (e) { |
|||
e.preventDefault(); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
|
|||
|
|||
$("#resetBtn").on("click", function () { |
|||
location.reload(); |
|||
}); |
|||
|
|||
// Load zones when page loads |
|||
$(document).ready(function () { |
|||
|
|||
$.ajax({ |
|||
url: "/swm/api/dropdown/getzoneslist", |
|||
type: "GET", |
|||
dataType: "json", |
|||
success: function (data) { |
|||
|
|||
let zoneDropdown = $("#zones"); |
|||
zoneDropdown.empty(); |
|||
zoneDropdown.append("<option value=''>Select Zone</option>"); |
|||
|
|||
$.each(data, function (index, item) { |
|||
zoneDropdown.append( |
|||
`<option value="${item.id}">${item.zone_name}</option>` |
|||
); |
|||
}); |
|||
}, |
|||
error: function (xhr, status, error) { |
|||
console.error("Error fetching zones:", error); |
|||
} |
|||
}); |
|||
|
|||
}); |
|||
|
|||
|
|||
|
|||
$("#submitBtn").on("click", function (e) { |
|||
e.preventDefault(); |
|||
|
|||
const zoneId = $("#zones").val(); |
|||
const reqDate = $("#date").val(); |
|||
const weight = $("#weight").val(); |
|||
const weight1 = $("#weight1").val(); |
|||
const weightType = $("#facilitytype").val(); |
|||
|
|||
const facilityTypeId = $("#facilityTypeId").val(); |
|||
|
|||
// 🔴 Client-side validations |
|||
if (!zoneId) { |
|||
Swal.fire("Validation Error", "Please select zone", "warning"); |
|||
return; |
|||
} |
|||
|
|||
if (!reqDate) { |
|||
Swal.fire("Validation Error", "Date is required", "warning"); |
|||
return; |
|||
} |
|||
|
|||
if (weight == null || weight == "") { |
|||
Swal.fire("Validation Error", "Weight is required", "warning"); |
|||
return; |
|||
} |
|||
|
|||
if (facilityTypeId == 5) { |
|||
if (weight < 0) { |
|||
Swal.fire("Validation Error", "Weight cannot be negative", "warning"); |
|||
return; |
|||
} |
|||
} else { |
|||
if (weight <= 0) { |
|||
Swal.fire("Validation Error", "Weight must be greater than zero", "warning"); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
// ⚠️ Note: |
|||
// Facility type 5 validation is done in BACKEND |
|||
// because facilityTypeId is derived after login |
|||
|
|||
$.ajax({ |
|||
url: "/swm/api/facilities/addfacility", |
|||
type: "POST", |
|||
data: { |
|||
zoneId: zoneId, |
|||
reqDate: reqDate, |
|||
weight: weight, |
|||
weight1: weight1, // backend will ignore if not needed |
|||
weightType: weightType |
|||
}, |
|||
beforeSend: function () { |
|||
Swal.fire({ |
|||
title: "Saving...", |
|||
text: "Please wait", |
|||
allowOutsideClick: false, |
|||
didOpen: () => Swal.showLoading() |
|||
}); |
|||
}, |
|||
success: function (response) { |
|||
Swal.fire("Success", response.message, "success"); |
|||
|
|||
// Reset fields |
|||
$("#weight").val(""); |
|||
$("#weight1").val(""); |
|||
}, |
|||
error: function (xhr) { |
|||
let msg = "Something went wrong"; |
|||
|
|||
if (xhr.responseJSON && xhr.responseJSON.message) { |
|||
msg = xhr.responseJSON.message; |
|||
} |
|||
|
|||
Swal.fire("Error", msg, "error"); |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
</script> |
|||
</body> |
|||
|
|||
</html> |
|||
@ -1,419 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en" xmlns:th="http://www.thymeleaf.org"> |
|||
|
|||
<head th:replace="~{fragments/modules/base/head :: head}"></head> |
|||
<style> |
|||
.width1 { |
|||
width: 120px; |
|||
} |
|||
|
|||
.width2 { |
|||
width: 150px; |
|||
} |
|||
|
|||
.modal-label { |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.modal-value { |
|||
color: #444; |
|||
} |
|||
|
|||
.modal-section-title { |
|||
font-size: 1.2rem; |
|||
font-weight: bold; |
|||
margin-top: 20px; |
|||
margin-bottom: 10px; |
|||
border-bottom: 2px solid #dee2e6; |
|||
padding-bottom: 5px; |
|||
} |
|||
|
|||
|
|||
.modal-title-big { |
|||
font-size: 20px; |
|||
font-weight: 700; |
|||
} |
|||
|
|||
.modal-subtext { |
|||
color: #b4c5d3; |
|||
font-size: 13px; |
|||
} |
|||
|
|||
.card-section { |
|||
background: white; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
margin-bottom: 25px; |
|||
border: 1px solid #eee; |
|||
} |
|||
|
|||
.section-title { |
|||
font-weight: 700; |
|||
color: #333; |
|||
margin-bottom: 15px; |
|||
font-size: 16px; |
|||
} |
|||
|
|||
.label-text { |
|||
font-size: 13px; |
|||
color: #6c757d; |
|||
} |
|||
|
|||
.value-text { |
|||
font-size: 15px; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.info-block { |
|||
display: flex; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
|
|||
.badge-status { |
|||
background: #ffd9b3; |
|||
color: #a65c00; |
|||
padding: 6px 10px; |
|||
border-radius: 5px; |
|||
font-size: 13px; |
|||
|
|||
} |
|||
|
|||
.btn-big { |
|||
padding: 12px 25px; |
|||
border-radius: 8px; |
|||
width: 200px; |
|||
} |
|||
|
|||
.rdo-box { |
|||
border: 1px solid #eee; |
|||
border-radius: 10px; |
|||
padding: 20px; |
|||
} |
|||
</style> |
|||
|
|||
<body th:attr="data-two-weight=${isTwoWeightFacility}"> |
|||
|
|||
<div class="wrapper"> |
|||
<!-- header top menu Start --> |
|||
<header th:replace="~{fragments/modules/base/header :: header}"></header> |
|||
<!-- header top menu end --> |
|||
<div class="page-wrap"> |
|||
<!--=============== Left Menu side Start ================--> |
|||
<div th:replace="~{fragments/modules/base/menu :: menu}"></div> |
|||
<!--=============== Left side End ================--> |
|||
<div class="main-content"> |
|||
<div class="container-fluid"> |
|||
<div class="page-header"> |
|||
<div class="row align-items-end"> |
|||
<div class="col-lg-6"> |
|||
<div class="page-header-title"> |
|||
<i class="fa fa-list-alt bg-blue"></i> |
|||
<div class="d-inline"> |
|||
<h5>SWD Windrow Facilities Add Details List</h5> |
|||
<span>Windrow Add Details</span> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-6"> |
|||
<nav class="breadcrumb-container" aria-label="breadcrumb"> |
|||
<ol class="breadcrumb"> |
|||
<li class="breadcrumb-item"> |
|||
<a href="/swm/index"><i class="ik ik-home"></i></a> |
|||
</li> |
|||
<li class="breadcrumb-item" aria-current="page">SWD Windrow Facilities Add |
|||
Details List |
|||
</li> |
|||
<li class="breadcrumb-item active" aria-current="page">Windrow Add Details</li> |
|||
</ol> |
|||
</nav> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="row mt-4"> |
|||
|
|||
<div class="col-md-12"> |
|||
<div class="card"> |
|||
<div class="card-header d-flex justify-content-between align-items-center fw-bold"> |
|||
<h3 class="mb-0"> SWM Windrow Add Details : <span th:text="${officer_name}"></span> |
|||
</h3> |
|||
<input type="hidden" id="userName" th:value="${officer_name}"> |
|||
</div> |
|||
|
|||
<div class="card-body"> |
|||
<div class="row"> |
|||
<div class="col-md-3"> |
|||
<label for="date" class="form-label" |
|||
style="font-size: medium;">Date:</label><span |
|||
class="text-danger">*</span> |
|||
<input type="date" id="date" class="form-control"> |
|||
</div> |
|||
<div class="col-md-3"> |
|||
<label for="zones" class="form-label">Zones <span |
|||
class="text-danger">*</span> |
|||
</label> <select id="zones" class="form-control"> |
|||
<option value="">Select zones</option> |
|||
|
|||
</select> |
|||
</div> |
|||
|
|||
<div class="col-md-3"> |
|||
|
|||
<label for="weight" class="form-label">Enter Weight:(in MT)</label><span |
|||
class="text-danger">*</span> |
|||
<input type="number" class="form-control" id="weight"> |
|||
</div> |
|||
|
|||
<input type="hidden" id="facilityTypeId" th:value="${facilityTypeId}"> |
|||
|
|||
<!-- SECOND WEIGHT (TC) --> |
|||
<div class="col-md-3" id="weight2Div" style="display:none;"> |
|||
<label for="weight1">Enter Weight (TC)</label><span |
|||
class="text-danger">*</span> |
|||
<input type="number" class="form-control" id="weight1"> |
|||
</div> |
|||
|
|||
<div class="col-md-3" style="margin-top: 30px;"> |
|||
<button id="submitBtn" class="btn btn-primary">Submit</button> |
|||
<button id="resetBtn" class="btn btn-secondary">Reset</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
<div id="pageLoader" |
|||
style="display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.8); z-index: 9999; text-align: center;"> |
|||
<div style="position: relative; top: 50%; transform: translateY(-50%);"> |
|||
<div class="spinner-border text-primary" role="status" style="width: 3rem; height: 3rem;"> |
|||
<span class="sr-only">Loading...</span> |
|||
</div> |
|||
<!-- Add the 'Please wait' text below the spinner --> |
|||
<p style="margin-top: 1rem; font-size: 1.2rem; color: #007bff;">Please wait...</p> |
|||
</div> |
|||
</div> |
|||
|
|||
<div th:replace="~{fragments/modules/base/app_module_menu_box :: div}"></div> |
|||
|
|||
<footer th:replace="~{fragments/modules/base/footer :: footer}"></footer> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Details Modal --> |
|||
<div class="modal fade" id="detailsModal" tabindex="-1" aria-hidden="true"> |
|||
<div class="modal-dialog modal-xl modal-dialog-scrollable"> |
|||
<div class="modal-content"> |
|||
|
|||
<div class="modal-header" style="background:#2f3e54; color:white;"> |
|||
<div> |
|||
<h4 class="modal-title-big" id="modalTitle"></h4> |
|||
<div id="modalSubTitle" class="modal-subtext"></div> |
|||
</div> |
|||
|
|||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span |
|||
aria-hidden="true">×</span></button> |
|||
</div> |
|||
|
|||
<div class="modal-body"> |
|||
|
|||
<div id="modalContent"></div> |
|||
|
|||
<div class="text-center mt-4"> |
|||
<button type="button" class="btn btn-primary btn-big" data-dismiss="modal" |
|||
style="background:#2f3e54;">Close</button> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
<script th:replace="~{fragments/modules/base/script :: script}"></script> |
|||
<script type="text/javascript"> |
|||
|
|||
$(document).ready(function () { |
|||
|
|||
const today = new Date(); |
|||
const day = today.getDay(); // 0=Sun, 1=Mon, ..., 6=Sat |
|||
|
|||
/* ============================= |
|||
LAST SATURDAY |
|||
============================= */ |
|||
const lastSaturday = new Date(today); |
|||
|
|||
// If today is Saturday (6) → today |
|||
// Else → go back to previous Saturday |
|||
const diffToLastSaturday = (day >= 6) |
|||
? day - 6 |
|||
: day + 1; |
|||
|
|||
lastSaturday.setDate(today.getDate() - diffToLastSaturday); |
|||
|
|||
/* ============================= |
|||
THIS WEEK FRIDAY |
|||
============================= */ |
|||
const thisFriday = new Date(today); |
|||
|
|||
// Friday = 5 |
|||
const diffToFriday = (5 - day + 7) % 7; |
|||
thisFriday.setDate(today.getDate() + diffToFriday); |
|||
|
|||
/* ============================= |
|||
FORMAT YYYY-MM-DD |
|||
============================= */ |
|||
const formatDate = (d) => d.toISOString().split("T")[0]; |
|||
|
|||
const minDate = formatDate(lastSaturday); |
|||
const maxDate = formatDate(thisFriday); |
|||
|
|||
/* ============================= |
|||
APPLY LIMITS |
|||
============================= */ |
|||
$("#date") |
|||
.attr("min", minDate) |
|||
.attr("max", maxDate) |
|||
.val(formatDate(today)); |
|||
// 🔒 BLOCK MANUAL TYPING (BUT ALLOW CALENDAR) |
|||
$("#date").on("keydown paste", function (e) { |
|||
e.preventDefault(); |
|||
}); |
|||
}); |
|||
$(document).ready(function () { |
|||
const isTwoWeightFacility = |
|||
$("body").data("two-weight") === true || |
|||
$("body").data("two-weight") === "true"; |
|||
|
|||
console.log($("body").data("two-weight")); |
|||
|
|||
|
|||
if (isTwoWeightFacility) { |
|||
$("#weight2Div").show(); |
|||
} else { |
|||
$("#weight2Div").hide(); |
|||
$("#weight1").val(""); |
|||
} |
|||
}); |
|||
|
|||
|
|||
$(document).ready(function () { |
|||
const today = new Date().toISOString().split('T')[0]; |
|||
$("#date").val(today); |
|||
}); |
|||
|
|||
$("#resetBtn").on("click", function () { |
|||
location.reload(); |
|||
}); |
|||
|
|||
// Load zones when page loads |
|||
$(document).ready(function () { |
|||
|
|||
$.ajax({ |
|||
url: "/swm/api/dropdown/getzoneslist", |
|||
type: "GET", |
|||
dataType: "json", |
|||
success: function (data) { |
|||
|
|||
let zoneDropdown = $("#zones"); |
|||
zoneDropdown.empty(); |
|||
zoneDropdown.append("<option value=''>Select Zone</option>"); |
|||
|
|||
$.each(data, function (index, item) { |
|||
zoneDropdown.append( |
|||
`<option value="${item.id}">${item.zone_name}</option>` |
|||
); |
|||
}); |
|||
}, |
|||
error: function (xhr, status, error) { |
|||
console.error("Error fetching zones:", error); |
|||
} |
|||
}); |
|||
|
|||
}); |
|||
|
|||
|
|||
|
|||
$("#submitBtn").on("click", function (e) { |
|||
e.preventDefault(); |
|||
|
|||
const facilityTypeId = $("#facilityTypeId").val(); // ✅ dynamic |
|||
const zoneId = $("#zones").val(); |
|||
const reqDate = $("#date").val(); |
|||
const weight = $("#weight").val(); |
|||
const weight1 = $("#weight1").val(); |
|||
const createdBy = $("#userName").val(); |
|||
|
|||
// 🔴 Client-side validations |
|||
if (!zoneId) { |
|||
Swal.fire("Validation Error", "Please select zone", "warning"); |
|||
return; |
|||
} |
|||
|
|||
if (!reqDate) { |
|||
Swal.fire("Validation Error", "Date is required", "warning"); |
|||
return; |
|||
} |
|||
|
|||
if (!weight || weight <= 0) { |
|||
Swal.fire("Validation Error", "Weight must be greater than zero", "warning"); |
|||
return; |
|||
} |
|||
|
|||
// ⚠️ Note: |
|||
// Facility type 5 validation is done in BACKEND |
|||
// because facilityTypeId is derived after login |
|||
|
|||
$.ajax({ |
|||
url: "/swm/api/admin/addfacility", |
|||
type: "POST", |
|||
data: { |
|||
facilityTypeId: facilityTypeId, |
|||
zoneId: zoneId, |
|||
reqDate: reqDate, |
|||
weight: weight, |
|||
weight1: weight1, |
|||
createdBy: createdBy // backend will ignore if not needed |
|||
}, |
|||
beforeSend: function () { |
|||
Swal.fire({ |
|||
title: "Saving...", |
|||
text: "Please wait", |
|||
allowOutsideClick: false, |
|||
didOpen: () => Swal.showLoading() |
|||
}); |
|||
}, |
|||
success: function (response) { |
|||
Swal.fire("Success", response.message, "success"); |
|||
|
|||
// Reset fields |
|||
$("#weight").val(""); |
|||
$("#weight1").val(""); |
|||
}, |
|||
error: function (xhr) { |
|||
let msg = "Something went wrong"; |
|||
|
|||
if (xhr.responseJSON && xhr.responseJSON.message) { |
|||
msg = xhr.responseJSON.message; |
|||
} |
|||
|
|||
Swal.fire("Error", msg, "error"); |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
|
|||
|
|||
</script> |
|||
</body> |
|||
|
|||
</html> |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue