|
|
@ -196,14 +196,18 @@ |
|
|
|
|
|
|
|
|
<div class="container-fluid py-4"> |
|
|
<div class="container-fluid py-4"> |
|
|
<div class="page-header-title"> |
|
|
<div class="page-header-title"> |
|
|
<h4>Food Distribution FSSAI Compliance Report</h4> |
|
|
|
|
|
|
|
|
<h4>Food Distribution Report</h4> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<!-- Filter Section --> |
|
|
<!-- Filter Section --> |
|
|
<div class="filter-section d-flex justify-content-center align-items-end gap-3 flex-wrap"> |
|
|
<div class="filter-section d-flex justify-content-center align-items-end gap-3 flex-wrap"> |
|
|
<div> |
|
|
<div> |
|
|
<label for="filterDate" class="form-label fw-bold">Select Date</label> |
|
|
|
|
|
<input type="date" id="filterDate" class="form-control"> |
|
|
|
|
|
|
|
|
<label for="fromDate" class="form-label fw-bold">From Date:</label> |
|
|
|
|
|
<input type="date" id="fromDate" class="form-control"> |
|
|
|
|
|
</div> |
|
|
|
|
|
<div> |
|
|
|
|
|
<label for="toDate" class="form-label fw-bold">To Date:</label> |
|
|
|
|
|
<input type="date" id="toDate" class="form-control"> |
|
|
</div> |
|
|
</div> |
|
|
<div> |
|
|
<div> |
|
|
<button id="btnSearch" class="btn btn-primary px-4"><i class="fa-solid fa-search"></i> Search</button> |
|
|
<button id="btnSearch" class="btn btn-primary px-4"><i class="fa-solid fa-search"></i> Search</button> |
|
|
@ -249,7 +253,7 @@ |
|
|
<table id="modalDataTable" class="table table-bordered table-striped"> |
|
|
<table id="modalDataTable" class="table table-bordered table-striped"> |
|
|
<thead class="table-dark"> |
|
|
<thead class="table-dark"> |
|
|
<tr> |
|
|
<tr> |
|
|
<th class="text-center">ID</th> |
|
|
|
|
|
|
|
|
<th class="text-center">S.No</th> |
|
|
<th class="text-center">Audit Date</th> |
|
|
<th class="text-center">Audit Date</th> |
|
|
<th class="text-center">Shift</th> |
|
|
<th class="text-center">Shift</th> |
|
|
<th class="text-center">Zone</th> |
|
|
<th class="text-center">Zone</th> |
|
|
@ -266,6 +270,9 @@ |
|
|
<th class="text-center">FS Challenged By</th> |
|
|
<th class="text-center">FS Challenged By</th> |
|
|
<th class="text-center">FS Remarks</th> |
|
|
<th class="text-center">FS Remarks</th> |
|
|
<th class="text-center">FS Image/Video Viewer</th> |
|
|
<th class="text-center">FS Image/Video Viewer</th> |
|
|
|
|
|
<th class="text-center">CE Status</th> |
|
|
|
|
|
<th class="text-center">CE Remarks</th> |
|
|
|
|
|
<th class="text-center">CE Updated By</th> |
|
|
</tr> |
|
|
</tr> |
|
|
</thead> |
|
|
</thead> |
|
|
<tbody id="modalTableBody"> |
|
|
<tbody id="modalTableBody"> |
|
|
@ -313,13 +320,26 @@ |
|
|
var modalTable = null; |
|
|
var modalTable = null; |
|
|
|
|
|
|
|
|
$(document).ready(function () { |
|
|
$(document).ready(function () { |
|
|
// Set default date to yesterday |
|
|
|
|
|
|
|
|
// Set default dates to yesterday |
|
|
var yesterday = new Date(); |
|
|
var yesterday = new Date(); |
|
|
yesterday.setDate(yesterday.getDate() - 1); |
|
|
yesterday.setDate(yesterday.getDate() - 1); |
|
|
var yyyy = yesterday.getFullYear(); |
|
|
var yyyy = yesterday.getFullYear(); |
|
|
var mm = String(yesterday.getMonth() + 1).padStart(2, '0'); |
|
|
var mm = String(yesterday.getMonth() + 1).padStart(2, '0'); |
|
|
var dd = String(yesterday.getDate()).padStart(2, '0'); |
|
|
var dd = String(yesterday.getDate()).padStart(2, '0'); |
|
|
$('#filterDate').val(yyyy + '-' + mm + '-' + dd); |
|
|
|
|
|
|
|
|
var defaultDate = yyyy + '-' + mm + '-' + dd; |
|
|
|
|
|
|
|
|
|
|
|
$('#fromDate').val(defaultDate); |
|
|
|
|
|
$('#toDate').val(defaultDate); |
|
|
|
|
|
$('#toDate').attr('min', defaultDate); |
|
|
|
|
|
|
|
|
|
|
|
$('#fromDate').on('change', function () { |
|
|
|
|
|
var selectedDate = $(this).val(); |
|
|
|
|
|
$('#toDate').attr('min', selectedDate); |
|
|
|
|
|
// if toDate is now before fromDate, reset it to fromDate |
|
|
|
|
|
if ($('#toDate').val() < selectedDate) { |
|
|
|
|
|
$('#toDate').val(selectedDate); |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
// Init modal DT just once |
|
|
// Init modal DT just once |
|
|
modalTable = $('#modalDataTable').DataTable({ |
|
|
modalTable = $('#modalDataTable').DataTable({ |
|
|
@ -341,7 +361,10 @@ |
|
|
{ width: "120px", targets: 13 }, |
|
|
{ width: "120px", targets: 13 }, |
|
|
{ width: "150px", targets: 14 }, |
|
|
{ width: "150px", targets: 14 }, |
|
|
{ width: "220px", targets: 15 }, // FS Remarks |
|
|
{ width: "220px", targets: 15 }, // FS Remarks |
|
|
{ width: "150px", targets: 16 } |
|
|
|
|
|
|
|
|
{ width: "150px", targets: 16 }, // fsImgBtn |
|
|
|
|
|
{ width: "120px", targets: 17 }, // CE Status |
|
|
|
|
|
{ width: "220px", targets: 18 }, // CE Remarks |
|
|
|
|
|
{ width: "150px", targets: 19 } // Chief Engineer |
|
|
], |
|
|
], |
|
|
responsive: false, |
|
|
responsive: false, |
|
|
scrollX: true, |
|
|
scrollX: true, |
|
|
@ -377,12 +400,15 @@ |
|
|
|
|
|
|
|
|
// Delegate click for modal details |
|
|
// Delegate click for modal details |
|
|
$('#ComplianceAbstractTable tbody').on('click', '.clickable-cell', function () { |
|
|
$('#ComplianceAbstractTable tbody').on('click', '.clickable-cell', function () { |
|
|
var filterDate = $('#filterDate').val() || ''; |
|
|
|
|
|
|
|
|
var fromDate = $('#fromDate').val() || ''; |
|
|
|
|
|
var toDate = $('#toDate').val() || ''; |
|
|
var hubId = $(this).data('hubid'); |
|
|
var hubId = $(this).data('hubid'); |
|
|
var shiftId = $(this).data('shiftid'); |
|
|
var shiftId = $(this).data('shiftid'); |
|
|
var qid = $(this).data('qid'); |
|
|
var qid = $(this).data('qid'); |
|
|
var statusFilter = $(this).data('status'); |
|
|
var statusFilter = $(this).data('status'); |
|
|
|
|
|
|
|
|
|
|
|
var clickedCell = $(this); |
|
|
|
|
|
|
|
|
if (!hubId || !qid || !statusFilter) return; |
|
|
if (!hubId || !qid || !statusFilter) return; |
|
|
|
|
|
|
|
|
// Show loading... |
|
|
// Show loading... |
|
|
@ -392,7 +418,8 @@ |
|
|
url: '/commissionerreview/api/fooddistribution/complianceDetails', |
|
|
url: '/commissionerreview/api/fooddistribution/complianceDetails', |
|
|
method: 'GET', |
|
|
method: 'GET', |
|
|
data: { |
|
|
data: { |
|
|
date: filterDate, |
|
|
|
|
|
|
|
|
fromDate: fromDate, |
|
|
|
|
|
toDate: toDate, |
|
|
hubId: hubId, |
|
|
hubId: hubId, |
|
|
shiftId: shiftId, |
|
|
shiftId: shiftId, |
|
|
qid: qid, |
|
|
qid: qid, |
|
|
@ -428,7 +455,11 @@ |
|
|
var groupedCategories = {}; |
|
|
var groupedCategories = {}; |
|
|
categoryMap.forEach(function (q) { |
|
|
categoryMap.forEach(function (q) { |
|
|
if (!groupedCategories[q.qcm_id]) { |
|
|
if (!groupedCategories[q.qcm_id]) { |
|
|
groupedCategories[q.qcm_id] = { name: q.audit_category, questions: [] }; |
|
|
|
|
|
|
|
|
var catName = q.audit_category; |
|
|
|
|
|
if (q.code && q.code.trim() !== '' && q.code !== 'null') { |
|
|
|
|
|
catName += ' - ' + q.code; |
|
|
|
|
|
} |
|
|
|
|
|
groupedCategories[q.qcm_id] = { name: catName, questions: [] }; |
|
|
} |
|
|
} |
|
|
groupedCategories[q.qcm_id].questions.push(q); |
|
|
groupedCategories[q.qcm_id].questions.push(q); |
|
|
}); |
|
|
}); |
|
|
@ -449,7 +480,8 @@ |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function loadAbstractReport() { |
|
|
function loadAbstractReport() { |
|
|
var filterDate = $('#filterDate').val() || ''; |
|
|
|
|
|
|
|
|
var fromDate = $('#fromDate').val() || ''; |
|
|
|
|
|
var toDate = $('#toDate').val() || ''; |
|
|
|
|
|
|
|
|
// Show loading |
|
|
// Show loading |
|
|
Swal.fire({ title: 'Fetching Data...', allowOutsideClick: false, didOpen: function () { Swal.showLoading(); } }); |
|
|
Swal.fire({ title: 'Fetching Data...', allowOutsideClick: false, didOpen: function () { Swal.showLoading(); } }); |
|
|
@ -457,7 +489,7 @@ |
|
|
$.ajax({ |
|
|
$.ajax({ |
|
|
url: '/commissionerreview/api/fooddistribution/complianceAbstract', |
|
|
url: '/commissionerreview/api/fooddistribution/complianceAbstract', |
|
|
method: 'GET', |
|
|
method: 'GET', |
|
|
data: { date: filterDate }, |
|
|
|
|
|
|
|
|
data: { fromDate: fromDate, toDate: toDate }, |
|
|
success: function (res) { |
|
|
success: function (res) { |
|
|
Swal.close(); |
|
|
Swal.close(); |
|
|
if (res.status === 'success') { |
|
|
if (res.status === 'success') { |
|
|
@ -486,10 +518,14 @@ |
|
|
var tableEl = document.getElementById('ComplianceAbstractTable'); |
|
|
var tableEl = document.getElementById('ComplianceAbstractTable'); |
|
|
|
|
|
|
|
|
// Use SheetJS to convert it purely visually exactly as the screen merges it |
|
|
// Use SheetJS to convert it purely visually exactly as the screen merges it |
|
|
var wb = XLSX.utils.table_to_book(tableEl, { sheet: "FSSAI Report", raw: true }); |
|
|
|
|
|
|
|
|
var wb = XLSX.utils.table_to_book(tableEl, { sheet: "FSSAI Report", raw: true, display: true }); |
|
|
|
|
|
|
|
|
// Trigger download |
|
|
|
|
|
XLSX.writeFile(wb, 'Food_Distribution_Compliance.xlsx'); |
|
|
|
|
|
|
|
|
// Get date for file naming |
|
|
|
|
|
var dFrom = $('#fromDate').val() || 'All_Dates'; |
|
|
|
|
|
var dTo = $('#toDate').val() || 'All_Dates'; |
|
|
|
|
|
|
|
|
|
|
|
// Trigger download with custom date in filename |
|
|
|
|
|
XLSX.writeFile(wb, 'Food_Distribution_Compliance_' + dFrom + '_to_' + dTo + '.xlsx'); |
|
|
|
|
|
|
|
|
// Restore old page length |
|
|
// Restore old page length |
|
|
dt.page.len(currentLen).draw(false); |
|
|
dt.page.len(currentLen).draw(false); |
|
|
@ -554,11 +590,14 @@ |
|
|
var qId = row.qid; |
|
|
var qId = row.qid; |
|
|
if (qId) { |
|
|
if (qId) { |
|
|
if (!hubGroups[kId].shifts[shiftId].counts[qId]) { |
|
|
if (!hubGroups[kId].shifts[shiftId].counts[qId]) { |
|
|
hubGroups[kId].shifts[shiftId].counts[qId] = { 'Issue Found': 0, 'No Issue': 0 }; |
|
|
|
|
|
|
|
|
hubGroups[kId].shifts[shiftId].counts[qId] = { 'Issue Found': 0, 'No Issue': 0, 'fs_review': 0 }; |
|
|
} |
|
|
} |
|
|
var s = row.answer_status; |
|
|
var s = row.answer_status; |
|
|
if (s === 'Issue Found' || s === 'No Issue') { |
|
|
if (s === 'Issue Found' || s === 'No Issue') { |
|
|
hubGroups[kId].shifts[shiftId].counts[qId][s] += row.issue_count; |
|
|
hubGroups[kId].shifts[shiftId].counts[qId][s] += row.issue_count; |
|
|
|
|
|
if (row.fs_review_count && row.fs_review_count > 0) { |
|
|
|
|
|
hubGroups[kId].shifts[shiftId].counts[qId]['fs_review'] += row.fs_review_count; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
@ -593,10 +632,12 @@ |
|
|
var counts = shift.counts[q.qid] || { 'Issue Found': 0 }; |
|
|
var counts = shift.counts[q.qid] || { 'Issue Found': 0 }; |
|
|
|
|
|
|
|
|
var issueCount = counts['Issue Found'] || 0; |
|
|
var issueCount = counts['Issue Found'] || 0; |
|
|
|
|
|
var fsRevCount = counts['fs_review'] || 0; |
|
|
totalIssues += issueCount; |
|
|
totalIssues += issueCount; |
|
|
questionTotals[q.qid] = (questionTotals[q.qid] || 0) + issueCount; |
|
|
questionTotals[q.qid] = (questionTotals[q.qid] || 0) + issueCount; |
|
|
|
|
|
|
|
|
var tdIssue = '<td><span class="clickable-cell" data-hubid="' + hub.hub_id + '" data-shiftid="' + shift.shift_id + '" data-qid="' + q.qid + '" data-status="Issue Found">' + (issueCount || '') + '</span></td>'; |
|
|
|
|
|
|
|
|
var textVal = issueCount > 0 ? '<span class="clickable-cell" ' + (fsRevCount > 0 ? 'style="color: red;"' : '') + ' data-hubid="' + hub.hub_id + '" data-shiftid="' + shift.shift_id + '" data-qid="' + q.qid + '" data-status="Issue Found">' + issueCount + '</span>' : ''; |
|
|
|
|
|
var tdIssue = '<td>' + textVal + '</td>'; |
|
|
|
|
|
|
|
|
tr.append(tdIssue); |
|
|
tr.append(tdIssue); |
|
|
}); |
|
|
}); |
|
|
@ -628,7 +669,7 @@ |
|
|
|
|
|
|
|
|
function populateModal(data) { |
|
|
function populateModal(data) { |
|
|
modalTable.clear(); |
|
|
modalTable.clear(); |
|
|
data.forEach(function (item) { |
|
|
|
|
|
|
|
|
data.forEach(function (item, index) { |
|
|
var ext = item.videoLink ? item.videoLink.split('.').pop().toLowerCase() : ''; |
|
|
var ext = item.videoLink ? item.videoLink.split('.').pop().toLowerCase() : ''; |
|
|
var isVideo = ['mp4', 'mov', 'avi', 'webm', 'mkv'].includes(ext); |
|
|
var isVideo = ['mp4', 'mov', 'avi', 'webm', 'mkv'].includes(ext); |
|
|
|
|
|
|
|
|
@ -646,9 +687,9 @@ |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
modalTable.row.add([ |
|
|
modalTable.row.add([ |
|
|
item.id, |
|
|
|
|
|
|
|
|
index + 1, |
|
|
item.auditDate || '-', |
|
|
item.auditDate || '-', |
|
|
item.shiftid || '-', |
|
|
|
|
|
|
|
|
item.shift || '-', |
|
|
item.zone || '-', |
|
|
item.zone || '-', |
|
|
item.ward || '-', |
|
|
item.ward || '-', |
|
|
item.address || '-', |
|
|
item.address || '-', |
|
|
@ -662,7 +703,10 @@ |
|
|
item.fsStatus || '-', |
|
|
item.fsStatus || '-', |
|
|
item.fsChallengedBy || '-', |
|
|
item.fsChallengedBy || '-', |
|
|
item.fsRemarks || '-', |
|
|
item.fsRemarks || '-', |
|
|
fsImgBtn |
|
|
|
|
|
|
|
|
fsImgBtn, |
|
|
|
|
|
item.chief_engineer_status || '-', |
|
|
|
|
|
item.chief_engineer_remarks || '-', |
|
|
|
|
|
item.chief_engineer || '-' |
|
|
]); |
|
|
]); |
|
|
}); |
|
|
}); |
|
|
modalTable.draw(); |
|
|
modalTable.draw(); |
|
|
|