feat: slicing laporan capaian rw jakarta
parent
5ff198a883
commit
862788c17c
|
|
@ -0,0 +1,81 @@
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace BpsRwApp.Controllers
|
||||||
|
{
|
||||||
|
[Route("[controller]/[action]")]
|
||||||
|
public class LaporanCapaianController : AppControllerBase
|
||||||
|
{
|
||||||
|
public IActionResult Index()
|
||||||
|
{
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public IActionResult GetData(string? date)
|
||||||
|
{
|
||||||
|
// Parse filter date
|
||||||
|
var targetDate = string.IsNullOrEmpty(date)
|
||||||
|
? DateTime.Now
|
||||||
|
: DateTime.Parse(date + "-01");
|
||||||
|
|
||||||
|
var indonesianCulture = new CultureInfo("id-ID");
|
||||||
|
var periode = targetDate.ToString("MMMM yyyy", indonesianCulture);
|
||||||
|
|
||||||
|
var data = new
|
||||||
|
{
|
||||||
|
periode,
|
||||||
|
pieTotal = new { ceklis = 700, belumCeklis = 282 },
|
||||||
|
barWilayah = new
|
||||||
|
{
|
||||||
|
labels = new[] { "Jakarta Pusat", "Jakarta Utara", "Jakarta Barat", "Jakarta Timur", "Jakarta Selatan", "Kepulauan Seribu" },
|
||||||
|
ceklis = new[] { 120, 115, 130, 125, 140, 70 },
|
||||||
|
belumCeklis = new[] { 45, 50, 42, 48, 35, 62 },
|
||||||
|
total = new[] { 165, 165, 172, 173, 175, 132 }
|
||||||
|
},
|
||||||
|
piePerWilayah = new[]
|
||||||
|
{
|
||||||
|
new { wilayah = "Jakarta Pusat", ceklis = 120, belumCeklis = 45 },
|
||||||
|
new { wilayah = "Jakarta Utara", ceklis = 115, belumCeklis = 50 },
|
||||||
|
new { wilayah = "Jakarta Barat", ceklis = 130, belumCeklis = 42 },
|
||||||
|
new { wilayah = "Jakarta Timur", ceklis = 125, belumCeklis = 48 },
|
||||||
|
new { wilayah = "Jakarta Selatan", ceklis = 140, belumCeklis = 35 },
|
||||||
|
new { wilayah = "Kepulauan Seribu", ceklis = 70, belumCeklis = 62 }
|
||||||
|
},
|
||||||
|
wilayahPjlp = new[]
|
||||||
|
{
|
||||||
|
new { wilayah = "Jakarta Pusat", jumlahPjlp = 165 },
|
||||||
|
new { wilayah = "Jakarta Utara", jumlahPjlp = 165 },
|
||||||
|
new { wilayah = "Jakarta Barat", jumlahPjlp = 172 },
|
||||||
|
new { wilayah = "Jakarta Timur", jumlahPjlp = 173 },
|
||||||
|
new { wilayah = "Jakarta Selatan", jumlahPjlp = 175 },
|
||||||
|
new { wilayah = "Kepulauan Seribu", jumlahPjlp = 132 }
|
||||||
|
},
|
||||||
|
satpel = new[]
|
||||||
|
{
|
||||||
|
new { validator = "Sudin LH", sudah = 812, belum = 124 },
|
||||||
|
new { validator = "Satpel LH", sudah = 790, belum = 400 }
|
||||||
|
},
|
||||||
|
rumah = new { konsisten = 723, tidakKonsisten = 300, total = 1023 },
|
||||||
|
barRumah = new
|
||||||
|
{
|
||||||
|
labels = new[] { "Jakarta Pusat", "Jakarta Utara", "Jakarta Barat", "Jakarta Timur", "Jakarta Selatan", "Kepulauan Seribu" },
|
||||||
|
konsisten = new[] { 833, 950, 1200, 1400, 1100, 500 },
|
||||||
|
tidakKonsisten = new[] { 124, 200, 300, 350, 250, 100 },
|
||||||
|
target = new[] { 1210, 1500, 1800, 2000, 1600, 712 }
|
||||||
|
},
|
||||||
|
detailRumahPerWilayah = new[]
|
||||||
|
{
|
||||||
|
new { wilayah = "Jakarta Pusat", target = 1210, konsisten = 833, tidakKonsisten = 124 },
|
||||||
|
new { wilayah = "Jakarta Utara", target = 1500, konsisten = 950, tidakKonsisten = 200 },
|
||||||
|
new { wilayah = "Jakarta Barat", target = 1800, konsisten = 1200, tidakKonsisten = 300 },
|
||||||
|
new { wilayah = "Jakarta Selatan", target = 1600, konsisten = 1100, tidakKonsisten = 250 },
|
||||||
|
new { wilayah = "Jakarta Timur", target = 2000, konsisten = 1400, tidakKonsisten = 350 },
|
||||||
|
new { wilayah = "Kep. Seribu", target = 712, konsisten = 500, tidakKonsisten = 100 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Json(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,414 @@
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Capaian BPS RW DKI Jakarta";
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="breadcrumbs text-sm">
|
||||||
|
<ul>
|
||||||
|
<li class="text-gray-500"><a>Laporan</a></li>
|
||||||
|
<li>Capaian BPS RW DKI Jakarta</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-between items-center mb-6">
|
||||||
|
<h2 class="text-xl font-semibold">Capaian BPS RW DKI Jakarta</h2>
|
||||||
|
|
||||||
|
<!-- Filter Bulan -->
|
||||||
|
<div class="flex items-center gap-3">
|
||||||
|
<span class="whitespace-nowrap text-sm font-medium text-gray-700">Filter Bulan:</span>
|
||||||
|
<input type="month" id="filterBulan" class="px-4 py-2 border bg-white rounded-md w-[180px] sm:w-[200px]"
|
||||||
|
min="2000-01" max="@DateTime.Now.ToString("yyyy-MM")" value="@DateTime.Now.ToString("yyyy-MM")" />
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Tingkat Kepatuhan -->
|
||||||
|
<div class="bg-white rounded-sm shadow p-6">
|
||||||
|
<h3 class="text-lg font-semibold mb-4">Tingkat Kepatuhan dalam Menjalankan Instruksi Kepala Dinas</h3>
|
||||||
|
|
||||||
|
<div class="border border-gray-400 rounded-sm p-4 h-80 grid grid-cols-1 md:grid-cols-3 gap-6 items-start">
|
||||||
|
<!-- Pie Chart Total -->
|
||||||
|
<div class="flex flex-col items-center col-span-1">
|
||||||
|
<h4 class="font-medium text-sm text-center" id="titleTotalPjlp">Kepatuhan PJLP Pendamping</h4>
|
||||||
|
<div class="w-full h-[250px] flex items-center justify-center mt-2">
|
||||||
|
<canvas id="pieTotal"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col items-start col-span-2">
|
||||||
|
<h4 class="font-medium text-sm text-left">Kepatuhan PJLP Pendamping</h4>
|
||||||
|
<div class="w-full h-[250px] mt-2">
|
||||||
|
<canvas id="barWilayah"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Detail Kepatuhan Per Wilayah -->
|
||||||
|
<div class="bg-white rounded-sm shadow p-6 mt-6">
|
||||||
|
<h3 class="text-lg font-semibold mb-4">Detail Kepatuhan PJLP Pendamping</h3>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6" id="detailPjlpContainer">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Status Validasi SATPEL Oktober 2025 -->
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-6" id="satpelContainer"></div>
|
||||||
|
|
||||||
|
<!-- Capaian Program Pendampingan -->
|
||||||
|
<div class="bg-white rounded-sm shadow p-6 mt-6">
|
||||||
|
<h3 class="text-lg font-semibold">Capaian Program Pendampingan BPS RW</h3>
|
||||||
|
<p class="text-sm text-gray-600 mb-4" id="descPeriodeRumah">Capaian Rumah memilah dalam pelaksanaan instruksi Kepala
|
||||||
|
Dinas Lingkungan Hidup</p>
|
||||||
|
<div class="border border-gray-400 rounded-sm p-4 h-80 grid grid-cols-1 md:grid-cols-3 gap-6 items-start">
|
||||||
|
|
||||||
|
<div class="flex flex-col items-center col-span-1 w-full">
|
||||||
|
<h4 class="font-medium text-sm text-center" id="titleTargetRumah">Total Target Rumah Tangga Memilah</h4>
|
||||||
|
<div class="w-full h-[250px] flex items-center justify-center mt-2">
|
||||||
|
<canvas id="pieRumah"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-col items-start col-span-2">
|
||||||
|
<div class="w-full h-[250px] mt-2">
|
||||||
|
<canvas id="barRumahWilayah"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Detail Rumah Memilah -->
|
||||||
|
<div class="bg-white rounded-sm shadow p-6 mt-6">
|
||||||
|
<h3 class="text-lg font-semibold mb-4">Detail Jumlah Rumah Memilah</h3>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6" id="detailRumahContainer">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.5.0/chart.umd.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.2.0/chartjs-plugin-datalabels.min.js"></script>
|
||||||
|
<script>
|
||||||
|
Chart.register(ChartDataLabels);
|
||||||
|
|
||||||
|
Chart.defaults.animation = {
|
||||||
|
duration: 1500,
|
||||||
|
easing: 'easeOutQuart'
|
||||||
|
};
|
||||||
|
Chart.defaults.animations = {
|
||||||
|
numbers: { duration: 1500, easing: 'easeOutQuart' },
|
||||||
|
colors: { duration: 1500, easing: 'easeOutQuart' }
|
||||||
|
};
|
||||||
|
|
||||||
|
let chartInstances = {
|
||||||
|
pieTotal: null,
|
||||||
|
barWilayah: null,
|
||||||
|
pieRumah: null,
|
||||||
|
barRumahWilayah: null,
|
||||||
|
piePerWilayah: {},
|
||||||
|
satpel: {},
|
||||||
|
detailRumah: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
function updateCharts(data) {
|
||||||
|
if (chartInstances.pieTotal) chartInstances.pieTotal.destroy();
|
||||||
|
if (chartInstances.barWilayah) chartInstances.barWilayah.destroy();
|
||||||
|
if (chartInstances.pieRumah) chartInstances.pieRumah.destroy();
|
||||||
|
if (chartInstances.barRumahWilayah) chartInstances.barRumahWilayah.destroy();
|
||||||
|
|
||||||
|
Object.values(chartInstances.piePerWilayah).forEach(chart => chart && chart.destroy());
|
||||||
|
chartInstances.piePerWilayah = {};
|
||||||
|
|
||||||
|
Object.values(chartInstances.satpel).forEach(chart => chart && chart.destroy());
|
||||||
|
chartInstances.satpel = {};
|
||||||
|
|
||||||
|
Object.values(chartInstances.detailRumah).forEach(chart => chart && chart.destroy());
|
||||||
|
chartInstances.detailRumah = {};
|
||||||
|
|
||||||
|
renderCharts(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderCharts(data) {
|
||||||
|
document.getElementById('titleTargetRumah').textContent = `Total Target ${data.rumah.total} Rumah Tangga Memilah`;
|
||||||
|
document.getElementById('descPeriodeRumah').textContent = `Capaian Rumah memilah dalam pelaksanaan instruksi Kepala Dinas Lingkungan Hidup Periode ${data.periode}`;
|
||||||
|
|
||||||
|
// Pie Kepatuhan PJLP
|
||||||
|
chartInstances.pieTotal = new Chart(document.getElementById('pieTotal'), {
|
||||||
|
type: 'pie',
|
||||||
|
data: {
|
||||||
|
labels: ['Ceklis', 'Belum Ceklis'],
|
||||||
|
datasets: [{ data: [data.pieTotal.ceklis, data.pieTotal.belumCeklis], backgroundColor: ['#9FCE62', '#EF4444'] }]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
aspectRatio: 1,
|
||||||
|
plugins: {
|
||||||
|
legend: { position: 'bottom', labels: { usePointStyle: true, pointStyle: "circle" } },
|
||||||
|
datalabels: {
|
||||||
|
color: '#fff',
|
||||||
|
formatter: (val, ctx) => {
|
||||||
|
const total = ctx.dataset.data.reduce((a, b) => a + b, 0);
|
||||||
|
const percent = Math.round(val / total * 100);
|
||||||
|
|
||||||
|
return `${val} PJLP\n${percent}%`;
|
||||||
|
},
|
||||||
|
font: { weight: 'bold', size: 12 },
|
||||||
|
align: 'center',
|
||||||
|
anchor: 'center'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// bar Kepatuhan PJLP
|
||||||
|
chartInstances.barWilayah = new Chart(document.getElementById('barWilayah'), {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: data.barWilayah.labels,
|
||||||
|
datasets: [
|
||||||
|
{ label: 'Ceklis', data: data.barWilayah.ceklis, backgroundColor: '#9FCE62' },
|
||||||
|
{ label: 'Belum Ceklis', data: data.barWilayah.belumCeklis, backgroundColor: '#EF4444' },
|
||||||
|
{ label: 'Total', data: data.barWilayah.total, backgroundColor: '#C6C6C6' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
scales: { y: { beginAtZero: true } },
|
||||||
|
plugins: {
|
||||||
|
legend: { position: 'bottom', labels: { usePointStyle: true, pointStyle: "circle" } },
|
||||||
|
datalabels: { anchor: 'end', align: 'top', color: '#444', font: { size: 10 } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Pie Detail Kepatuhan
|
||||||
|
const detailPjlpContainer = document.getElementById('detailPjlpContainer');
|
||||||
|
detailPjlpContainer.innerHTML = '';
|
||||||
|
|
||||||
|
data.piePerWilayah.forEach((item, i) => {
|
||||||
|
const wilayahId = item.wilayah.replace(/\s+/g, '_');
|
||||||
|
|
||||||
|
const card = document.createElement('div');
|
||||||
|
card.className = 'relative border border-gray-400 rounded-sm p-4 text-center space-y-2 h-[300px] flex flex-col items-center justify-between';
|
||||||
|
card.innerHTML = `
|
||||||
|
<h4 class="font-semibold text-sm leading-tight">${item.wilayah} : ${data.wilayahPjlp[i].jumlahPjlp} PJLP<br />Pendamping BPS RW</h4>
|
||||||
|
<div class="w-full h-[200px]">
|
||||||
|
<canvas id="pie_${wilayahId}"></canvas>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
detailPjlpContainer.appendChild(card);
|
||||||
|
|
||||||
|
// Buat chart untuk wilayah ini
|
||||||
|
const ctx = document.getElementById(`pie_${wilayahId}`);
|
||||||
|
if (ctx) {
|
||||||
|
chartInstances.piePerWilayah[wilayahId] = new Chart(ctx, {
|
||||||
|
type: 'pie',
|
||||||
|
data: {
|
||||||
|
labels: ['Ceklis', 'Belum Ceklis'],
|
||||||
|
datasets: [{
|
||||||
|
data: [item.ceklis, item.belumCeklis],
|
||||||
|
backgroundColor: ['#9FCE62', '#EF4444']
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
aspectRatio: 1,
|
||||||
|
plugins: {
|
||||||
|
legend: { position: 'bottom', labels: { usePointStyle: true, pointStyle: "circle" } },
|
||||||
|
datalabels: {
|
||||||
|
color: '#fff',
|
||||||
|
formatter: (val, ctx) => {
|
||||||
|
const total = ctx.dataset.data.reduce((a, b) => a + b, 0);
|
||||||
|
return Math.round(val / total * 100) + '%';
|
||||||
|
},
|
||||||
|
font: { weight: 'bold', size: 12 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Status Validasi
|
||||||
|
const satpelContainer = document.getElementById('satpelContainer');
|
||||||
|
satpelContainer.innerHTML = '';
|
||||||
|
|
||||||
|
data.satpel.forEach((item, i) => {
|
||||||
|
const card = document.createElement('div');
|
||||||
|
card.className = 'bg-base-100 rounded-sm p-4 space-y-4';
|
||||||
|
card.innerHTML = `
|
||||||
|
<div>
|
||||||
|
<h3 class="text-lg font-semibold">Status Validasi ${item.validator} ${data.periode}</h3>
|
||||||
|
<span class="text-sm text-gray-500">DKI Jakarta</span>
|
||||||
|
<div class="bg-white rounded-sm border border-gray-400 p-6 mt-6">
|
||||||
|
<div class="w-full h-[250px] flex items-center justify-center">
|
||||||
|
<canvas id="satpel_${i}"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class="text-sm leading-relaxed text-gray-700">
|
||||||
|
Terhadap status validasi yang dilakukan ${item.validator}:<br />
|
||||||
|
Periode bulan ini terdapat <strong>${item.sudah.toLocaleString()}</strong> aktifitas PJLP pendamping BPS RW melakukan checklist pada sistem
|
||||||
|
informasi Dashboard BPS RW yang sudah divalidasi,
|
||||||
|
sedangkan <strong>${item.belum.toLocaleString()}</strong> aktifitas tidak tervalidasi
|
||||||
|
(Terlewat/diragukan kebenaran checklist).
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
satpelContainer.appendChild(card);
|
||||||
|
|
||||||
|
const ctx = document.getElementById(`satpel_${i}`);
|
||||||
|
if (ctx) {
|
||||||
|
chartInstances.satpel[i] = new Chart(ctx, {
|
||||||
|
type: 'pie',
|
||||||
|
data: {
|
||||||
|
labels: ['Sudah', 'Belum'],
|
||||||
|
datasets: [{
|
||||||
|
data: [item.sudah, item.belum],
|
||||||
|
backgroundColor: ['#93C5FD ', '#FACC15']
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: true,
|
||||||
|
aspectRatio: 1,
|
||||||
|
plugins: {
|
||||||
|
legend: { position: 'bottom', labels: { usePointStyle: true, pointStyle: "circle" } },
|
||||||
|
datalabels: {
|
||||||
|
color: '#fff',
|
||||||
|
formatter: (val, ctx) => {
|
||||||
|
const total = ctx.dataset.data.reduce((a, b) => a + b, 0);
|
||||||
|
return val.toLocaleString() + '\n' + Math.round(val / total * 100) + '%';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Pie Capaian Program
|
||||||
|
chartInstances.pieRumah = new Chart(document.getElementById('pieRumah'), {
|
||||||
|
type: 'pie',
|
||||||
|
data: { labels: ['Rumah Memilih Konsisten', 'Rumah Memilih Tidak Konsisten'], datasets: [{ data: [data.rumah.konsisten, data.rumah.tidakKonsisten], backgroundColor: ['#9FCE62', '#FDBA74'] }] },
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: true,
|
||||||
|
aspectRatio: 1,
|
||||||
|
plugins: {
|
||||||
|
legend: { position: 'bottom', labels: { usePointStyle: true, pointStyle: "circle" } },
|
||||||
|
datalabels: {
|
||||||
|
color: '#fff',
|
||||||
|
formatter: (val, ctx) => {
|
||||||
|
const total = ctx.dataset.data.reduce((a, b) => a + b, 0);
|
||||||
|
return val + '\n' + Math.round(val / total * 100) + '%';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Bar Capaian Program
|
||||||
|
chartInstances.barRumahWilayah = new Chart(document.getElementById('barRumahWilayah'), {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: data.barRumah.labels,
|
||||||
|
datasets: [
|
||||||
|
{ label: 'Rumah Memilah Konsisten', data: data.barRumah.konsisten, backgroundColor: '#9FCE62' },
|
||||||
|
{ label: 'Rumah Memilih Tidak Konsisten', data: data.barRumah.tidakKonsisten, backgroundColor: '#FDBA74' },
|
||||||
|
{ label: 'Target', data: data.barRumah.target, backgroundColor: '#C6C6C6' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
scales: { y: { beginAtZero: true } },
|
||||||
|
plugins: {
|
||||||
|
legend: { position: 'bottom', labels: { usePointStyle: true, pointStyle: "circle" } },
|
||||||
|
datalabels: { anchor: 'end', align: 'top', color: '#444', font: { size: 10 } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Pie Detail Rumah Memilah
|
||||||
|
const detailRumahContainer = document.getElementById('detailRumahContainer');
|
||||||
|
detailRumahContainer.innerHTML = '';
|
||||||
|
|
||||||
|
data.detailRumahPerWilayah.forEach((item, i) => {
|
||||||
|
const wilayahId = item.wilayah.replace(/\s+/g, '_');
|
||||||
|
|
||||||
|
const card = document.createElement('div');
|
||||||
|
card.className = 'border border-gray-400 rounded-sm p-4 space-y-4';
|
||||||
|
card.innerHTML = `
|
||||||
|
<h4 class="font-semibold text-sm text-center">${item.wilayah}</h4>
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<div class="w-[200px] h-[200px]">
|
||||||
|
<canvas id="rm_${wilayahId}"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-sm text-gray-700 border border-gray-400 leading-relaxed mt-2 bg-gray-50 p-2 rounded">
|
||||||
|
Target Rumah Pemilah : ${item.target.toLocaleString()} <br />
|
||||||
|
Rumah Memilah Konsisten : ${item.konsisten.toLocaleString()} <br />
|
||||||
|
Rumah Memilah Tidak Konsisten : ${item.tidakKonsisten.toLocaleString()}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
detailRumahContainer.appendChild(card);
|
||||||
|
|
||||||
|
// Buat chart untuk wilayah ini
|
||||||
|
const ctx = document.getElementById(`rm_${wilayahId}`);
|
||||||
|
if (ctx) {
|
||||||
|
chartInstances.detailRumah[wilayahId] = new Chart(ctx, {
|
||||||
|
type: 'pie',
|
||||||
|
data: {
|
||||||
|
labels: ['Rumah Memilih Konsisten', 'Rumah Memilih Tidak Konsisten'],
|
||||||
|
datasets: [{
|
||||||
|
data: [item.konsisten, item.tidakKonsisten],
|
||||||
|
backgroundColor: ['#9FCE62', '#FDBA74']
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
maintainAspectRatio: true,
|
||||||
|
aspectRatio: 1,
|
||||||
|
plugins: {
|
||||||
|
legend: { position: 'bottom', labels: { usePointStyle: true, pointStyle: "circle" } },
|
||||||
|
datalabels: {
|
||||||
|
color: '#fff',
|
||||||
|
formatter: (val, ctx) => {
|
||||||
|
const total = ctx.dataset.data.reduce((a, b) => a + b, 0);
|
||||||
|
return Math.round(val / total * 100) + '%';
|
||||||
|
},
|
||||||
|
font: { weight: 'bold', size: 12 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterBulan = document.getElementById('filterBulan');
|
||||||
|
|
||||||
|
function loadDataByDate(date) {
|
||||||
|
const url = `/LaporanCapaian/GetData?date=${encodeURIComponent(date)}`;
|
||||||
|
fetch(url, {
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => updateCharts(data))
|
||||||
|
.catch(err => console.error('Gagal memuat data:', err));
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const defaultDate = filterBulan.value;
|
||||||
|
loadDataByDate(defaultDate);
|
||||||
|
});
|
||||||
|
|
||||||
|
filterBulan.addEventListener('change', () => {
|
||||||
|
const selectedDate = filterBulan.value;
|
||||||
|
loadDataByDate(selectedDate);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
@ -154,7 +154,7 @@
|
||||||
</details>
|
</details>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<details @(new[] { "RincianTargetRumahMemilah", "VolumeTimbulanSampah" }.Contains(controller) ? "open" : "")>
|
<details @(new[] { "RincianTargetRumahMemilah", "VolumeTimbulanSampah", "LaporanCapaian" }.Contains(controller) ? "open" : "")>
|
||||||
<summary>LAPORAN</summary>
|
<summary>LAPORAN</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
|
|
@ -169,6 +169,13 @@
|
||||||
Volume Timbulan Sampah
|
Volume Timbulan Sampah
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a asp-controller="LaporanCapaian" asp-action="Index"
|
||||||
|
class="@(controller == "LaporanCapaian" ? "menu-active" : "")">
|
||||||
|
<span class="icon icon-fill">flag</span>
|
||||||
|
Laporan Capaian BPS RW DKI Jakarta
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</details>
|
</details>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue