|
|
|
@ -143,7 +143,7 @@ |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- FILTER SECTION --> |
|
|
|
<div class="card-body pb-0"> |
|
|
|
<!-- <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> |
|
|
|
@ -155,14 +155,73 @@ |
|
|
|
<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"> |
|
|
|
@ -190,7 +249,11 @@ |
|
|
|
|
|
|
|
<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> |
|
|
|
|
|
|
|
@ -200,7 +263,7 @@ |
|
|
|
<th colspan="3">Bio-GAS</th> |
|
|
|
<th colspan="3">Horticulture</th> |
|
|
|
<th colspan="3">Incinerator</th> |
|
|
|
<th colspan="3">Plastic Baling Centre</th> |
|
|
|
<th colspan="3">Plasting Baling Centre</th> |
|
|
|
</tr> |
|
|
|
|
|
|
|
<!-- ROW 2 : SUB HEADERS --> |
|
|
|
@ -329,6 +392,8 @@ |
|
|
|
<script th:replace="~{fragments/modules/base/script :: script}"></script> |
|
|
|
<script type="text/javascript"> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let table; |
|
|
|
|
|
|
|
$(document).ready(function () { |
|
|
|
@ -339,8 +404,8 @@ |
|
|
|
searching: true, |
|
|
|
info: true, |
|
|
|
paging: true, |
|
|
|
pageLength: 15, // ✅ show 15 rows |
|
|
|
lengthMenu: [15, 25, 50, 100], // ✅ optional dropdown |
|
|
|
pageLength: 15, // show 15 rows |
|
|
|
lengthMenu: [15, 25, 50, 100], // optional dropdown |
|
|
|
scrollX: true, |
|
|
|
responsive: false, |
|
|
|
dom: 'Bftip', |
|
|
|
@ -385,9 +450,9 @@ |
|
|
|
'GW & TC Waste Achieved', |
|
|
|
'GW & TC Waste %', |
|
|
|
|
|
|
|
'Plastic Baling Centre Target', |
|
|
|
'Plastic Baling Centre Achieved', |
|
|
|
'Plastic Baling Centre %' |
|
|
|
'Plasting Baling Centre Target', |
|
|
|
'Plasting Baling Centre Achieved', |
|
|
|
'Plasting Baling Centre %' |
|
|
|
]; |
|
|
|
|
|
|
|
return headers[columnIdx]; |
|
|
|
@ -477,9 +542,9 @@ |
|
|
|
{ data: "GW & TC Waste_achieved" }, |
|
|
|
{ data: "GW & TC Waste_percentage" }, |
|
|
|
|
|
|
|
{ data: "Plastic Baling Centre_target" }, |
|
|
|
{ data: "Plastic Baling Centre_achieved" }, |
|
|
|
{ data: "Plastic Baling Centre_percentage" } |
|
|
|
{ data: "Plasting Baling Centre_target" }, |
|
|
|
{ data: "Plasting Baling Centre_achieved" }, |
|
|
|
{ data: "Plasting Baling Centre_percentage" } |
|
|
|
], |
|
|
|
|
|
|
|
footerCallback: function () { |
|
|
|
@ -534,20 +599,219 @@ |
|
|
|
$("#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 fromDate = $("#fromDate").val(); |
|
|
|
const toDate = $("#toDate").val(); |
|
|
|
const reportType = $("#reportType").val(); |
|
|
|
|
|
|
|
if (!fromDate || !toDate) { |
|
|
|
Swal.fire("Validation Error", "Please select both dates", "warning"); |
|
|
|
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: "/swm/api/admin/reports", |
|
|
|
url: url, |
|
|
|
type: "GET", |
|
|
|
data: { fromDate, toDate }, |
|
|
|
data: data, |
|
|
|
beforeSend: function () { |
|
|
|
Swal.fire({ |
|
|
|
title: "Loading...", |
|
|
|
@ -556,8 +820,19 @@ |
|
|
|
}); |
|
|
|
}, |
|
|
|
success: function (res) { |
|
|
|
|
|
|
|
Swal.close(); |
|
|
|
renderZoneTable(res.data); |
|
|
|
|
|
|
|
// ✅ 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"); |
|
|
|
@ -565,6 +840,8 @@ |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function renderZoneTable(data) { |
|
|
|
|
|
|
|
const zoneMap = {}; |
|
|
|
@ -591,6 +868,76 @@ |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 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> |
|
|
|
|