$request->desaKelurahan_id, 'kecamatan_id' => $request->kecamatan_id, 'kabupatenKota_id' => $request->kabupatenKota_id, 'provinsi_id' => $request->provinsi_id, 'komoditas_id' => $request->komoditas_id, 'segmen' => $request->segmen, ]; } private function petaniQuery(array $filters): \Illuminate\Database\Eloquent\Builder { $petaniQuery = Petani::query() ->join('master_desa_kelurahan', 'petani.desa_kelurahan_id', '=', 'master_desa_kelurahan.id') ->join('master_kecamatan', 'master_desa_kelurahan.kecamatan_id', '=', 'master_kecamatan.id') ->join('master_kabupaten_kota', 'master_kecamatan.kabupaten_kota_id', '=', 'master_kabupaten_kota.id') ->join('master_provinsi', 'master_kabupaten_kota.provinsi_id', '=', 'master_provinsi.id') ->whereNull('petani.deleted_at') ->when($filters['provinsi_id'], fn($q, $id) => $q->where('master_kabupaten_kota.provinsi_id', $id)) ->when($filters['kabupatenKota_id'], fn($q, $id) => $q->where('master_kecamatan.kabupaten_kota_id', $id)) ->when($filters['kecamatan_id'], fn($q, $id) => $q->where('master_desa_kelurahan.kecamatan_id', $id)) ->when($filters['desaKelurahan_id'], fn($q, $id) => $q->where('petani.desa_kelurahan_id', $id)) ->when($filters['komoditas_id'], fn($q, $id) => $q->where('petani.komoditas_id', $id)); return $petaniQuery; } private function skorPetaniQuery(array $filters, array $komoditas): \Illuminate\Database\Eloquent\Builder { $skor = SkorPetani::query() ->join('petani', 'petani_skor.petani_id', '=', 'petani.id') ->join('master_desa_kelurahan', 'petani.desa_kelurahan_id', '=', 'master_desa_kelurahan.id') ->join('master_kecamatan', 'master_desa_kelurahan.kecamatan_id', '=', 'master_kecamatan.id') ->join('master_kabupaten_kota', 'master_kecamatan.kabupaten_kota_id', '=', 'master_kabupaten_kota.id') ->join('master_provinsi', 'master_kabupaten_kota.provinsi_id', '=', 'master_provinsi.id') ->whereNull('petani.deleted_at') ->when($filters['provinsi_id'], fn($q, $id) => $q->where('master_kabupaten_kota.provinsi_id', $id)) ->when($filters['kabupatenKota_id'], fn($q, $id) => $q->where('master_kecamatan.kabupaten_kota_id', $id)) ->when($filters['kecamatan_id'], fn($q, $id) => $q->where('master_desa_kelurahan.kecamatan_id', $id)) ->when($filters['desaKelurahan_id'], fn($q, $id) => $q->where('petani.desa_kelurahan_id', $id)) ->whereIn('petani.komoditas_id', $komoditas); if ($filters['segmen']) { $skor->where(function ($q) use ($filters) { match ($filters['segmen']) { 'Penggerak' => $q->where('skor_kesiapan_adopsi', '>=', 4), 'Perintis' => $q->where(function($q) { $q->where('skor_kesiapan_adopsi', '>=', 3) ->where('skor_kesiapan_adopsi', '<', 4); }), 'Pemerhati' => $q->where(function($q) { $q->where('skor_kesiapan_adopsi', '>=', 2) ->where('skor_kesiapan_adopsi', '<', 3); }), 'Pemula' => $q->where(function($q) { $q->where('skor_kesiapan_adopsi', '>=', 1) ->where('skor_kesiapan_adopsi', '<', 2); }), 'Belum Lengkap' => $q->where(function ($q) { $q->whereNull('skor_kesiapan_adopsi') ->orWhere('skor_kesiapan_adopsi', '<', 1); }), default => null, }; }); } return $skor; } public function index(Request $request) { if (!Gate::any(['super_admin', 'admin', 'fasilitator'])) { abort(403); } return redirect()->route('dashboard.profil-pertanian', array_merge($request->query(), [ 'tab' => 'indeks-petani', ])); } public function contentData(Request $request): array { $filters = $this->filters($request); $title = 'Dashboard Profil Petani'; $segments = $this->segments(); $colors = collect($segments) ->pluck('color') ->map(fn($c) => "var(--bs-{$c})") ->values(); $komoditas = Komoditas::where('is_utama', true)->get(); $petaniQuery = $this->petaniQuery($filters); $desaKelurahan = $petaniQuery->clone() ->selectRaw(" master_desa_kelurahan.id as desa_kelurahan_id, master_desa_kelurahan.nama as desa_kelurahan, master_desa_kelurahan.path as path, master_kecamatan.id as kecamatan_id, master_kecamatan.nama as kecamatan, master_kabupaten_kota.id as kabupaten_id, master_kabupaten_kota.nama as kabupaten, master_provinsi.id as provinsi_id, master_provinsi.nama as provinsi ") ->distinct() ->get(); $provinsi = $desaKelurahan ->unique('provinsi_id') ->sortBy('provinsi') ->values(); $wilayah = $desaKelurahan ->groupBy('provinsi_id') ->map(function ($provinsi) { return [ 'id' => $provinsi->first()->provinsi_id, 'nama' => $provinsi->first()->provinsi, 'kabupaten' => $provinsi ->groupBy('kabupaten_id') ->map(function ($kabupaten) { return [ 'id' => $kabupaten->first()->kabupaten_id, 'nama' => $kabupaten->first()->kabupaten, 'kecamatan' => $kabupaten ->groupBy('kecamatan_id') ->map(function ($kecamatan) { return [ 'id' => $kecamatan->first()->kecamatan_id, 'nama' => $kecamatan->first()->kecamatan, 'desa' => $kecamatan->map(function ($desa) { return [ 'id' => $desa->desa_kelurahan_id, 'nama' => $desa->desa_kelurahan, 'path' => $desa->path, ]; })->values(), ]; })->values(), ]; })->values(), ]; })->values(); return array_merge($filters, compact( 'komoditas', 'desaKelurahan', 'provinsi', 'wilayah', 'segments', 'colors', )); } public function summary(Request $request): JsonResponse { $filters = $this->filters($request); $petaniQuery = $this->petaniQuery($filters); $komoditas = Komoditas::where('is_utama', true) ->when($filters['komoditas_id'], fn($q, $id) => $q->where('id', $id))->get(); $countKomoditas = $petaniQuery->clone() ->whereHas('komoditas', fn ($query) => $query->where('is_utama', true)) ->distinct()->count('komoditas_id'); $filteredPetaniIds = $petaniQuery ->clone() ->select('petani.id') ->distinct() ->pluck('petani.id'); $sumLahan = Lahan::has('petani')->whereIn('petani_id', $filteredPetaniIds)->whereIn('komoditas_id', $komoditas->pluck('id'))->sum('luas_lahan'); $avgLahan = Lahan::has('petani')->whereIn('petani_id', $filteredPetaniIds)->whereIn('komoditas_id', $komoditas->pluck('id'))->avg('luas_lahan'); $countDesa = $petaniQuery->clone()->whereIn('komoditas_id', $komoditas->pluck('id'))->distinct()->count('desa_kelurahan_id'); $countKecamatan = $petaniQuery->clone()->whereIn('komoditas_id', $komoditas->pluck('id'))->distinct()->count('master_kecamatan.id'); $skorQuery = $this->skorPetaniQuery($filters, $komoditas->pluck('id')->toArray()); $avgSkor = $skorQuery->clone()->avg('skor_kesiapan_adopsi'); if ($avgSkor >= 4.0) { $avgSegmen = 'Penggerak'; } elseif ($avgSkor >= 3.0) { $avgSegmen = 'Perintis'; } elseif ($avgSkor >= 2.0) { $avgSegmen = 'Pemerhati'; } elseif ($avgSkor >= 1.0) { $avgSegmen = 'Pemula'; } else { $avgSegmen = 'Belum Lengkap'; } return response()->json([ 'petani' => $petaniQuery->clone()->count(), 'komoditas' => $countKomoditas, 'sum_lahan' => $sumLahan, 'avg_lahan' => $avgLahan, 'desa' => $countDesa, 'kecamatan' => $countKecamatan, 'skor' => $avgSkor, 'segmen' => $avgSegmen ]); } private function segments(): array { $segments = [ [ 'name' => 'Penggerak', 'range' => '4.0 - 5.0', 'icon' => 'tabler-crown', 'color' => 'success', ], [ 'name' => 'Perintis', 'range' => '3.0 - 3.9', 'icon' => 'tabler-flag', 'color' => 'info', ], [ 'name' => 'Pemerhati', 'range' => '2.0 - 2.9', 'icon' => 'tabler-eye', 'color' => 'warning', ], [ 'name' => 'Pemula', 'range' => '1.0 - 1.9', 'icon' => 'tabler-seedling', 'color' => 'danger', ], ]; return $segments; } private function cases(): string { $case = " CASE WHEN skor_kesiapan_adopsi >= 4.0 THEN 'Penggerak' WHEN skor_kesiapan_adopsi >= 3.0 THEN 'Perintis' WHEN skor_kesiapan_adopsi >= 2.0 THEN 'Pemerhati' WHEN skor_kesiapan_adopsi >= 1.0 THEN 'Pemula' ELSE 'Belum Lengkap' END "; return $case; } public function segmen(Request $request): JsonResponse { $filters = $this->filters($request); $segments = $this->segments(); $case = $this->cases(); $komoditas = Komoditas::where('is_utama', true) ->when($filters['komoditas_id'], fn($q, $id) => $q->where('id', $id))->get(); $skorQuery = $this->skorPetaniQuery($filters, $komoditas->pluck('id')->toArray()); $countSegmentasi = $skorQuery->clone() ->selectRaw("$case AS segmen, COUNT(*) AS total") ->groupByRaw($case) ->get(); $series = collect($segments) ->map(function ($segment) use ($countSegmentasi) { return $countSegmentasi ->where('segmen', $segment['name']) ->sum('total'); }) ->values(); $countPetani = $series->sum(); $persentase = collect($segments) ->map(function ($segment) use ($countSegmentasi, $countPetani) { $total = $countSegmentasi ->where('segmen', $segment['name']) ->sum('total'); return $countPetani > 0 ? ($total / $countPetani) * 100 : 0; }) ->values(); return response()->json([ 'series' => $series, 'persentase' => $persentase, ]); } public function segmenByKomoditas(Request $request): JsonResponse { $filters = $this->filters($request); $segments = $this->segments(); $case = $this->cases(); $komoditas = Komoditas::where('is_utama', true) ->when($filters['komoditas_id'], fn($q, $id) => $q->where('id', $id))->get(); $skorQuery = $this->skorPetaniQuery($filters, $komoditas->pluck('id')->toArray()); $countSegmentasiByKomoditas = $skorQuery->clone() ->selectRaw(" petani.komoditas_id, $case AS segmen, COUNT(petani.id) AS total ") ->groupBy('petani.komoditas_id') ->groupByRaw($case) ->get(); $seriesSegmentasiKomoditas = collect($segments)->map(function ($segment) use ($countSegmentasiByKomoditas, $komoditas) { return [ 'name' => $segment['name'], 'data' => $komoditas->map(function ($item) use ($countSegmentasiByKomoditas, $segment) { return optional( $countSegmentasiByKomoditas->first(function ($row) use ($item, $segment) { return $row->komoditas_id == $item->id && $row->segmen == $segment['name']; }) )->total ?? 0; })->values(), ]; })->values(); return response()->json([ 'categories' => $komoditas->pluck('nama')->values(), 'series' => $seriesSegmentasiKomoditas, ]); } public function dimensi(Request $request): JsonResponse { $filters = $this->filters($request); $komoditas = Komoditas::where('is_utama', true) ->when($filters['komoditas_id'], fn($q, $id) => $q->where('id', $id))->get(); $skorQuery = $this->skorPetaniQuery($filters, $komoditas->pluck('id')->toArray()); $avgDimensi = $skorQuery->clone() ->selectRaw(" avg(skor_d2_sistem_praktik_budidaya) as skor_d2_sistem_praktik_budidaya, avg(skor_d4_sosial_ekonomi) as skor_d4_sosial_ekonomi, avg(skor_d6_rantai_nilai_akses_pasar) as skor_d6_rantai_nilai_akses_pasar") ->first(); return response()->json([ 'radarDimensi' => [ round($avgDimensi->skor_d2_sistem_praktik_budidaya, 2), round($avgDimensi->skor_d4_sosial_ekonomi, 2), round($avgDimensi->skor_d6_rantai_nilai_akses_pasar, 2), ] ]); } public function komponen(Request $request): JsonResponse { $filters = $this->filters($request); $komoditas = Komoditas::where('is_utama', true) ->when($filters['komoditas_id'], fn($q, $id) => $q->where('id', $id))->get(); $skorQuery = $this->skorPetaniQuery($filters, $komoditas->pluck('id')->toArray()); $avgKomponen = $skorQuery->clone() ->selectRaw("avg(skor_komp_1_d4_k3_motivasi_kapasitas_adopsi) as skor_komp_1_d4_k3_motivasi_kapasitas_adopsi, avg(skor_komp_2_d4_k2_ekonomi_rumah_tangga) as skor_komp_2_d4_k2_ekonomi_rumah_tangga, avg(skor_komp_3_d2_praktik_budidaya_gap) as skor_komp_3_d2_praktik_budidaya_gap, avg(skor_komp_4_d4_k4_keterlibatan_kelembagaan) as skor_komp_4_d4_k4_keterlibatan_kelembagaan, avg(skor_komp_5_d4_k5_k6_akses_kebebasan_keuangan) as skor_komp_5_d4_k5_k6_akses_kebebasan_keuangan, avg(skor_komp_6_d6_k1_k4_k5_rantai_nilai_akses_pasar) as skor_komp_6_d6_k1_k4_k5_rantai_nilai_akses_pasar") ->first(); return response()->json([ 'radarKomponen' => [ round($avgKomponen->skor_komp_1_d4_k3_motivasi_kapasitas_adopsi, 2), round($avgKomponen->skor_komp_2_d4_k2_ekonomi_rumah_tangga, 2), round($avgKomponen->skor_komp_3_d2_praktik_budidaya_gap, 2), round($avgKomponen->skor_komp_4_d4_k4_keterlibatan_kelembagaan, 2), round($avgKomponen->skor_komp_5_d4_k5_k6_akses_kebebasan_keuangan, 2), round($avgKomponen->skor_komp_6_d6_k1_k4_k5_rantai_nilai_akses_pasar, 2) ] ]); } public function map(Request $request): JsonResponse { $filters = $this->filters($request); $segments = $this->segments(); $colors = collect($segments) ->pluck('color') ->map(fn($c) => "var(--bs-{$c})") ->values(); $segmentStyles = collect($segments)->keyBy('name'); $case = $this->cases(); $petaniQuery = $this->petaniQuery($filters); $desaKelurahan = $petaniQuery->clone() ->selectRaw(" master_desa_kelurahan.id as desa_kelurahan_id, master_desa_kelurahan.nama as desa_kelurahan, master_desa_kelurahan.path as path, master_kecamatan.id as kecamatan_id, master_kecamatan.nama as kecamatan, master_kabupaten_kota.id as kabupaten_id, master_kabupaten_kota.nama as kabupaten, master_provinsi.id as provinsi_id, master_provinsi.nama as provinsi ") ->distinct() ->get(); $komoditas = Komoditas::where('is_utama', true) ->when($filters['komoditas_id'], fn($q, $id) => $q->where('id', $id))->get(); $skorQuery = $this->skorPetaniQuery($filters, $komoditas->pluck('id')->toArray()); $mapSegmentasi = $skorQuery->clone() ->selectRaw("petani.desa_kelurahan_id, $case AS segmen, COUNT(petani.id) AS total ") ->groupBy('petani.desa_kelurahan_id') ->groupByRaw($case) ->get(); $mapAvgSkorSegmentasi = $skorQuery->clone() ->selectRaw("petani.desa_kelurahan_id, COUNT(petani.id) AS jumlah_petani, avg(skor_kesiapan_adopsi) AS skor, CASE WHEN AVG(skor_kesiapan_adopsi) >= 4 THEN 'Penggerak' WHEN AVG(skor_kesiapan_adopsi) >= 3 THEN 'Perintis' WHEN AVG(skor_kesiapan_adopsi) >= 2 THEN 'Pemerhati' WHEN AVG(skor_kesiapan_adopsi) >= 1 THEN 'Pemula' ELSE 'Belum Lengkap' END AS segmen ") ->groupBy('petani.desa_kelurahan_id') ->get(); $segmenDominan = $mapSegmentasi ->groupBy('desa_kelurahan_id') ->map(function ($items) { return $items->sortByDesc('total')->first(); }); $mapAvgSkorSegmentasi->each(function ($item) use ($segmenDominan) { $dominan = $segmenDominan->get($item->desa_kelurahan_id); $item->segmen_dominan = $dominan?->segmen; $item->jumlah_dominan = $dominan?->total; }); $segmentasiByDesa = $mapAvgSkorSegmentasi->keyBy('desa_kelurahan_id'); $desaLookup = $desaKelurahan->keyBy('desa_kelurahan_id'); $mapDesaSegmentasi = $segmentasiByDesa->map(function ($segmentasi, $desaId) use ($desaLookup) { $desa = $desaLookup->get($desaId); if (!$desa) { return null; } $desa->segmentasi = $segmentasi; return $desa; })->filter()->values(); return response()->json($mapDesaSegmentasi); } public function desa(Request $request): JsonResponse { $filters = $this->filters($request); $segments = $this->segments(); $colors = collect($segments) ->pluck('color') ->map(fn($c) => "var(--bs-{$c})") ->values(); $segmentStyles = collect($segments)->keyBy('name'); $case = $this->cases(); $petaniQuery = $this->petaniQuery($filters); $desaKelurahan = $petaniQuery->clone() ->selectRaw(" master_desa_kelurahan.id as desa_kelurahan_id, master_desa_kelurahan.nama as desa_kelurahan, master_desa_kelurahan.path as path, master_kecamatan.id as kecamatan_id, master_kecamatan.nama as kecamatan, master_kabupaten_kota.id as kabupaten_id, master_kabupaten_kota.nama as kabupaten, master_provinsi.id as provinsi_id, master_provinsi.nama as provinsi ") ->distinct() ->get(); $komoditas = Komoditas::where('is_utama', true) ->when($filters['komoditas_id'], fn($q, $id) => $q->where('id', $id))->get(); $skorQuery = $this->skorPetaniQuery($filters, $komoditas->pluck('id')->toArray()); $mapSegmentasi = $skorQuery->clone() ->selectRaw("petani.desa_kelurahan_id, $case AS segmen, COUNT(petani.id) AS total ") ->groupBy('petani.desa_kelurahan_id') ->groupByRaw($case) ->get(); $mapAvgSkorSegmentasi = $skorQuery->clone() ->selectRaw("petani.desa_kelurahan_id, COUNT(petani.id) AS jumlah_petani, avg(skor_kesiapan_adopsi) AS skor, CASE WHEN AVG(skor_kesiapan_adopsi) >= 4 THEN 'Penggerak' WHEN AVG(skor_kesiapan_adopsi) >= 3 THEN 'Perintis' WHEN AVG(skor_kesiapan_adopsi) >= 2 THEN 'Pemerhati' WHEN AVG(skor_kesiapan_adopsi) >= 1 THEN 'Pemula' ELSE 'Belum Lengkap' END AS segmen ") ->groupBy('petani.desa_kelurahan_id') ->get(); $segmenDominan = $mapSegmentasi ->groupBy('desa_kelurahan_id') ->map(function ($items) { return $items->sortByDesc('total')->first(); }); $mapAvgSkorSegmentasi->each(function ($item) use ($segmenDominan) { $dominan = $segmenDominan->get($item->desa_kelurahan_id); $item->segmen_dominan = $dominan?->segmen; $item->jumlah_dominan = $dominan?->total; }); $segmentasiByDesa = $mapAvgSkorSegmentasi->keyBy('desa_kelurahan_id'); $desaLookup = $desaKelurahan->keyBy('desa_kelurahan_id'); $mapDesaSegmentasi = $segmentasiByDesa->map(function ($segmentasi, $desaId) use ($desaLookup) { $desa = $desaLookup->get($desaId); if (!$desa) { return null; } $desa->segmentasi = $segmentasi; return $desa; })->filter()->values(); $rows = $mapDesaSegmentasi->map(function ($desa) use ($segmentStyles) { $style = $segmentStyles[$desa->segmentasi->segmen] ?? ['color' => 'secondary']; $styleDominan = $segmentStyles[$desa->segmentasi->segmen_dominan] ?? ['color' => 'secondary']; return [ 'desa' => $desa->desa_kelurahan, 'jumlah_petani' => $desa->segmentasi->jumlah_petani, 'segmen' => $desa->segmentasi->segmen, 'skor' => $desa->segmentasi->skor, 'segmen_dominan' => $desa->segmentasi->segmen_dominan, 'jumlah_dominan' => $desa->segmentasi->jumlah_dominan, 'color' => $style['color'], 'color_dominan' => $styleDominan['color'], ]; }); return response()->json($rows); } public function data(Request $request): JsonResponse { $filters = $this->filters($request); $segments = $this->segments(); $colors = collect($segments) ->pluck('color') ->map(fn($c) => "var(--bs-{$c})") ->values(); $segmentStyles = collect($segments)->keyBy('name'); $petaniQuery = $this->petaniQuery($filters); $komoditas = Komoditas::where('is_utama', true) ->when($filters['komoditas_id'], fn($q, $id) => $q->where('id', $id))->get(); $daftarPetani = $petaniQuery->clone() ->select('petani.*') ->whereIn('komoditas_id', $komoditas->pluck('id')) ->get(); $data = $daftarPetani ->filter(function ($item) use ($filters) { if (!$filters['segmen']) { return true; } $segmen = $item->skor ? $item->segmen() : 'Belum Lengkap'; return $segmen === $filters['segmen']; }) ->map(function ($item) use ($segmentStyles) { $segmen = $item->skor ? $item->segmen() : null; $style = $segmentStyles[$segmen] ?? ['color' => 'secondary']; return [ 'id' => $item->id, 'nama' => $item->nama, 'desa' => $item->desaKelurahan?->nama, 'desa_kelurahan_id' => $item->desa_kelurahan_id, 'komoditas' => $item->komoditas?->nama, 'luas_lahan' => $item->lahans?->sum('luas_lahan') ?? 0, 'skor' => $item->skor ? $item->skor->skor_kesiapan_adopsi : null, 'segmen' => $segmen, 'color' => $style['color'], 'url' => route('dashboard.profil-petani', $item->id), ]; }) ->values(); return response()->json($data); } }