1357 lines
57 KiB
Plaintext
1357 lines
57 KiB
Plaintext
@{
|
|
ViewData["Title"] = "Capaian BPS RW per Wilayah";
|
|
}
|
|
|
|
<div class="breadcrumbs text-sm">
|
|
<ul>
|
|
<li class="text-gray-500"><a>Laporan</a></li>
|
|
<li>Capaian BPS RW per Wilayah</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 gap-4 lg:grid-cols-2">
|
|
<div class="prose">
|
|
<h3 class="mb-2">Capaian BPS RW per Wilayah</h3>
|
|
</div>
|
|
<div class="justify-self-end lg:self-center">
|
|
<button class="btn rounded-full bg-white" type="button" onclick="modal_filter.showModal()">
|
|
<span class="icon icon-fill me-2">filter_list</span>
|
|
Filter
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="h-6"></div>
|
|
|
|
<!-- Tingkat Kepatuhan PJLP -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<div class="bg-white rounded-lg shadow-md p-6">
|
|
<h3 class="text-lg font-semibold mb-1">Tingkat Kepatuhan PJLP</h3>
|
|
<p class="text-md font-medium mb-1" id="descTingkatKepatuhan">Tingkat Kepatuhan PJLP Periode Mei-Oktober</p>
|
|
<p class="text-sm mb-4" id="locationTingkatKepatuhan">Kota Administrasi Jakarta Barat</p>
|
|
<div class="border border-gray-400 rounded-sm p-4">
|
|
<div class="w-full" id="chartTingkatKepatuhanContainer">
|
|
<canvas id="chartTingkatKepatuhan"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Status Validasi SATPEL -->
|
|
<div class="bg-white rounded-lg shadow-md p-6">
|
|
<h3 class="text-lg font-semibold mb-1">Status Validasi SATPEL</h3>
|
|
<p class="text-md font-medium mb-1" id="descStatusSatpel">Status Validasi SATPEL Periode Oktober</p>
|
|
<p class="text-sm mb-4" id="locationStatusSatpel">Kota Administrasi Jakarta Barat</p>
|
|
|
|
<div class="border border-gray-400 rounded-sm p-4">
|
|
<div class="w-full min-h-80">
|
|
<canvas id="chartStatusSatpel"></canvas>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4 p-4 bg-gray-100 rounded-lg">
|
|
<p class="text-sm font-semibold text-gray-700 mb-2">Terhadap status validasi:</p>
|
|
<div id="satpelValidationText" class="text-sm"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Status Validasi SUDIN -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-6">
|
|
<div class="bg-white rounded-lg shadow-md p-6">
|
|
<h3 class="text-lg font-semibold mb-1">Status Validasi SUDIN</h3>
|
|
<p class="text-md font-medium mb-1" id="descStatusSudin">Status Validasi SUDIN Periode Oktober</p>
|
|
<p class="text-sm mb-4" id="locationStatusSudin">Kota Administrasi Jakarta Barat</p>
|
|
|
|
<div class="border border-gray-400 rounded-sm p-4">
|
|
<div class="w-full min-h-80">
|
|
<canvas id="chartStatusSudin"></canvas>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4 p-4 bg-gray-100 rounded-lg">
|
|
<p class="text-sm font-semibold text-gray-700 mb-2">Terhadap status validasi:</p>
|
|
<div id="sudinValidationText" class="text-sm"></div>
|
|
</div>
|
|
</div>
|
|
<div class="bg-white rounded-lg shadow-md p-6">
|
|
<h3 class="text-lg font-semibold mb-1">Capaian Rumah Memilah</h3>
|
|
<p class="text-md font-medium mb-1" id="descCapaianRumah">Capaian Rumah Memilah Periode Oktober 2025</p>
|
|
<p class="text-sm mb-4" id="locationCapaianRumah">Kota Administrasi Jakarta Barat</p>
|
|
<div class="border border-gray-400 rounded-sm p-4">
|
|
<div class="w-full min-h-80">
|
|
<canvas id="chartCapaianRumah"></canvas>
|
|
</div>
|
|
</div>
|
|
<div class="mt-4 p-4 bg-gray-100 rounded-lg">
|
|
<p class="text-sm font-semibold text-gray-700 mb-2">Terhadap Tingkat kepatuhan dalam melaksanakan SK Kepala
|
|
Dinas LH Nomor e-0017 Tahun 2025 dan Instruksi Kepala Dinas LH Nomor e-0003 Tahun 2025, dalam
|
|
menjalankan program pertumbuhan rumah memilah di lingkup warga:</p>
|
|
<div id="capaianRumahText" class="text-sm"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Volume Timbulan Sampah -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-6">
|
|
<div class="bg-white rounded-lg shadow-md p-6">
|
|
<h3 class="text-lg font-semibold mb-1">Volume Timbulan Sampah</h3>
|
|
<p class="text-md font-medium mb-1" id="descVolumeSampah">Volume Timbulan Sampah Per Hari Per Jiwa Dalam Satu
|
|
Bulan Oktober</p>
|
|
|
|
<p class="text-sm mb-4" id="locationVolumeSampah">Kota Administrasi Jakarta Barat</p>
|
|
<div class="border border-gray-400 rounded-sm p-4">
|
|
<div class="w-full" id="chartVolumeSampahContainer">
|
|
<canvas id="chartVolumeSampah"></canvas>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4 p-4 bg-gray-100 rounded-lg">
|
|
<p class="text-sm text-gray-600" id="volumeSampahText">Terhadap total volume timbulan sampah organik hasil
|
|
pilahan 5367 rumah tangga memilah secara konsisten periode bulan Oktober sebanyak 28092,18 Kg.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Realisasi Terhadap Target -->
|
|
<div class="bg-white rounded-lg shadow-md p-6">
|
|
<h3 class="text-lg font-semibold mb-1">Realisasi Terhadap Target</h3>
|
|
<p class="text-md font-medium mb-1" id="descRealisasi">Laporan Program Realisasi dan Realisasi Terhadap Target
|
|
Maret-Oktober</p>
|
|
<p class="text-sm mb-4" id="locationRealisasi">Kota Administrasi Jakarta Barat</p>
|
|
|
|
<div class="border border-gray-400 rounded-sm p-4">
|
|
<div class="w-full min-h-80">
|
|
<canvas id="chartRealisasi"></canvas>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4 p-4 bg-gray-100 rounded-lg">
|
|
<p class="text-sm font-semibold text-gray-700 mb-2">Terhadap realisasi target rumah memilah sebagai berikut:
|
|
</p>
|
|
<div id="realisasiTargetText" class="text-sm"></div>
|
|
<p class="text-sm text-gray-600 mt-3 font-medium">Dari diagram dapat dilihat bahwa terjadi progres
|
|
pertumbuhan rumah memilah disetiap bulannya.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tingkat Kepatuhan PJLP Periode -->
|
|
<div class="bg-white rounded-lg shadow-md p-6 mt-6">
|
|
|
|
<div class="grid grid-cols-1 gap-4 lg:grid-cols-2">
|
|
<div class="prose">
|
|
<h3 class="text-lg font-semibold mb-1" id="titleKepatuhanPeriode">Tingkat Kepatuhan PJLP Periode</h3>
|
|
<p class="text-md font-medium" id="subtitleKepatuhanPeriode">Tingkat Kepatuhan PJLP Periode</p>
|
|
<p class="text-sm mb-4" id="locationKepatuhanPeriode">Kota Administrasi Jakarta Barat</p>
|
|
</div>
|
|
<div class="flex justify-end items-start mb-4">
|
|
<input type="month" id="filterBulan" class="px-4 py-2 border bg-white rounded-md w-[180px] sm:w-[200px]"
|
|
min="2020-01" max="@DateTime.Now.ToString("yyyy-MM")" value="@DateTime.Now.ToString("yyyy-MM")" />
|
|
</div>
|
|
</div>
|
|
<div class="border border-gray-400 rounded-sm p-4">
|
|
<div class="w-full h-[400px]">
|
|
<canvas id="chartKepatuhanPeriode"></canvas>
|
|
</div>
|
|
</div>
|
|
<!-- PJLP Pendamping Cards -->
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mt-6">
|
|
<div class="border border-gray-400 rounded-lg p-4">
|
|
<p class="text-md text-gray-800 mb-2">Total PJLP Pendamping</p>
|
|
|
|
<div class="flex flex-row items-center gap-2">
|
|
<p class="text-3xl font-bold text-primary-500" id="totalPjlpPendamping">1210</p>
|
|
<p class="text-lg font-bold text-green-700" id="percenlPjlpPendamping">Pendamping</p>
|
|
</div>
|
|
</div>
|
|
<div class="border border-gray-400 rounded-lg p-4">
|
|
<p class="text-md text-gray-800 mb-2">PJLP Pendamping yang sudah melakukan Ceklis</p>
|
|
<div class="flex flex-row items-center gap-2">
|
|
<p class="text-3xl font-bold text-primary-500" id="sudahCeklisCount">605</p>
|
|
<p class="text-lg font-bold text-green-700" id="sudahCeklisPercent">Pendamping (50%)</p>
|
|
</div>
|
|
</div>
|
|
<div class="border border-gray-400 rounded-lg p-4">
|
|
<p class="text-md text-gray-800 mb-2">PJLP Pendamping yang belum melakukan Ceklis</p>
|
|
<div class="flex flex-row items-center gap-2">
|
|
<p class="text-3xl font-bold text-primary-500" id="belumCeklisCount">605</p>
|
|
<p class="text-lg font-bold text-green-700" id="belumCeklisPercent">Pendamping (50%)</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Filter Modal -->
|
|
<dialog id="modal_filter" class="modal modal-bottom sm:modal-middle">
|
|
<div class="modal-box w-full sm:max-w-sm">
|
|
<div class="flex items-center justify-between mb-4">
|
|
<h3 class="text-lg font-bold">Filter</h3>
|
|
<button type="button" class="btn btn-sm btn-circle btn-ghost" onclick="modal_filter.close()">✕</button>
|
|
</div>
|
|
<form id="filterForm" action="#" method="get">
|
|
<fieldset class="fieldset mb-4">
|
|
<legend class="fieldset-legend">Wilayah</legend>
|
|
<select id="wilayahFilter" class="input w-full" name="wilayah">
|
|
<option value="Jakarta Pusat">Jakarta Pusat</option>
|
|
<option value="Jakarta Utara">Jakarta Utara</option>
|
|
<option value="Jakarta Barat" selected>Jakarta Barat</option>
|
|
<option value="Jakarta Timur">Jakarta Timur</option>
|
|
<option value="Jakarta Selatan">Jakarta Selatan</option>
|
|
<option value="Kepulauan Seribu">Kepulauan Seribu</option>
|
|
</select>
|
|
</fieldset>
|
|
<div class="grid grid-cols-2 gap-4">
|
|
<fieldset class="fieldset">
|
|
<legend class="fieldset-legend">Bulan Awal</legend>
|
|
<input type="month" id="bulanAwal" class="input w-full" name="bulanAwal" placeholder="Pilih bulan"
|
|
min="2020-01" required>
|
|
</fieldset>
|
|
<fieldset class="fieldset">
|
|
<legend class="fieldset-legend">Bulan Akhir</legend>
|
|
<input type="month" id="bulanAkhir" class="input w-full" name="bulanAkhir" placeholder="Pilih bulan"
|
|
required>
|
|
</fieldset>
|
|
</div>
|
|
<div id="errorMessage" class="text-red-500 text-sm mt-2 hidden"></div>
|
|
<div class="modal-action">
|
|
<button type="button" class="btn" onclick="clearFilter()">Bersihkan</button>
|
|
<button type="submit" class="btn btn-neutral">Terapkan Filter</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</dialog>
|
|
|
|
<script src="/lib/chart.js/chart.umd.js"></script>
|
|
<script src="/lib/chartjs-plugin-annotation/chartjs-plugin-annotation.min.js"></script>
|
|
<script src="/lib/chartjs-plugin-datalabels/chartjs-plugin-datalabels.min.js"></script>
|
|
<script>
|
|
Chart.register(ChartDataLabels);
|
|
|
|
Chart.defaults.animation = { duration: 500, easing: 'easeOutQuart' };
|
|
Chart.defaults.animations = {
|
|
numbers: { duration: 500, easing: 'easeOutQuart' },
|
|
colors: { duration: 500, easing: 'easeOutQuart' }
|
|
};
|
|
|
|
let chartInstances = {
|
|
tingkatKepatuhan: null,
|
|
statusSatpel: null,
|
|
statusSudin: null,
|
|
capaianRumah: null,
|
|
volumeSampah: null,
|
|
realisasi: null,
|
|
kepatuhanPeriode: null
|
|
};
|
|
|
|
function updateCharts(data) {
|
|
// Destroy existing charts
|
|
Object.keys(chartInstances).forEach(key => {
|
|
if (key !== 'kepatuhanPeriode' && chartInstances[key]) {
|
|
chartInstances[key].destroy();
|
|
}
|
|
});
|
|
|
|
// Update dynamic height for chartTingkatKepatuhan and chartVolumeSampah
|
|
if (data.countMonthLabels) {
|
|
const baseHeight = 320;
|
|
let dynamicHeight = baseHeight;
|
|
|
|
if (window.innerWidth >= 768) {
|
|
const additionalHeight = 70 + ((data.countMonthLabels - 2) * 23);
|
|
dynamicHeight = baseHeight + additionalHeight;
|
|
}
|
|
|
|
const containerTingkatKepatuhan = document.getElementById('chartTingkatKepatuhanContainer');
|
|
containerTingkatKepatuhan.style.minHeight = `${dynamicHeight}px`;
|
|
|
|
const containerVolumeSampah = document.getElementById('chartVolumeSampahContainer');
|
|
containerVolumeSampah.style.minHeight = `${dynamicHeight}px`;
|
|
}
|
|
|
|
renderCharts(data);
|
|
}
|
|
|
|
function updateKepatuhanPeriodeChart(data) {
|
|
// Destroy chart
|
|
if (chartInstances.kepatuhanPeriode) {
|
|
chartInstances.kepatuhanPeriode.destroy();
|
|
}
|
|
|
|
renderKepatuhanPeriodeChart(data);
|
|
}
|
|
|
|
function renderCharts(data) {
|
|
if (!data) {
|
|
console.error('No data provided to renderCharts');
|
|
return;
|
|
}
|
|
|
|
const periode = data.periode;
|
|
|
|
// Update filter
|
|
if (data.bulanAwal) document.getElementById('bulanAwal').value = data.bulanAwal;
|
|
if (data.bulanAkhir) document.getElementById('bulanAkhir').value = data.bulanAkhir;
|
|
if (data.wilayah) document.getElementById('wilayahFilter').value = data.wilayah;
|
|
|
|
// Update descriptions
|
|
document.getElementById('descTingkatKepatuhan').textContent = `Tingkat Kepatuhan PJLP Periode ${periode}`;
|
|
document.getElementById('descStatusSatpel').textContent = `Status Validasi SATPEL Periode ${periode}`;
|
|
document.getElementById('descStatusSudin').textContent = `Status Validasi SUDIN Periode ${periode}`;
|
|
document.getElementById('descCapaianRumah').textContent = `Capaian Rumah Memilah Periode ${periode}`;
|
|
document.getElementById('descVolumeSampah').textContent = `Volume Timbulan Sampah Per Hari Per Jiwa Dalam Satu Bulan ${periode}`;
|
|
document.getElementById('descRealisasi').textContent = `Laporan Program Realisasi dan Realisasi Terhadap Target ${periode}`;
|
|
|
|
// Chart Kepatuhan PJLP
|
|
const kepatuhanAnnotations = {};
|
|
|
|
// linear trend
|
|
if (data.tingkatKepatuhanPjlp && data.tingkatKepatuhanPjlp.length > 1) {
|
|
const numBars = 2;
|
|
const categoryPercentage = 0.8;
|
|
const barWidth = categoryPercentage / numBars;
|
|
const offsetCeklis = -barWidth / 2;
|
|
const offsetBelumCeklis = barWidth / 2;
|
|
|
|
data.tingkatKepatuhanPjlp.forEach((item, idx) => {
|
|
if (idx < data.tingkatKepatuhanPjlp.length - 1) {
|
|
kepatuhanAnnotations[`lineCeklis${idx}`] = {
|
|
type: 'line',
|
|
xMin: idx + offsetCeklis,
|
|
xMax: idx + 1 + offsetCeklis,
|
|
yMin: data.tingkatKepatuhanPjlp[idx].ceklis,
|
|
yMax: data.tingkatKepatuhanPjlp[idx + 1].ceklis,
|
|
borderColor: '#84CC16',
|
|
borderWidth: 2,
|
|
borderDash: [5, 5]
|
|
};
|
|
|
|
kepatuhanAnnotations[`lineBelumCeklis${idx}`] = {
|
|
type: 'line',
|
|
xMin: idx + offsetBelumCeklis,
|
|
xMax: idx + 1 + offsetBelumCeklis,
|
|
yMin: data.tingkatKepatuhanPjlp[idx].belumCeklis,
|
|
yMax: data.tingkatKepatuhanPjlp[idx + 1].belumCeklis,
|
|
borderColor: '#EF4444',
|
|
borderWidth: 2,
|
|
borderDash: [5, 5]
|
|
};
|
|
}
|
|
});
|
|
}
|
|
|
|
chartInstances.tingkatKepatuhan = new Chart(document.getElementById('chartTingkatKepatuhan'), {
|
|
type: 'bar',
|
|
data: {
|
|
labels: data.tingkatKepatuhanPjlp.map(x => x.bulan),
|
|
datasets: [
|
|
{
|
|
label: 'Ceklis',
|
|
data: data.tingkatKepatuhanPjlp.map(x => x.ceklis),
|
|
backgroundColor: '#12B76A',
|
|
barPercentage: 0.9,
|
|
categoryPercentage: 0.8
|
|
},
|
|
{
|
|
label: 'Belum Ceklis',
|
|
data: data.tingkatKepatuhanPjlp.map(x => x.belumCeklis),
|
|
backgroundColor: '#F04438',
|
|
barPercentage: 0.9,
|
|
categoryPercentage: 0.8
|
|
}
|
|
]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
interaction: { mode: 'index', intersect: false },
|
|
layout: {
|
|
padding: {
|
|
top: 20
|
|
}
|
|
},
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true,
|
|
grace: '5%',
|
|
grid: { color: '#E5E7EB' }
|
|
},
|
|
x: {
|
|
grid: { offset: false }
|
|
}
|
|
},
|
|
plugins: {
|
|
legend: {
|
|
position: 'bottom',
|
|
labels: {
|
|
usePointStyle: true,
|
|
pointStyle: "circle",
|
|
padding: 15,
|
|
generateLabels: (chart) => {
|
|
const original = Chart.defaults.plugins.legend.labels.generateLabels(chart);
|
|
if (data.tingkatKepatuhanPjlp && data.tingkatKepatuhanPjlp.length > 1) {
|
|
original.push(
|
|
{
|
|
text: 'Linear Ceklis',
|
|
fillStyle: 'transparent',
|
|
strokeStyle: '#84CC16',
|
|
lineWidth: 2,
|
|
lineDash: [5, 5],
|
|
pointStyle: 'line'
|
|
},
|
|
{
|
|
text: 'Linear Belum Ceklis',
|
|
fillStyle: 'transparent',
|
|
strokeStyle: '#EF4444',
|
|
lineWidth: 2,
|
|
lineDash: [5, 5],
|
|
pointStyle: 'line'
|
|
}
|
|
);
|
|
}
|
|
return original;
|
|
}
|
|
}
|
|
},
|
|
datalabels: {
|
|
anchor: 'end',
|
|
align: 'top',
|
|
color: '#444',
|
|
font: { size: 10, weight: 'bold' }
|
|
},
|
|
annotation: {
|
|
annotations: kepatuhanAnnotations
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Chart Status Validasi SATPEL
|
|
const satpelAnnotations = {};
|
|
|
|
// linear trend
|
|
if (data.statusValidasiSatpel && data.statusValidasiSatpel.length > 1) {
|
|
const numBars = 2;
|
|
const categoryPercentage = 0.8;
|
|
const barWidth = categoryPercentage / numBars;
|
|
const offsetSudah = -barWidth / 2;
|
|
|
|
data.statusValidasiSatpel.forEach((item, idx) => {
|
|
if (idx < data.statusValidasiSatpel.length - 1) {
|
|
satpelAnnotations[`lineSudah${idx}`] = {
|
|
type: 'line',
|
|
xMin: idx + offsetSudah,
|
|
xMax: idx + 1 + offsetSudah,
|
|
yMin: data.statusValidasiSatpel[idx].sudah,
|
|
yMax: data.statusValidasiSatpel[idx + 1].sudah,
|
|
borderColor: '#84CC16',
|
|
borderWidth: 2,
|
|
borderDash: [5, 5]
|
|
};
|
|
}
|
|
});
|
|
}
|
|
|
|
chartInstances.statusSatpel = new Chart(document.getElementById('chartStatusSatpel'), {
|
|
type: 'bar',
|
|
data: {
|
|
labels: data.statusValidasiSatpel.map(x => x.bulan),
|
|
datasets: [
|
|
{
|
|
label: 'Sudah',
|
|
data: data.statusValidasiSatpel.map(x => x.sudah),
|
|
backgroundColor: '#12B76A',
|
|
barPercentage: 0.9,
|
|
categoryPercentage: 0.8
|
|
},
|
|
{
|
|
label: 'Belum',
|
|
data: data.statusValidasiSatpel.map(x => x.belum),
|
|
backgroundColor: '#F04438',
|
|
barPercentage: 0.9,
|
|
categoryPercentage: 0.8
|
|
}
|
|
]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
interaction: { mode: 'index', intersect: false },
|
|
layout: {
|
|
padding: {
|
|
top: 20
|
|
}
|
|
},
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true,
|
|
grace: '5%',
|
|
grid: { color: '#E5E7EB' }
|
|
},
|
|
x: {
|
|
grid: { offset: false }
|
|
}
|
|
},
|
|
plugins: {
|
|
legend: {
|
|
position: 'bottom',
|
|
labels: {
|
|
usePointStyle: true,
|
|
pointStyle: "circle",
|
|
padding: 15,
|
|
generateLabels: (chart) => {
|
|
const original = Chart.defaults.plugins.legend.labels.generateLabels(chart);
|
|
if (data.statusValidasiSatpel && data.statusValidasiSatpel.length > 1) {
|
|
original.push({
|
|
text: 'Linear Sudah',
|
|
fillStyle: 'transparent',
|
|
strokeStyle: '#12B76A',
|
|
lineWidth: 2,
|
|
lineDash: [5, 5],
|
|
pointStyle: 'line'
|
|
});
|
|
}
|
|
return original;
|
|
}
|
|
}
|
|
},
|
|
datalabels: {
|
|
anchor: 'end',
|
|
align: 'top',
|
|
color: '#444',
|
|
font: { size: 10, weight: 'bold' }
|
|
},
|
|
annotation: {
|
|
annotations: satpelAnnotations
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Chart Status Validasi SUDIN
|
|
const sudinAnnotations = {};
|
|
|
|
// linear trend
|
|
if (data.statusValidasiSudin && data.statusValidasiSudin.length > 1) {
|
|
const numBars = 2;
|
|
const categoryPercentage = 0.8;
|
|
const barWidth = categoryPercentage / numBars;
|
|
const offsetSudah = -barWidth / 2;
|
|
|
|
data.statusValidasiSudin.forEach((item, idx) => {
|
|
if (idx < data.statusValidasiSudin.length - 1) {
|
|
sudinAnnotations[`lineSudah${idx}`] = {
|
|
type: 'line',
|
|
xMin: idx + offsetSudah,
|
|
xMax: idx + 1 + offsetSudah,
|
|
yMin: data.statusValidasiSudin[idx].sudah,
|
|
yMax: data.statusValidasiSudin[idx + 1].sudah,
|
|
borderColor: '#84CC16',
|
|
borderWidth: 2,
|
|
borderDash: [5, 5]
|
|
};
|
|
}
|
|
});
|
|
}
|
|
|
|
chartInstances.statusSudin = new Chart(document.getElementById('chartStatusSudin'), {
|
|
type: 'bar',
|
|
data: {
|
|
labels: data.statusValidasiSudin.map(x => x.bulan),
|
|
datasets: [
|
|
{
|
|
label: 'Sudah',
|
|
data: data.statusValidasiSudin.map(x => x.sudah),
|
|
backgroundColor: '#84CC16',
|
|
barPercentage: 0.9,
|
|
categoryPercentage: 0.8
|
|
},
|
|
{
|
|
label: 'Belum',
|
|
data: data.statusValidasiSudin.map(x => x.belum),
|
|
backgroundColor: '#FB923C',
|
|
barPercentage: 0.9,
|
|
categoryPercentage: 0.8
|
|
}
|
|
]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
interaction: { mode: 'index', intersect: false },
|
|
layout: {
|
|
padding: {
|
|
top: 20
|
|
}
|
|
},
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true,
|
|
grace: '5%',
|
|
grid: { color: '#E5E7EB' }
|
|
},
|
|
x: {
|
|
grid: { offset: false }
|
|
}
|
|
},
|
|
plugins: {
|
|
legend: {
|
|
position: 'bottom',
|
|
labels: {
|
|
usePointStyle: true,
|
|
pointStyle: "circle",
|
|
padding: 15,
|
|
generateLabels: (chart) => {
|
|
const original = Chart.defaults.plugins.legend.labels.generateLabels(chart);
|
|
if (data.statusValidasiSudin && data.statusValidasiSudin.length > 1) {
|
|
original.push({
|
|
text: 'Linear Sudah',
|
|
fillStyle: 'transparent',
|
|
strokeStyle: '#84CC16',
|
|
lineWidth: 2,
|
|
lineDash: [5, 5],
|
|
pointStyle: 'line'
|
|
});
|
|
}
|
|
return original;
|
|
}
|
|
}
|
|
},
|
|
datalabels: {
|
|
anchor: 'end',
|
|
align: 'top',
|
|
color: '#444',
|
|
font: { size: 10, weight: 'bold' }
|
|
},
|
|
annotation: {
|
|
annotations: sudinAnnotations
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Chart Capaian Rumah Memilah
|
|
const capaianAnnotations = {};
|
|
|
|
// linear trend
|
|
if (data.capaianRumahMemilah && data.capaianRumahMemilah.length > 1) {
|
|
const numBars = 2;
|
|
const categoryPercentage = 0.8;
|
|
const barWidth = categoryPercentage / numBars;
|
|
const offsetKonsisten = -barWidth / 2;
|
|
const offsetTidakKonsisten = barWidth / 2;
|
|
|
|
data.capaianRumahMemilah.forEach((item, idx) => {
|
|
if (idx < data.capaianRumahMemilah.length - 1) {
|
|
capaianAnnotations[`lineKonsisten${idx}`] = {
|
|
type: 'line',
|
|
xMin: idx + offsetKonsisten,
|
|
xMax: idx + 1 + offsetKonsisten,
|
|
yMin: data.capaianRumahMemilah[idx].konsisten,
|
|
yMax: data.capaianRumahMemilah[idx + 1].konsisten,
|
|
borderColor: '#84CC16',
|
|
borderWidth: 2,
|
|
borderDash: [5, 5]
|
|
};
|
|
|
|
capaianAnnotations[`lineTidakKonsisten${idx}`] = {
|
|
type: 'line',
|
|
xMin: idx + offsetTidakKonsisten,
|
|
xMax: idx + 1 + offsetTidakKonsisten,
|
|
yMin: data.capaianRumahMemilah[idx].tidakKonsisten,
|
|
yMax: data.capaianRumahMemilah[idx + 1].tidakKonsisten,
|
|
borderColor: '#FB923C',
|
|
borderWidth: 2,
|
|
borderDash: [5, 5]
|
|
};
|
|
}
|
|
});
|
|
}
|
|
|
|
chartInstances.capaianRumah = new Chart(document.getElementById('chartCapaianRumah'), {
|
|
type: 'bar',
|
|
data: {
|
|
labels: data.capaianRumahMemilah.map(x => x.bulan),
|
|
datasets: [
|
|
{
|
|
label: 'Rumah Memilah Konsisten',
|
|
data: data.capaianRumahMemilah.map(x => x.konsisten),
|
|
backgroundColor: '#84CC16',
|
|
barPercentage: 0.9,
|
|
categoryPercentage: 0.8
|
|
},
|
|
{
|
|
label: 'Rumah Memilah Tidak Konsisten',
|
|
data: data.capaianRumahMemilah.map(x => x.tidakKonsisten),
|
|
backgroundColor: '#FB923C',
|
|
barPercentage: 0.9,
|
|
categoryPercentage: 0.8
|
|
},
|
|
]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
interaction: { mode: 'index', intersect: false },
|
|
layout: {
|
|
padding: {
|
|
top: 20
|
|
}
|
|
},
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true,
|
|
grace: '5%',
|
|
grid: { color: '#E5E7EB' }
|
|
},
|
|
x: {
|
|
grid: { offset: false }
|
|
}
|
|
},
|
|
plugins: {
|
|
legend: {
|
|
position: 'bottom',
|
|
labels: {
|
|
usePointStyle: true,
|
|
pointStyle: "circle",
|
|
padding: 15,
|
|
generateLabels: (chart) => {
|
|
const original = Chart.defaults.plugins.legend.labels.generateLabels(chart);
|
|
if (data.capaianRumahMemilah && data.capaianRumahMemilah.length > 1) {
|
|
original.push(
|
|
{
|
|
text: 'Linear Rumah Memilah Konsisten',
|
|
fillStyle: 'transparent',
|
|
strokeStyle: '#84CC16',
|
|
lineWidth: 2,
|
|
lineDash: [5, 5],
|
|
pointStyle: 'line'
|
|
},
|
|
{
|
|
text: 'Linear Rumah Memilah Tidak Konsisten',
|
|
fillStyle: 'transparent',
|
|
strokeStyle: '#FB923C',
|
|
lineWidth: 2,
|
|
lineDash: [5, 5],
|
|
pointStyle: 'line'
|
|
}
|
|
);
|
|
}
|
|
return original;
|
|
}
|
|
}
|
|
},
|
|
datalabels: {
|
|
anchor: 'end',
|
|
align: 'top',
|
|
color: '#444',
|
|
font: { size: 10, weight: 'bold' }
|
|
},
|
|
annotation: {
|
|
annotations: capaianAnnotations
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Chart Volume Timbulan Sampah
|
|
const volumeAnnotations = {};
|
|
|
|
// linear trend untuk Mudah Terurai
|
|
if (data.volumeTimbulanSampah && data.volumeTimbulanSampah.length > 1) {
|
|
const numBars = 2;
|
|
const categoryPercentage = 0.8;
|
|
const barWidth = categoryPercentage / numBars;
|
|
const offsetTerurai = -barWidth / 2;
|
|
|
|
data.volumeTimbulanSampah.forEach((item, idx) => {
|
|
if (idx < data.volumeTimbulanSampah.length - 1) {
|
|
volumeAnnotations[`lineTerurai${idx}`] = {
|
|
type: 'line',
|
|
xMin: idx + offsetTerurai,
|
|
xMax: idx + 1 + offsetTerurai,
|
|
yMin: data.volumeTimbulanSampah[idx].terurai,
|
|
yMax: data.volumeTimbulanSampah[idx + 1].terurai,
|
|
borderColor: '#84CC16',
|
|
borderWidth: 2,
|
|
borderDash: [5, 5]
|
|
};
|
|
}
|
|
});
|
|
}
|
|
|
|
chartInstances.volumeSampah = new Chart(document.getElementById('chartVolumeSampah'), {
|
|
type: 'bar',
|
|
data: {
|
|
labels: data.volumeTimbulanSampah.map(x => x.bulan),
|
|
datasets: [
|
|
{
|
|
label: 'Mudah Terurai',
|
|
data: data.volumeTimbulanSampah.map(x => x.terurai),
|
|
backgroundColor: '#84CC16',
|
|
barPercentage: 0.9,
|
|
categoryPercentage: 0.8
|
|
},
|
|
{
|
|
label: 'Tidak Mudah Terurai',
|
|
data: data.volumeTimbulanSampah.map(x => x.tidakTerurai),
|
|
backgroundColor: '#FB923C',
|
|
barPercentage: 0.9,
|
|
categoryPercentage: 0.8
|
|
},
|
|
]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
interaction: { mode: 'index', intersect: false },
|
|
layout: {
|
|
padding: {
|
|
top: 20
|
|
}
|
|
},
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true,
|
|
grace: '5%',
|
|
grid: { color: '#E5E7EB' },
|
|
ticks: {
|
|
callback: function (value) {
|
|
return value.toFixed(2) + ' kg';
|
|
}
|
|
}
|
|
},
|
|
x: {
|
|
grid: { offset: false }
|
|
}
|
|
},
|
|
plugins: {
|
|
legend: {
|
|
position: 'bottom',
|
|
labels: {
|
|
usePointStyle: true,
|
|
pointStyle: "circle",
|
|
padding: 15,
|
|
generateLabels: (chart) => {
|
|
const original = Chart.defaults.plugins.legend.labels.generateLabels(chart);
|
|
if (data.volumeTimbulanSampah && data.volumeTimbulanSampah.length > 1) {
|
|
original.push({
|
|
text: 'Linear Mudah Terurai',
|
|
fillStyle: 'transparent',
|
|
strokeStyle: '#84CC16',
|
|
lineWidth: 2,
|
|
lineDash: [5, 5],
|
|
pointStyle: 'line'
|
|
});
|
|
}
|
|
return original;
|
|
}
|
|
}
|
|
},
|
|
datalabels: {
|
|
anchor: 'end',
|
|
align: 'top',
|
|
color: '#444',
|
|
font: { size: 10, weight: 'bold' },
|
|
formatter: (value) => value.toFixed(2)
|
|
},
|
|
annotation: {
|
|
annotations: volumeAnnotations
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Chart Realisasi Terhadap Target
|
|
const realisasiAnnotations = {};
|
|
|
|
// linear trend
|
|
if (data.realisasiTarget && data.realisasiTarget.length > 1) {
|
|
const numBars = 3;
|
|
const categoryPercentage = 0.8;
|
|
const barWidth = categoryPercentage / numBars;
|
|
const offsetKonsisten = -barWidth;
|
|
const offsetTidakKonsisten = 0;
|
|
|
|
data.realisasiTarget.forEach((item, idx) => {
|
|
if (idx < data.realisasiTarget.length - 1) {
|
|
realisasiAnnotations[`lineKonsisten${idx}`] = {
|
|
type: 'line',
|
|
xMin: idx + offsetKonsisten,
|
|
xMax: idx + 1 + offsetKonsisten,
|
|
yMin: data.realisasiTarget[idx].rmKonsisten,
|
|
yMax: data.realisasiTarget[idx + 1].rmKonsisten,
|
|
borderColor: '#84CC16',
|
|
borderWidth: 2,
|
|
borderDash: [5, 5]
|
|
};
|
|
|
|
realisasiAnnotations[`lineTidakKonsisten${idx}`] = {
|
|
type: 'line',
|
|
xMin: idx + offsetTidakKonsisten,
|
|
xMax: idx + 1 + offsetTidakKonsisten,
|
|
yMin: data.realisasiTarget[idx].rmTidakKonsisten,
|
|
yMax: data.realisasiTarget[idx + 1].rmTidakKonsisten,
|
|
borderColor: '#F97316',
|
|
borderWidth: 2,
|
|
borderDash: [5, 5]
|
|
};
|
|
}
|
|
});
|
|
}
|
|
|
|
chartInstances.realisasi = new Chart(document.getElementById('chartRealisasi'), {
|
|
type: 'bar',
|
|
data: {
|
|
labels: data.realisasiTarget.map(x => x.bulan),
|
|
datasets: [
|
|
{
|
|
label: 'Rumah Memilah Konsisten',
|
|
data: data.realisasiTarget.map(x => x.rmKonsisten),
|
|
backgroundColor: '#84CC16',
|
|
barPercentage: 0.9,
|
|
categoryPercentage: 0.8
|
|
},
|
|
{
|
|
label: 'Rumah Memilah Tidak Konsisten',
|
|
data: data.realisasiTarget.map(x => x.rmTidakKonsisten),
|
|
backgroundColor: '#F97316',
|
|
barPercentage: 0.9,
|
|
categoryPercentage: 0.8
|
|
},
|
|
{
|
|
label: 'Target',
|
|
data: data.realisasiTarget.map(x => x.target),
|
|
backgroundColor: '#C6C6C6',
|
|
barPercentage: 0.9,
|
|
categoryPercentage: 0.8
|
|
}
|
|
]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
interaction: { mode: 'index', intersect: false },
|
|
layout: {
|
|
padding: {
|
|
top: 20
|
|
}
|
|
},
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true,
|
|
grace: '5%',
|
|
grid: { color: '#E5E7EB' }
|
|
},
|
|
x: {
|
|
grid: { offset: false }
|
|
}
|
|
},
|
|
plugins: {
|
|
legend: {
|
|
position: 'bottom',
|
|
labels: {
|
|
usePointStyle: true,
|
|
pointStyle: "circle",
|
|
padding: 15,
|
|
generateLabels: (chart) => {
|
|
const original = Chart.defaults.plugins.legend.labels.generateLabels(chart);
|
|
if (data.realisasiTarget && data.realisasiTarget.length > 1) {
|
|
original.push(
|
|
{
|
|
text: 'Linear Rumah Memilah Konsisten',
|
|
fillStyle: 'transparent',
|
|
strokeStyle: '#84CC16',
|
|
lineWidth: 2,
|
|
lineDash: [5, 5],
|
|
pointStyle: 'line'
|
|
},
|
|
{
|
|
text: 'Linear Rumah Memilah Tidak Konsisten',
|
|
fillStyle: 'transparent',
|
|
strokeStyle: '#F97316',
|
|
lineWidth: 2,
|
|
lineDash: [5, 5],
|
|
pointStyle: 'line'
|
|
}
|
|
);
|
|
}
|
|
return original;
|
|
}
|
|
}
|
|
},
|
|
datalabels: {
|
|
anchor: 'end',
|
|
align: 'top',
|
|
color: '#444',
|
|
font: { size: 10, weight: 'bold' }
|
|
},
|
|
annotation: {
|
|
annotations: realisasiAnnotations
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
|
|
|
|
// Update Capaian Rumah Memilah Text
|
|
if (data.tingkatKepatuhanPjlp) {
|
|
const capaianRumahTextContainer = document.getElementById('capaianRumahText');
|
|
capaianRumahTextContainer.innerHTML = '';
|
|
|
|
data.tingkatKepatuhanPjlp.forEach((item, index) => {
|
|
const p = document.createElement('p');
|
|
if (item.belumCeklis === 0) {
|
|
p.textContent = `${index + 1}. Periode ${item.bulan} sebanyak ${item.ceklis} PJLP sudah menjalankan program.`;
|
|
} else {
|
|
p.textContent = `${index + 1}. Periode ${item.bulan} sebanyak ${item.ceklis} PJLP sudah menjalankan program, dan yang belum menjalankan program sebanyak ${item.belumCeklis} orang.`;
|
|
}
|
|
capaianRumahTextContainer.appendChild(p);
|
|
});
|
|
}
|
|
|
|
// Update SATPEL Validation Text
|
|
if (data.statusValidasiSatpel) {
|
|
const satpelTextContainer = document.getElementById('satpelValidationText');
|
|
satpelTextContainer.innerHTML = '';
|
|
|
|
data.statusValidasiSatpel.forEach((item, index) => {
|
|
const p = document.createElement('p');
|
|
if (item.belum === 0) {
|
|
p.textContent = `${index + 1}. Periode bulan ${item.bulan} sudah tervalidasi semua.`;
|
|
} else {
|
|
p.textContent = `${index + 1}. Periode bulan ${item.bulan} terdapat ${item.belum} belum tervalidasi.`;
|
|
}
|
|
satpelTextContainer.appendChild(p);
|
|
});
|
|
}
|
|
|
|
// Update SUDIN Validation Text
|
|
if (data.statusValidasiSudin) {
|
|
const sudinTextContainer = document.getElementById('sudinValidationText');
|
|
sudinTextContainer.innerHTML = '';
|
|
|
|
data.statusValidasiSudin.forEach((item, index) => {
|
|
const p = document.createElement('p');
|
|
if (item.belum === 0) {
|
|
p.textContent = `${index + 1}. Periode bulan ${item.bulan} sudah tervalidasi semua.`;
|
|
} else {
|
|
p.textContent = `${index + 1}. Periode bulan ${item.bulan} terdapat ${item.belum} aktifitas ceklis yang tidak tervalidasi (terlewat/diragukan kebenaran ceklis).`;
|
|
}
|
|
sudinTextContainer.appendChild(p);
|
|
});
|
|
}
|
|
|
|
// Update Volume Sampah Text
|
|
if (data.volumeSampahInfo) {
|
|
const volumeText = `Terhadap total volume timbulan sampah organik hasil pilahan ${data.volumeSampahInfo.jumlahRumah} rumah tangga memilah secara konsisten periode ${data.volumeSampahInfo.periode} sebanyak ${data.volumeSampahInfo.totalVolume} Kg.`;
|
|
document.getElementById('volumeSampahText').textContent = volumeText;
|
|
}
|
|
|
|
// Update Realisasi Target Text
|
|
if (data.realisasiTarget) {
|
|
const realisasiTextContainer = document.getElementById('realisasiTargetText');
|
|
realisasiTextContainer.innerHTML = '';
|
|
|
|
data.realisasiTarget.forEach((item, index) => {
|
|
const p = document.createElement('p');
|
|
const selisih = item.target - item.realisasi;
|
|
|
|
if (selisih > 0) {
|
|
p.textContent = `${index + 1}. Bulan ${item.bulan} dari target ${item.target} rumah tangga memilah konsisten, baru terbentuk ${item.realisasi} rumah tangga konsisten melakukan pemilahan, sehingga realisasi terhadap target masih kurang ${selisih} rumah tangga.`;
|
|
} else if (selisih < 0) {
|
|
p.textContent = `${index + 1}. Bulan ${item.bulan} dari target ${item.target} rumah tangga memilah konsisten, baru terbentuk ${item.realisasi} rumah tangga konsisten melakukan pemilahan, sehingga realisasi terhadap target sudah melewati target yaitu ${Math.abs(selisih)} rumah tangga.`;
|
|
} else {
|
|
p.textContent = `${index + 1}. Bulan ${item.bulan} dari target ${item.target} rumah tangga memilah konsisten, baru terbentuk ${item.realisasi} rumah tangga konsisten melakukan pemilahan, sehingga realisasi terhadap target sudah tercapai.`;
|
|
}
|
|
realisasiTextContainer.appendChild(p);
|
|
});
|
|
}
|
|
}
|
|
|
|
function renderKepatuhanPeriodeChart(data) {
|
|
if (!data || !data.tingkatKepatuhanPeriode) {
|
|
console.error('No data provided to renderKepatuhanPeriodeChart');
|
|
return;
|
|
}
|
|
|
|
// Update descriptions
|
|
document.getElementById('subtitleKepatuhanPeriode').textContent = `Tingkat Kepatuhan PJLP Periode ${data.periode}`;
|
|
document.getElementById('locationKepatuhanPeriode').textContent = data.locationText;
|
|
|
|
// Chart Tingkat Kepatuhan PJLP Periode
|
|
chartInstances.kepatuhanPeriode = new Chart(document.getElementById('chartKepatuhanPeriode'), {
|
|
type: 'bar',
|
|
data: {
|
|
labels: data.tingkatKepatuhanPeriode.map(x => x.wilayah),
|
|
datasets: [
|
|
{
|
|
label: 'Ceklis',
|
|
data: data.tingkatKepatuhanPeriode.map(x => x.ceklis),
|
|
backgroundColor: '#84CC16'
|
|
},
|
|
{
|
|
label: 'Belum Ceklis',
|
|
data: data.tingkatKepatuhanPeriode.map(x => x.belumCeklis),
|
|
backgroundColor: '#FB923C'
|
|
},
|
|
{
|
|
label: 'Total PJLP',
|
|
data: data.tingkatKepatuhanPeriode.map(x => x.total),
|
|
backgroundColor: '#98A2B3'
|
|
},
|
|
]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
layout: {
|
|
padding: {
|
|
top: 20
|
|
}
|
|
},
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true,
|
|
grace: '5%',
|
|
grid: { color: '#E5E7EB' }
|
|
},
|
|
x: {
|
|
grid: { display: false }
|
|
}
|
|
},
|
|
plugins: {
|
|
legend: {
|
|
position: 'bottom',
|
|
labels: {
|
|
usePointStyle: true,
|
|
pointStyle: "circle",
|
|
padding: 15
|
|
}
|
|
},
|
|
datalabels: {
|
|
display: true,
|
|
anchor: 'end',
|
|
align: 'top',
|
|
color: '#444',
|
|
font: { size: 10, weight: 'bold' }
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Update PJLP Stats Cards
|
|
if (data.pjlpStats) {
|
|
document.getElementById('totalPjlpPendamping').textContent = data.pjlpStats.total;
|
|
document.getElementById('percenlPjlpPendamping').textContent = 'Pendamping';
|
|
|
|
document.getElementById('sudahCeklisCount').textContent = data.pjlpStats.sudahCeklis;
|
|
document.getElementById('sudahCeklisPercent').textContent = `Pendamping (${data.pjlpStats.persentaseSudah}%)`;
|
|
|
|
document.getElementById('belumCeklisCount').textContent = data.pjlpStats.belumCeklis;
|
|
document.getElementById('belumCeklisPercent').textContent = `Pendamping (${data.pjlpStats.persentaseBelum}%)`;
|
|
}
|
|
}
|
|
|
|
const getCurrentMonth = () => new Date().toISOString().slice(0, 7);
|
|
|
|
const getDefaultDateRange = () => {
|
|
const today = new Date();
|
|
const year = today.getFullYear();
|
|
const month = today.getMonth();
|
|
|
|
const startMonth = month - 2;
|
|
const startYear = startMonth < 0 ? year - 1 : year;
|
|
const adjustedStartMonth = startMonth < 0 ? startMonth + 12 : startMonth;
|
|
|
|
const endYear = year;
|
|
const endMonth = month;
|
|
|
|
const start = `${startYear}-${String(adjustedStartMonth + 1).padStart(2, '0')}`;
|
|
const end = `${endYear}-${String(endMonth + 1).padStart(2, '0')}`;
|
|
|
|
return { start, end };
|
|
};
|
|
|
|
const getErrorMsg = () => document.getElementById('errorMessage');
|
|
const getBulanAwalInput = () => document.getElementById('bulanAwal');
|
|
const getBulanAkhirInput = () => document.getElementById('bulanAkhir');
|
|
const getWilayahInput = () => document.getElementById('wilayahFilter');
|
|
|
|
function loadDataByDateRange(startDate, endDate, wilayah) {
|
|
const params = new URLSearchParams();
|
|
if (startDate) params.append('bulanAwal', startDate);
|
|
if (endDate) params.append('bulanAkhir', endDate);
|
|
if (wilayah) params.append('wilayah', wilayah);
|
|
|
|
fetch(`/LaporanCapaianWilayah/GetData?${params.toString()}`, {
|
|
headers: { 'Accept': 'application/json' }
|
|
})
|
|
.then(res => {
|
|
if (!res.ok) {
|
|
throw new Error(`HTTP error! status: ${res.status}`);
|
|
}
|
|
return res.json();
|
|
})
|
|
.then(data => {
|
|
console.log('Data received:', data);
|
|
if (!data || !data.tingkatKepatuhanPjlp) {
|
|
console.error('Invalid data structure:', data);
|
|
return;
|
|
}
|
|
updateCharts(data);
|
|
updateLocationTexts(data.locationText);
|
|
})
|
|
.catch(err => console.error('Gagal memuat data:', err));
|
|
}
|
|
|
|
function loadDataKepatuhanPeriode(bulan, wilayah) {
|
|
const params = new URLSearchParams();
|
|
if (bulan) params.append('bulan', bulan);
|
|
if (wilayah) params.append('wilayah', wilayah);
|
|
|
|
fetch(`/LaporanCapaianWilayah/GetDataKepatuhanPeriode?${params.toString()}`, {
|
|
headers: { 'Accept': 'application/json' }
|
|
})
|
|
.then(res => {
|
|
if (!res.ok) {
|
|
throw new Error(`HTTP error! status: ${res.status}`);
|
|
}
|
|
return res.json();
|
|
})
|
|
.then(data => {
|
|
console.log('Data Kepatuhan Periode received:', data);
|
|
if (!data || !data.tingkatKepatuhanPeriode) {
|
|
console.error('Invalid data structure:', data);
|
|
return;
|
|
}
|
|
updateKepatuhanPeriodeChart(data);
|
|
})
|
|
.catch(err => console.error('Gagal memuat data kepatuhan periode:', err));
|
|
}
|
|
|
|
function updateLocationTexts(locationText) {
|
|
document.getElementById('locationTingkatKepatuhan').textContent = locationText;
|
|
document.getElementById('locationStatusSatpel').textContent = locationText;
|
|
document.getElementById('locationStatusSudin').textContent = locationText;
|
|
document.getElementById('locationCapaianRumah').textContent = locationText;
|
|
document.getElementById('locationVolumeSampah').textContent = locationText;
|
|
document.getElementById('locationRealisasi').textContent = locationText;
|
|
}
|
|
|
|
function setErrorMessage(message) {
|
|
const errorMsg = getErrorMsg();
|
|
if (message) {
|
|
errorMsg.textContent = message;
|
|
errorMsg.classList.remove('hidden');
|
|
} else {
|
|
errorMsg.classList.add('hidden');
|
|
}
|
|
}
|
|
|
|
function validateDateRange(startDate, endDate) {
|
|
const currentMonth = getCurrentMonth();
|
|
|
|
if (!startDate || !endDate) {
|
|
setErrorMessage('Bulan awal dan akhir harus diisi');
|
|
return false;
|
|
}
|
|
|
|
if (startDate < '2020-01') {
|
|
setErrorMessage('Bulan awal minimal tahun 2020');
|
|
return false;
|
|
}
|
|
|
|
if (startDate > currentMonth) {
|
|
setErrorMessage('Bulan awal tidak boleh lebih besar dari bulan berjalan');
|
|
return false;
|
|
}
|
|
|
|
if (endDate < startDate) {
|
|
setErrorMessage('Bulan akhir tidak boleh lebih kecil dari bulan awal');
|
|
return false;
|
|
}
|
|
|
|
if (endDate > currentMonth) {
|
|
setErrorMessage('Bulan akhir tidak boleh lebih besar dari bulan berjalan');
|
|
return false;
|
|
}
|
|
|
|
setErrorMessage('');
|
|
return true;
|
|
}
|
|
|
|
function updateDateInputConstraints() {
|
|
const currentMonth = getCurrentMonth();
|
|
const bulanAwalInput = getBulanAwalInput();
|
|
const bulanAkhirInput = getBulanAkhirInput();
|
|
|
|
bulanAwalInput.max = currentMonth;
|
|
if (bulanAwalInput.value) {
|
|
bulanAkhirInput.min = bulanAwalInput.value;
|
|
}
|
|
bulanAkhirInput.max = currentMonth;
|
|
}
|
|
|
|
function setDefaultValues() {
|
|
const defaultRange = getDefaultDateRange();
|
|
getBulanAwalInput().value = defaultRange.start;
|
|
getBulanAkhirInput().value = defaultRange.end;
|
|
getWilayahInput().value = 'Jakarta Barat';
|
|
updateDateInputConstraints();
|
|
}
|
|
|
|
function clearFilter() {
|
|
setDefaultValues();
|
|
setErrorMessage('');
|
|
modal_filter.close();
|
|
const defaultRange = getDefaultDateRange();
|
|
const currentMonth = getCurrentMonth();
|
|
loadDataByDateRange(defaultRange.start, defaultRange.end, 'Jakarta Barat');
|
|
loadDataKepatuhanPeriode(currentMonth, 'Jakarta Barat');
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
setDefaultValues();
|
|
const defaultRange = getDefaultDateRange();
|
|
const currentMonth = getCurrentMonth();
|
|
|
|
loadDataByDateRange(defaultRange.start, defaultRange.end, 'Jakarta Barat');
|
|
loadDataKepatuhanPeriode(currentMonth, 'Jakarta Barat');
|
|
|
|
// Filter form
|
|
document.getElementById('filterForm').addEventListener('submit', (e) => {
|
|
e.preventDefault();
|
|
const startDate = getBulanAwalInput().value;
|
|
const endDate = getBulanAkhirInput().value;
|
|
const wilayah = getWilayahInput().value;
|
|
|
|
if (validateDateRange(startDate, endDate)) {
|
|
loadDataByDateRange(startDate, endDate, wilayah);
|
|
// update chart kepatuhan
|
|
const bulanPeriode = document.getElementById('filterBulan').value;
|
|
loadDataKepatuhanPeriode(bulanPeriode, wilayah);
|
|
modal_filter.close();
|
|
}
|
|
});
|
|
|
|
// Filter bulan Kepatuhan PJLP Periode
|
|
document.getElementById('filterBulan').addEventListener('change', (e) => {
|
|
const bulan = e.target.value;
|
|
const wilayah = getWilayahInput().value;
|
|
loadDataKepatuhanPeriode(bulan, wilayah);
|
|
});
|
|
|
|
getBulanAwalInput().addEventListener('change', () => {
|
|
updateDateInputConstraints();
|
|
const startDate = getBulanAwalInput().value;
|
|
const endDate = getBulanAkhirInput().value;
|
|
if (startDate && endDate) validateDateRange(startDate, endDate);
|
|
});
|
|
|
|
getBulanAkhirInput().addEventListener('change', () => {
|
|
const startDate = getBulanAwalInput().value;
|
|
const endDate = getBulanAkhirInput().value;
|
|
if (startDate && endDate) validateDateRange(startDate, endDate);
|
|
});
|
|
});
|
|
</script> |