dashboard indikator pertanian
This commit is contained in:
@@ -15,6 +15,7 @@ use App\Models\Pertanian\PraktikBudidaya;
|
||||
use App\Models\Pertanian\Produksi;
|
||||
use App\Models\Pertanian\SkorPetani;
|
||||
use App\Models\Pertanian\SosialEkonomi;
|
||||
use App\Models\Pertanian\SurveyProduktivitas;
|
||||
use App\Models\Wilayah\DesaKelurahan;
|
||||
use App\Models\Wilayah\KabupatenKota;
|
||||
use App\Models\Wilayah\Kecamatan;
|
||||
@@ -120,6 +121,12 @@ class IndikatorPertanianController extends Controller
|
||||
'keparahanSerangan' => $this->keparahanSeranganChart($initialFilters),
|
||||
'statusHakKelolaLahan' => $this->statusHakKelolaLahanChart($initialFilters),
|
||||
'praktikPemupukan' => $this->praktikPemupukanChart($initialFilters),
|
||||
'produksiPerKomoditas' => $this->produksiPerKomoditasChart($initialFilters),
|
||||
'produktivitasPerKomoditas' => $this->produktivitasPerKomoditasChart($initialFilters),
|
||||
'luasPanenPerKomoditas' => $this->luasPanenPerKomoditasChart($initialFilters),
|
||||
'statusPanen' => $this->statusPanenChart($initialFilters),
|
||||
'surveyProduktivitasHa' => $this->surveyProduktivitasByUnitChart($initialFilters, 'ha_tahun'),
|
||||
'surveyProduktivitasPohon' => $this->surveyProduktivitasByUnitChart($initialFilters, 'pohon_tahun'),
|
||||
],
|
||||
]);
|
||||
}
|
||||
@@ -410,6 +417,123 @@ class IndikatorPertanianController extends Controller
|
||||
);
|
||||
}
|
||||
|
||||
private function produksiPerKomoditasChart(array $filters): array
|
||||
{
|
||||
$rows = $this->applyProduksiFilters(Produksi::query(), $filters)
|
||||
->leftJoin('master_komoditas as k', 'k.id', '=', 'produksi.komoditas_id')
|
||||
->whereNotNull('jumlah_panen')
|
||||
->selectRaw("COALESCE(k.nama, 'Belum ditentukan') as label")
|
||||
->selectRaw('produksi.jumlah_panen')
|
||||
->selectRaw('produksi.satuan')
|
||||
->get()
|
||||
->groupBy('label')
|
||||
->map(fn ($items) => round($items->sum(
|
||||
fn (Produksi $produksi) => $this->toKilograms(
|
||||
(float) $produksi->jumlah_panen,
|
||||
(string) $produksi->satuan
|
||||
)
|
||||
), 2))
|
||||
->filter(fn ($total) => $total > 0)
|
||||
->sortDesc();
|
||||
|
||||
return [
|
||||
'labels' => $rows->keys()->values()->all(),
|
||||
'series' => $rows->values()->map(fn ($value) => round((float) $value, 2))->values()->all(),
|
||||
];
|
||||
}
|
||||
|
||||
private function produktivitasPerKomoditasChart(array $filters): array
|
||||
{
|
||||
$rows = $this->applyProduksiFilters(Produksi::query(), $filters)
|
||||
->leftJoin('master_komoditas as k', 'k.id', '=', 'produksi.komoditas_id')
|
||||
->selectRaw("COALESCE(k.nama, 'Belum ditentukan') as label")
|
||||
->selectRaw('produksi.jumlah_panen')
|
||||
->selectRaw('produksi.satuan')
|
||||
->selectRaw('produksi.luas_panen')
|
||||
->selectRaw('produksi.produktivitas')
|
||||
->get()
|
||||
->groupBy('label')
|
||||
->map(function ($items) {
|
||||
$storedAverage = $items
|
||||
->pluck('produktivitas')
|
||||
->filter(fn ($value) => (float) $value > 0)
|
||||
->avg();
|
||||
|
||||
if ($storedAverage > 0) {
|
||||
return round((float) $storedAverage, 2);
|
||||
}
|
||||
|
||||
$totalProduksiKg = $items->sum(
|
||||
fn (Produksi $produksi) => $this->toKilograms(
|
||||
(float) $produksi->jumlah_panen,
|
||||
(string) $produksi->satuan
|
||||
)
|
||||
);
|
||||
$totalLuasPanen = $items->sum(fn (Produksi $produksi) => (float) $produksi->luas_panen);
|
||||
|
||||
return $totalLuasPanen > 0
|
||||
? round($totalProduksiKg / $totalLuasPanen, 2)
|
||||
: 0;
|
||||
})
|
||||
->filter(fn ($total) => $total > 0)
|
||||
->sortDesc();
|
||||
|
||||
return [
|
||||
'labels' => $rows->keys()->values()->all(),
|
||||
'series' => $rows->values()->map(fn ($value) => round((float) $value, 2))->values()->all(),
|
||||
];
|
||||
}
|
||||
|
||||
private function luasPanenPerKomoditasChart(array $filters): array
|
||||
{
|
||||
$rows = $this->applyProduksiFilters(Produksi::query(), $filters)
|
||||
->leftJoin('master_komoditas as k', 'k.id', '=', 'produksi.komoditas_id')
|
||||
->whereNotNull('luas_panen')
|
||||
->selectRaw("COALESCE(k.nama, 'Belum ditentukan') as label")
|
||||
->selectRaw('SUM(produksi.luas_panen) as total')
|
||||
->groupBy('k.id', 'k.nama')
|
||||
->havingRaw('SUM(produksi.luas_panen) > 0')
|
||||
->orderByDesc('total')
|
||||
->get();
|
||||
|
||||
return [
|
||||
'labels' => $rows->pluck('label')->values()->all(),
|
||||
'series' => $rows->pluck('total')->map(fn ($value) => round((float) $value, 2))->values()->all(),
|
||||
];
|
||||
}
|
||||
|
||||
private function statusPanenChart(array $filters): array
|
||||
{
|
||||
$rows = $this->applyProduksiFilters(Produksi::query(), $filters)
|
||||
->whereNotNull('status_panen')
|
||||
->selectRaw("COALESCE(status_panen, 'Belum ditentukan') as label")
|
||||
->selectRaw('COUNT(produksi.id) as total')
|
||||
->groupBy('status_panen')
|
||||
->orderByDesc('total')
|
||||
->get();
|
||||
|
||||
return $this->chartFromRows($rows, fn ($label) => $this->shortEnumLabel((string) $label));
|
||||
}
|
||||
|
||||
private function surveyProduktivitasByUnitChart(array $filters, string $unit): array
|
||||
{
|
||||
$rows = $this->applySurveyProduktivitasFilters(SurveyProduktivitas::query(), $filters)
|
||||
->leftJoin('master_komoditas as k', 'k.id', '=', 'survey_produktivitas.komoditas_id')
|
||||
->where('satuan', $unit)
|
||||
->whereNotNull('kuantitas')
|
||||
->selectRaw("COALESCE(k.nama, 'Belum ditentukan') as label")
|
||||
->selectRaw('AVG(survey_produktivitas.kuantitas) as total')
|
||||
->groupBy('k.id', 'k.nama')
|
||||
->havingRaw('AVG(survey_produktivitas.kuantitas) > 0')
|
||||
->orderByDesc('total')
|
||||
->get();
|
||||
|
||||
return [
|
||||
'labels' => $rows->pluck('label')->values()->all(),
|
||||
'series' => $rows->pluck('total')->map(fn ($value) => round((float) $value, 2))->values()->all(),
|
||||
];
|
||||
}
|
||||
|
||||
private function chartFromRows($rows, callable $labelResolver): array
|
||||
{
|
||||
return [
|
||||
@@ -505,6 +629,15 @@ class IndikatorPertanianController extends Controller
|
||||
});
|
||||
}
|
||||
|
||||
private function applySurveyProduktivitasFilters($query, array $filters)
|
||||
{
|
||||
return $query
|
||||
->whereHas('petani', function ($petani) use ($filters) {
|
||||
$this->applyPetaniFilters($petani, $filters);
|
||||
})
|
||||
->when($filters['komoditas'] !== 'all', fn ($query) => $query->where('komoditas_id', $filters['komoditas']));
|
||||
}
|
||||
|
||||
private function applyTanamanTableFilters($query, array $filters)
|
||||
{
|
||||
return $query
|
||||
|
||||
@@ -146,7 +146,13 @@
|
||||
#chart-penyakit-tanaman .apexcharts-tooltip,
|
||||
#chart-keparahan-serangan .apexcharts-tooltip,
|
||||
#chart-status-hak-kelola-lahan .apexcharts-tooltip,
|
||||
#chart-praktik-pemupukan .apexcharts-tooltip {
|
||||
#chart-praktik-pemupukan .apexcharts-tooltip,
|
||||
#chart-produksi-komoditas .apexcharts-tooltip,
|
||||
#chart-produktivitas-komoditas .apexcharts-tooltip,
|
||||
#chart-luas-panen-komoditas .apexcharts-tooltip,
|
||||
#chart-status-panen .apexcharts-tooltip,
|
||||
#chart-survey-produktivitas-ha .apexcharts-tooltip,
|
||||
#chart-survey-produktivitas-pohon .apexcharts-tooltip {
|
||||
background: transparent !important;
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
@@ -531,12 +537,100 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="indicator-tab-produksi" role="tabpanel">
|
||||
<div class="row g-6 mt-1">
|
||||
<div class="col-xxl-4 col-lg-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<div class="card-title mb-0">
|
||||
<h5 class="m-0 me-2">Total Produksi per Komoditas</h5>
|
||||
<small class="text-body-secondary">Akumulasi hasil panen aktual</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="chart-produksi-komoditas" class="indicator-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xxl-4 col-lg-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<div class="card-title mb-0">
|
||||
<h5 class="m-0 me-2">Produktivitas Aktual</h5>
|
||||
<small class="text-body-secondary">Rata-rata kg/ha per komoditas</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="chart-produktivitas-komoditas" class="indicator-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xxl-4 col-lg-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<div class="card-title mb-0">
|
||||
<h5 class="m-0 me-2">Luas Panen per Komoditas</h5>
|
||||
<small class="text-body-secondary">Akumulasi luas panen terdata</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="chart-luas-panen-komoditas" class="indicator-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xxl-4 col-lg-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<div class="card-title mb-0">
|
||||
<h5 class="m-0 me-2">Status Panen</h5>
|
||||
<small class="text-body-secondary">Jumlah catatan produksi per status</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="chart-status-panen" class="indicator-chart-sm"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xxl-4 col-lg-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<div class="card-title mb-0">
|
||||
<h5 class="m-0 me-2">Produktivitas Survey (ha/tahun)</h5>
|
||||
<small class="text-body-secondary">Rata-rata produktivitas per komoditas</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="chart-survey-produktivitas-ha" class="indicator-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xxl-4 col-lg-6">
|
||||
<div class="card h-100">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<div class="card-title mb-0">
|
||||
<h5 class="m-0 me-2">Produktivitas Survey (pohon/tahun)</h5>
|
||||
<small class="text-body-secondary">Rata-rata produktivitas per komoditas</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div id="chart-survey-produktivitas-pohon" class="indicator-chart"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@foreach ([
|
||||
'indicator-tab-produksi' => 'Produksi dan Produktivitas',
|
||||
'indicator-tab-input-produksi' => 'Input Produksi',
|
||||
'indicator-tab-panen' => 'Panen dan Pascapanen',
|
||||
'indicator-tab-akses-pasar' => 'Akses Pasar',
|
||||
] as $tabId => $tabLabel)
|
||||
|
||||
<div class="tab-pane fade" id="{{ $tabId }}" role="tabpanel">
|
||||
<div class="card">
|
||||
<div class="card-body text-center text-body-secondary py-5">
|
||||
@@ -1154,6 +1248,84 @@
|
||||
labelWidth: 180,
|
||||
valueDigits: 0,
|
||||
});
|
||||
|
||||
let productionChartsRendered = false;
|
||||
|
||||
function renderProductionCharts() {
|
||||
if (productionChartsRendered) {
|
||||
return;
|
||||
}
|
||||
|
||||
productionChartsRendered = true;
|
||||
|
||||
renderBar('#chart-produksi-komoditas', chartData.produksiPerKomoditas, {
|
||||
name: 'Produksi',
|
||||
suffix: 'kg',
|
||||
colors: colorsFor(0),
|
||||
height: 330,
|
||||
horizontal: true,
|
||||
labelWidth: 150,
|
||||
valueDigits: 0,
|
||||
});
|
||||
|
||||
renderBar('#chart-produktivitas-komoditas', chartData.produktivitasPerKomoditas, {
|
||||
name: 'Produktivitas',
|
||||
suffix: 'kg/ha',
|
||||
colors: colorsFor(2),
|
||||
height: 330,
|
||||
horizontal: true,
|
||||
labelWidth: 150,
|
||||
valueDigits: 2,
|
||||
});
|
||||
|
||||
renderBar('#chart-luas-panen-komoditas', chartData.luasPanenPerKomoditas, {
|
||||
name: 'Luas panen',
|
||||
suffix: 'ha',
|
||||
colors: colorsFor(4),
|
||||
height: 330,
|
||||
horizontal: true,
|
||||
labelWidth: 150,
|
||||
valueDigits: 2,
|
||||
});
|
||||
|
||||
renderDonut(
|
||||
'#chart-status-panen',
|
||||
chartData.statusPanen,
|
||||
colorsFor(6),
|
||||
{
|
||||
totalLabel: 'Catatan',
|
||||
valueDigits: 0,
|
||||
}
|
||||
);
|
||||
|
||||
renderBar('#chart-survey-produktivitas-ha', chartData.surveyProduktivitasHa, {
|
||||
name: 'Produktivitas',
|
||||
suffix: 'ha/tahun',
|
||||
colors: colorsFor(1),
|
||||
height: 330,
|
||||
horizontal: true,
|
||||
labelWidth: 150,
|
||||
valueDigits: 2,
|
||||
});
|
||||
|
||||
renderBar('#chart-survey-produktivitas-pohon', chartData.surveyProduktivitasPohon, {
|
||||
name: 'Produktivitas',
|
||||
suffix: 'pohon/tahun',
|
||||
colors: colorsFor(3),
|
||||
height: 330,
|
||||
horizontal: true,
|
||||
labelWidth: 150,
|
||||
valueDigits: 2,
|
||||
});
|
||||
}
|
||||
|
||||
document
|
||||
.querySelector('[data-bs-target="#indicator-tab-produksi"]')
|
||||
?.addEventListener('shown.bs.tab', renderProductionCharts);
|
||||
|
||||
if (document.querySelector('#indicator-tab-produksi')?.classList.contains('active')) {
|
||||
renderProductionCharts();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
Reference in New Issue
Block a user