dashboard produksi & ganti warna chart
This commit is contained in:
@@ -5,8 +5,13 @@ namespace App\Http\Controllers\Web\Dashboard;
|
||||
use App\Enums\KeparahanSerangan;
|
||||
use App\Enums\KondisiTanaman;
|
||||
use App\Enums\PenyakitTanaman;
|
||||
use App\Enums\PraktikBudidaya\FrekuensiPemangkasanUtama;
|
||||
use App\Enums\PraktikBudidaya\FrekuensiSanitasiLahan;
|
||||
use App\Enums\PraktikBudidaya\MetodePenangananHamaPenyakit;
|
||||
use App\Enums\PraktikBudidaya\PemberianPupuk;
|
||||
use App\Enums\SeranganHama;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Pertanian\Komoditas;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
@@ -67,6 +72,7 @@ class SummaryController extends Controller
|
||||
->get([
|
||||
'id',
|
||||
'lahan_id',
|
||||
'komoditas_id',
|
||||
'kondisi_tanaman',
|
||||
'umur_tanaman',
|
||||
'serangan_hama',
|
||||
@@ -87,49 +93,189 @@ class SummaryController extends Controller
|
||||
|
||||
$landMetrics = $this->karakteristikLandMetrics($request);
|
||||
$totalLuasLahan = $landMetrics['total_luas_lahan'];
|
||||
$petaniCount = $landMetrics['total_petani'];
|
||||
$avgLuasPerPetani = $landMetrics['ratarata_luas_lahan'];
|
||||
$jumlahTanaman = $conditionSource->whereNotNull('kondisi_tanaman')->count();
|
||||
$productivityCards = $this->productivityKpiCards($lahanIds);
|
||||
$praktikBudidaya = $this->filteredPraktikBudidaya($request);
|
||||
|
||||
$kpiCards = [
|
||||
[
|
||||
'value' => number_format($totalLuasLahan, 2, ',', '.'),
|
||||
'unit' => 'Ha',
|
||||
'unit' => 'ha',
|
||||
'label' => 'Total Luas Lahan',
|
||||
'description' => 'Luas keseluruhan lahan terfilter',
|
||||
'description' => 'Seluruh lahan petani',
|
||||
'icon' => 'tabler-chart-area-line',
|
||||
'variant' => 'success',
|
||||
],
|
||||
[
|
||||
'value' => number_format($avgLuasPerPetani, 2, ',', '.'),
|
||||
'unit' => 'Ha/petani',
|
||||
'label' => 'Rata-Rata Luas Lahan per Petani',
|
||||
'description' => number_format($petaniCount, 0, ',', '.').' petani terfilter',
|
||||
'unit' => 'ha',
|
||||
'label' => 'Rata-rata Luas Lahan',
|
||||
'description' => 'Rata-rata per petani',
|
||||
'icon' => 'tabler-ruler-measure',
|
||||
'variant' => 'danger',
|
||||
],
|
||||
[
|
||||
'value' => number_format($jumlahTanaman, 0, ',', '.'),
|
||||
'unit' => 'tanaman',
|
||||
'label' => 'Jumlah Tanaman',
|
||||
'description' => 'Total tanaman pada chart kondisi tanaman',
|
||||
'icon' => 'tabler-plant-2',
|
||||
'variant' => 'secondary',
|
||||
],
|
||||
];
|
||||
$kpiCards = array_merge($kpiCards, $productivityCards);
|
||||
|
||||
return [
|
||||
'kpiCards' => $kpiCards,
|
||||
'chartData' => [
|
||||
'umurLahan' => $this->ageBucketChart($lahan, 'umur_lahan'),
|
||||
'umurTanaman' => $this->ageBucketChart($healthSource, 'umur_tanaman'),
|
||||
'jumlahTanamanPerKomoditas' => $this->plantCountByCommodityChart($tanaman, $lahan),
|
||||
'kondisiTanaman' => $this->attributeChart($conditionSource, 'kondisi_tanaman', fn ($value) => $this->conditionLabel($value)),
|
||||
'keparahanSerangan' => $this->attributeChart($healthSource, 'keparahan_serangan', fn ($value) => $this->severityLabel($value)),
|
||||
'gejalaSerangan' => $this->symptomChart($healthSource),
|
||||
'intensitasPemangkasan' => $this->enumOptionChart($praktikBudidaya, 'frekuensi_pemangkasan_utama', FrekuensiPemangkasanUtama::class),
|
||||
'intensitasPemupukan' => $this->enumOptionChart($praktikBudidaya, 'pemberian_pupuk', PemberianPupuk::class),
|
||||
'metodePenangananHamaPenyakit' => $this->enumOptionChart($praktikBudidaya, 'metode_penanganan_opt', MetodePenangananHamaPenyakit::class),
|
||||
'intensitasPembersihanLahan' => $this->enumOptionChart($praktikBudidaya, 'frekuensi_sanitasi_lahan', FrekuensiSanitasiLahan::class),
|
||||
'sumberAirKebun' => $this->arrayOptionChart(
|
||||
$praktikBudidaya,
|
||||
'sumber_air',
|
||||
['Sungai/mata air', 'Sumur', 'Mengandalkan hujan saja', 'Lainnya'],
|
||||
fn ($value) => in_array($value, ['Sungai/mata air', 'Sumur', 'Mengandalkan hujan saja'], true) ? $value : 'Lainnya',
|
||||
),
|
||||
'kebiasaanPraktikBaik' => $this->arrayOptionChart(
|
||||
$praktikBudidaya,
|
||||
'kebiasaan_konservasi_tanah',
|
||||
[
|
||||
'Membuat pematang/tanggul tanah di lahan miring supaya tanah tidak longsor ke bawah',
|
||||
'Menumpuk daun kering/sisa tanaman di sekitar pohon',
|
||||
'Menanam tanaman lain di sela-sela komoditas utama untuk menutupi tanah',
|
||||
'Membuat lubang atau parit kecil untuk menampung air hujan',
|
||||
'Tidak ada yang seperti itu di kebun saya',
|
||||
],
|
||||
fn ($value) => $value === 'Membuat pematang atau tanggul tanah di lahan miring supaya tanah tidak longsor ke bawah'
|
||||
? 'Membuat pematang/tanggul tanah di lahan miring supaya tanah tidak longsor ke bawah'
|
||||
: $value,
|
||||
),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function filteredPraktikBudidaya(Request $request)
|
||||
{
|
||||
$petaniIds = $this->filteredPetaniIdsQuery($request);
|
||||
|
||||
return DB::table('praktik_budidaya')
|
||||
->whereNull('praktik_budidaya.deleted_at')
|
||||
->whereIn('praktik_budidaya.petani_id', $petaniIds)
|
||||
->get([
|
||||
'frekuensi_pemangkasan_utama',
|
||||
'pemberian_pupuk',
|
||||
'metode_penanganan_opt',
|
||||
'frekuensi_sanitasi_lahan',
|
||||
'sumber_air',
|
||||
'kebiasaan_konservasi_tanah',
|
||||
]);
|
||||
}
|
||||
|
||||
private function plantCountByCommodityChart($tanaman, $lahan): array
|
||||
{
|
||||
$lahanKomoditas = $lahan
|
||||
->mapWithKeys(fn ($row) => [(int) $row->id => $row->komoditas_nama ?: 'Belum ditentukan']);
|
||||
|
||||
$komoditasNames = DB::table('master_komoditas')
|
||||
->whereNull('deleted_at')
|
||||
->pluck('nama', 'id');
|
||||
|
||||
$counts = $tanaman
|
||||
->map(function ($row) use ($komoditasNames, $lahanKomoditas) {
|
||||
if ($row->komoditas_id && $komoditasNames->has($row->komoditas_id)) {
|
||||
return $komoditasNames[$row->komoditas_id];
|
||||
}
|
||||
|
||||
return $lahanKomoditas[(int) $row->lahan_id] ?? 'Belum ditentukan';
|
||||
})
|
||||
->filter()
|
||||
->countBy()
|
||||
->sortDesc();
|
||||
|
||||
return [
|
||||
'labels' => $counts->keys()->values()->all(),
|
||||
'series' => $counts->values()->map(fn ($value) => (int) $value)->values()->all(),
|
||||
];
|
||||
}
|
||||
|
||||
private function productivityKpiCards($lahanIds): array
|
||||
{
|
||||
$komoditas = Komoditas::query()
|
||||
->where('is_utama', true)
|
||||
->orderBy('nama')
|
||||
->limit(4)
|
||||
->get(['id', 'nama']);
|
||||
|
||||
$produksiRows = DB::table('produksi')
|
||||
->whereNull('produksi.deleted_at')
|
||||
->leftJoin('map_lahan as lahan_produksi', 'lahan_produksi.id', '=', 'produksi.lahan_id')
|
||||
->when($lahanIds->isNotEmpty(), fn ($query) => $query->whereIn('produksi.lahan_id', $lahanIds))
|
||||
->when($lahanIds->isEmpty(), fn ($query) => $query->whereRaw('1 = 0'))
|
||||
->selectRaw('COALESCE(produksi.komoditas_id, lahan_produksi.komoditas_id) as komoditas_id')
|
||||
->addSelect([
|
||||
'produksi.jumlah_panen',
|
||||
'produksi.satuan',
|
||||
'produksi.luas_panen',
|
||||
'produksi.produktivitas',
|
||||
])
|
||||
->get()
|
||||
->groupBy('komoditas_id');
|
||||
|
||||
$variants = ['primary', 'warning', 'info', 'secondary'];
|
||||
$icon = 'tabler-chart-bar';
|
||||
|
||||
return $komoditas
|
||||
->values()
|
||||
->map(function ($item, int $index) use ($produksiRows, $variants, $icon) {
|
||||
$rows = $produksiRows->get($item->id, collect());
|
||||
$average = $this->averageProductivity($rows);
|
||||
|
||||
return [
|
||||
'value' => number_format($average, 0, ',', '.'),
|
||||
'unit' => 'kg/ha',
|
||||
'label' => 'Produktivitas Rata-rata '.$item->nama,
|
||||
'description' => 'Rata-rata produktivitas per komoditas',
|
||||
'icon' => $icon,
|
||||
'variant' => $variants[$index % count($variants)],
|
||||
];
|
||||
})
|
||||
->all();
|
||||
}
|
||||
|
||||
private function averageProductivity($rows): float
|
||||
{
|
||||
if ($rows->isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$storedAverage = $rows
|
||||
->pluck('produktivitas')
|
||||
->filter(fn ($value) => (float) $value > 0)
|
||||
->avg();
|
||||
|
||||
if ($storedAverage > 0) {
|
||||
return round((float) $storedAverage, 2);
|
||||
}
|
||||
|
||||
$totalProduksiKg = $rows->sum(fn ($row) => $this->toKilograms(
|
||||
(float) ($row->jumlah_panen ?? 0),
|
||||
(string) ($row->satuan ?? 'kg')
|
||||
));
|
||||
$totalLuasPanen = $rows->sum(fn ($row) => (float) ($row->luas_panen ?? 0));
|
||||
|
||||
return $totalLuasPanen > 0
|
||||
? round($totalProduksiKg / $totalLuasPanen, 2)
|
||||
: 0;
|
||||
}
|
||||
|
||||
private function toKilograms(float $value, string $unit): float
|
||||
{
|
||||
return match (strtolower($unit)) {
|
||||
'ton' => $value * 1000,
|
||||
'kuintal', 'kwintal' => $value * 100,
|
||||
default => $value,
|
||||
};
|
||||
}
|
||||
|
||||
private function filteredLahanQuery(Request $request)
|
||||
{
|
||||
return DB::table('map_lahan')
|
||||
@@ -271,6 +417,48 @@ class SummaryController extends Controller
|
||||
];
|
||||
}
|
||||
|
||||
private function enumOptionChart($rows, string $field, string $enumClass): array
|
||||
{
|
||||
$options = collect($enumClass::options())
|
||||
->mapWithKeys(fn ($option) => [(string) $option['value'] => $option['label']]);
|
||||
|
||||
$counts = $rows
|
||||
->pluck($field)
|
||||
->filter(fn ($value) => $value !== null && $value !== '')
|
||||
->map(fn ($value) => (string) $value)
|
||||
->countBy();
|
||||
|
||||
return [
|
||||
'labels' => $options->values()->all(),
|
||||
'series' => $options->keys()->map(fn ($value) => (int) ($counts[$value] ?? 0))->values()->all(),
|
||||
];
|
||||
}
|
||||
|
||||
private function arrayOptionChart($rows, string $field, array $labels, ?callable $normalizer = null): array
|
||||
{
|
||||
$counts = collect($labels)->mapWithKeys(fn ($label) => [$label => 0]);
|
||||
|
||||
foreach ($rows as $row) {
|
||||
foreach ($this->arrayValues($row->{$field} ?? null) as $value) {
|
||||
$label = $normalizer ? $normalizer($value) : $value;
|
||||
if ($label === null || $label === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$counts->has($label)) {
|
||||
$counts[$label] = 0;
|
||||
}
|
||||
|
||||
$counts[$label] = (int) $counts[$label] + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'labels' => $counts->keys()->values()->all(),
|
||||
'series' => $counts->values()->map(fn ($value) => (int) $value)->values()->all(),
|
||||
];
|
||||
}
|
||||
|
||||
private function symptomChart($rows): array
|
||||
{
|
||||
$counts = collect();
|
||||
|
||||
Reference in New Issue
Block a user