This commit is contained in:
2026-08-27 11:48:55 +07:00
6 changed files with 2623 additions and 967 deletions
@@ -6,6 +6,9 @@ use App\Http\Controllers\Controller;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate; use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\JsonResponse;
use App\Models\Pertanian\Petani; use App\Models\Pertanian\Petani;
use App\Models\Pertanian\Komoditas; use App\Models\Pertanian\Komoditas;
@@ -13,41 +16,181 @@ use App\Models\Pertanian\Lahan;
use App\Models\Pertanian\Tanaman; use App\Models\Pertanian\Tanaman;
use App\Models\Pertanian\SkorPetani; use App\Models\Pertanian\SkorPetani;
use App\Models\Wilayah\Provinsi;
use App\Models\Wilayah\KabupatenKota;
use App\Models\Wilayah\Kecamatan;
use App\Models\Wilayah\DesaKelurahan;
class IndeksPetaniController extends Controller class IndeksPetaniController extends Controller
{ {
public function index()
private function filters(Request $request): array
{
return [
'desaKelurahan_id' => $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'])) { if (!Gate::any(['super_admin', 'admin', 'fasilitator'])) {
abort(403); abort(403);
} }
$filters = $this->filters($request);
$title = 'Dashboard Profil Petani'; $title = 'Dashboard Profil Petani';
$komoditas = Komoditas::where('is_utama', true)->get(); $komoditas = Komoditas::where('is_utama', true)->get();
$petaniQuery = $this->petaniQuery($filters);
$petani = Petani::pluck('id'); $desaKelurahan = $petaniQuery->clone()
$lahan = Lahan::has('petani')->get(); ->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();
$case = " $wilayah = $desaKelurahan
CASE ->groupBy('provinsi_id')
WHEN skor_kesiapan_adopsi >= 4.0 THEN 'Penggerak' ->map(function ($provinsi) {
WHEN skor_kesiapan_adopsi >= 3.0 THEN 'Perintis' return [
WHEN skor_kesiapan_adopsi >= 2.0 THEN 'Pemerhati' 'id' => $provinsi->first()->provinsi_id,
WHEN skor_kesiapan_adopsi >= 1.0 THEN 'Pemula' 'nama' => $provinsi->first()->provinsi,
ELSE 'Belum Lengkap' 'kabupaten' => $provinsi
END ->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();
$countPetani = Petani::count(); return view('dashboard.indeks-petani', array_merge($filters,
$countKomoditas = Petani::whereIn('komoditas_id', $komoditas->pluck('id'))->distinct()->count('komoditas_id'); compact(
$sumLahan = Lahan::has('petani')->whereIn('komoditas_id', $komoditas->pluck('id'))->sum('luas_lahan'); 'komoditas',
$avgLahan = Lahan::has('petani')->whereIn('komoditas_id', $komoditas->pluck('id'))->avg('luas_lahan'); 'desaKelurahan',
'wilayah',
)));
}
$avgSkor = SkorPetani::query() public function summary(Request $request): JsonResponse
->join('petani', 'petani_skor.petani_id', '=', 'petani.id') {
->whereNull('petani.deleted_at') $filters = $this->filters($request);
->whereIn('petani.komoditas_id', $komoditas->pluck('id')) $petaniQuery = $this->petaniQuery($filters);
->avg('skor_kesiapan_adopsi');
$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) { if ($avgSkor >= 4.0) {
$avgSegmen = 'Penggerak'; $avgSegmen = 'Penggerak';
@@ -61,19 +204,120 @@ class IndeksPetaniController extends Controller
$avgSegmen = 'Belum Lengkap'; $avgSegmen = 'Belum Lengkap';
} }
$countDesa = Petani::whereIn('komoditas_id', $komoditas->pluck('id'))->distinct()->count('desa_kelurahan_id'); return response()->json([
$countKecamatan = Petani::query() 'petani' => $petaniQuery->clone()->count(),
->join('master_desa_kelurahan', 'petani.desa_kelurahan_id', '=', 'master_desa_kelurahan.id') 'komoditas' => $countKomoditas,
->join('master_kecamatan', 'master_desa_kelurahan.kecamatan_id', '=', 'master_kecamatan.id') 'sum_lahan' => $sumLahan,
->whereIn('komoditas_id', $komoditas->pluck('id'))->distinct()->count('master_kecamatan.id'); 'avg_lahan' => $avgLahan,
'desa' => $countDesa,
'kecamatan' => $countKecamatan,
'skor' => $avgSkor,
'segmen' => $avgSegmen
]);
}
$countSegmentasi = SkorPetani::selectRaw("$case AS segmen, COUNT(*) AS total") 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) ->groupByRaw($case)
->get(); ->get();
$countSegmentasiByKomoditas = SkorPetani::query() $series = collect($segments)
->join('petani', 'petani_skor.petani_id', '=', 'petani.id') ->map(function ($segment) use ($countSegmentasi) {
->whereNull('petani.deleted_at') 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(" ->selectRaw("
petani.komoditas_id, petani.komoditas_id,
$case AS segmen, $case AS segmen,
@@ -83,20 +327,64 @@ class IndeksPetaniController extends Controller
->groupByRaw($case) ->groupByRaw($case)
->get(); ->get();
$avgDimensi = SkorPetani::query() $seriesSegmentasiKomoditas = collect($segments)->map(function ($segment) use ($countSegmentasiByKomoditas, $komoditas) {
->join('petani', 'petani_skor.petani_id', '=', 'petani.id') return [
->whereNull('petani.deleted_at') 'name' => $segment['name'],
->whereIn('petani.komoditas_id', $komoditas->pluck('id')) '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(" ->selectRaw("
avg(skor_d2_sistem_praktik_budidaya) as skor_d2_sistem_praktik_budidaya, avg(skor_d2_sistem_praktik_budidaya) as skor_d2_sistem_praktik_budidaya,
avg(skor_d4_sosial_ekonomi) as skor_d4_sosial_ekonomi, avg(skor_d4_sosial_ekonomi) as skor_d4_sosial_ekonomi,
avg(skor_d6_rantai_nilai_akses_pasar) as skor_d6_rantai_nilai_akses_pasar") avg(skor_d6_rantai_nilai_akses_pasar) as skor_d6_rantai_nilai_akses_pasar")
->first(); ->first();
$avgKomponen = SkorPetani::query() return response()->json([
->join('petani', 'petani_skor.petani_id', '=', 'petani.id') 'radarDimensi' => [
->whereNull('petani.deleted_at') round($avgDimensi->skor_d2_sistem_praktik_budidaya, 2),
->whereIn('petani.komoditas_id', $komoditas->pluck('id')) 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, ->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_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_3_d2_praktik_budidaya_gap) as skor_komp_3_d2_praktik_budidaya_gap,
@@ -105,11 +393,34 @@ class IndeksPetaniController extends Controller
avg(skor_komp_6_d6_k1_k4_k5_rantai_nilai_akses_pasar) as skor_komp_6_d6_k1_k4_k5_rantai_nilai_akses_pasar") 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(); ->first();
$desaKelurahan = Petani::query() return response()->json([
->join('master_desa_kelurahan', 'petani.desa_kelurahan_id', '=', 'master_desa_kelurahan.id') 'radarKomponen' => [
->join('master_kecamatan', 'master_desa_kelurahan.kecamatan_id', '=', 'master_kecamatan.id') round($avgKomponen->skor_komp_1_d4_k3_motivasi_kapasitas_adopsi, 2),
->join('master_kabupaten_kota', 'master_kecamatan.kabupaten_kota_id', '=', 'master_kabupaten_kota.id') round($avgKomponen->skor_komp_2_d4_k2_ekonomi_rumah_tangga, 2),
->join('master_provinsi', 'master_kabupaten_kota.provinsi_id', '=', 'master_provinsi.id') 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(" ->selectRaw("
master_desa_kelurahan.id as desa_kelurahan_id, master_desa_kelurahan.id as desa_kelurahan_id,
master_desa_kelurahan.nama as desa_kelurahan, master_desa_kelurahan.nama as desa_kelurahan,
@@ -121,13 +432,15 @@ class IndeksPetaniController extends Controller
master_provinsi.id as provinsi_id, master_provinsi.id as provinsi_id,
master_provinsi.nama as provinsi master_provinsi.nama as provinsi
") ")
->whereIn('petani.id', $petani)
->distinct() ->distinct()
->get(); ->get();
$mapSegmentasi = SkorPetani::query() $komoditas = Komoditas::where('is_utama', true)
->join('petani', 'petani_skor.petani_id', '=', 'petani.id') ->when($filters['komoditas_id'], fn($q, $id) => $q->where('id', $id))->get();
->whereNull('petani.deleted_at')
$skorQuery = $this->skorPetaniQuery($filters, $komoditas->pluck('id')->toArray());
$mapSegmentasi = $skorQuery->clone()
->selectRaw("petani.desa_kelurahan_id, ->selectRaw("petani.desa_kelurahan_id,
$case AS segmen, $case AS segmen,
COUNT(petani.id) AS total COUNT(petani.id) AS total
@@ -136,9 +449,7 @@ class IndeksPetaniController extends Controller
->groupByRaw($case) ->groupByRaw($case)
->get(); ->get();
$mapAvgSkorSegmentasi = SkorPetani::query() $mapAvgSkorSegmentasi = $skorQuery->clone()
->join('petani', 'petani_skor.petani_id', '=', 'petani.id')
->whereNull('petani.deleted_at')
->selectRaw("petani.desa_kelurahan_id, ->selectRaw("petani.desa_kelurahan_id,
COUNT(petani.id) AS jumlah_petani, COUNT(petani.id) AS jumlah_petani,
avg(skor_kesiapan_adopsi) AS skor, avg(skor_kesiapan_adopsi) AS skor,
@@ -153,28 +464,195 @@ class IndeksPetaniController extends Controller
->groupBy('petani.desa_kelurahan_id') ->groupBy('petani.desa_kelurahan_id')
->get(); ->get();
$daftarPetani = Petani::query() $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')) ->whereIn('komoditas_id', $komoditas->pluck('id'))
->get(); ->get();
return view('dashboard.indeks-petani', compact( $data = $daftarPetani
'komoditas', ->filter(function ($item) use ($filters) {
'countPetani', if (!$filters['segmen']) {
'countKomoditas', return true;
'sumLahan', }
'avgLahan', $segmen = $item->skor ? $item->segmen() : 'Belum Lengkap';
'avgSkor', return $segmen === $filters['segmen'];
'avgSegmen', })
'countDesa', ->map(function ($item) use ($segmentStyles) {
'countKecamatan', $segmen = $item->skor
'countSegmentasi', ? $item->segmen()
'countSegmentasiByKomoditas', : null;
'avgDimensi', $style = $segmentStyles[$segmen]
'avgKomponen', ?? ['color' => 'secondary'];
'desaKelurahan',
'mapSegmentasi', return [
'mapAvgSkorSegmentasi', 'id' => $item->id,
'daftarPetani', '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);
} }
} }
@@ -13,6 +13,11 @@ use App\Models\Pertanian\Lahan;
use App\Models\Pertanian\Tanaman; use App\Models\Pertanian\Tanaman;
use App\Models\Pertanian\PraktikBudidaya; use App\Models\Pertanian\PraktikBudidaya;
use App\Models\Pertanian\SurveyPanen; use App\Models\Pertanian\SurveyPanen;
use App\Models\Pertanian\SosialEkonomi;
use App\Models\Pertanian\SurveyPelatihan;
use App\Models\Pertanian\SurveySertifikasi;
use App\Models\Pertanian\AksesPasar;
use App\Models\Pertanian\HargaJualPanen;
use App\Models\Pertanian\PendapatanKomoditas; use App\Models\Pertanian\PendapatanKomoditas;
use App\Models\Wilayah\DesaKelurahan; use App\Models\Wilayah\DesaKelurahan;
use App\Models\Profile; use App\Models\Profile;
@@ -23,6 +28,15 @@ use App\Enums\PraktikBudidaya\MetodePenangananHamaPenyakit;
use App\Enums\PraktikBudidaya\FrekuensiSanitasiLahan; use App\Enums\PraktikBudidaya\FrekuensiSanitasiLahan;
use App\Enums\PraktikBudidaya\PenangananGulma; use App\Enums\PraktikBudidaya\PenangananGulma;
use App\Enums\PraktikBudidaya\KondisiPengelolaanAir; use App\Enums\PraktikBudidaya\KondisiPengelolaanAir;
use App\Enums\SosialEkonomi\SkorKecukupanPenghasilan;
use App\Enums\SosialEkonomi\SkorKemampuanMenabung;
use App\Enums\SosialEkonomi\TerdaftarKelompokTani;
use App\Enums\SosialEkonomi\PeranDalamKelompok;
use App\Enums\SosialEkonomi\StatusRekeningTabungan;
use App\Enums\SosialEkonomi\PengalamanKreditKebun;
use App\Enums\SosialEkonomi\KeterikatanHutangPanen;
use App\Enums\SosialEkonomi\PraktikIjon;
use App\Enums\SosialEkonomi\KebebasanMemilihPembeli;
class ProfilPetaniController extends Controller class ProfilPetaniController extends Controller
{ {
@@ -62,6 +76,7 @@ class ProfilPetaniController extends Controller
$praktikBudidaya = PraktikBudidaya::where('petani_id', $petani->id)->first(); $praktikBudidaya = PraktikBudidaya::where('petani_id', $petani->id)->first();
$surveyPanen = SurveyPanen::where('petani_id', $petani->id)->first(); $surveyPanen = SurveyPanen::where('petani_id', $petani->id)->first();
$sosialEkonomi = SosialEkonomi::where('petani_id', $id)->first();
$indikatorOnFarm = collect(); $indikatorOnFarm = collect();
@@ -145,6 +160,280 @@ class ProfilPetaniController extends Controller
'konservasi_tanah' => $praktikBudidaya?->kebiasaan_konservasi_tanah ?? [], 'konservasi_tanah' => $praktikBudidaya?->kebiasaan_konservasi_tanah ?? [],
]; ];
$d4SosialEkonomi = null;
$terdaftarKelompok = $sosialEkonomi->terdaftar_kelompok_tani;
$peranKelompok = $sosialEkonomi->peran_dalam_kelompok;
if ($sosialEkonomi) {
$kecukupanPenghasilan = $sosialEkonomi->skor_kecukupan_penghasilan;
$kemampuanMenabung = $sosialEkonomi->skor_kemampuan_menabung;
$rekening = $sosialEkonomi->status_rekening_tabungan;
$kredit = $sosialEkonomi->pengalaman_kredit_kebun;
$hutangPanen = $sosialEkonomi->keterikatan_hutang_panen;
$ijon = $sosialEkonomi->praktik_ijon;
$programKeuanganRaw = $sosialEkonomi->status_program_keuangan_formal ?? [];
$namaProgram = [
'pkh' => 'PKH',
'blt' => 'BLT',
'kur' => 'KUR',
'kredit_koperasi_resmi' => 'Kredit Koperasi',
'credit_union_cu' => 'Credit Union (CU)',
'pinjaman_bumdes' => 'Pinjaman BUMDes',
'modal_hibah_dinas_pertanian' => 'Hibah Dinas Pertanian',
];
$programBantuan = collect($programKeuanganRaw)->map(function ($status, $key) use ($namaProgram) {
$statusMeta = match ($status) {
'sedang_menerima' => [
'label' => 'Sedang Menerima',
'short' => 'Aktif',
'color' => 'success',
'icon' => 'tabler-circle-check',
],
'pernah_tapi_tidak_lagi' => [
'label' => 'Pernah, Tidak Lagi',
'short' => 'Pernah',
'color' => 'info',
'icon' => 'tabler-history',
],
'belum_pernah' => [
'label' => 'Belum Pernah',
'short' => 'Belum Pernah',
'color' => 'secondary',
'icon' => 'tabler-minus',
],
default => [
'label' => Str::headline($status),
'short' => Str::headline($status),
'color' => 'secondary',
'icon' => 'tabler-help-circle',
],
};
return [
'key' => $key,
'nama' => $namaProgram[$key] ?? Str::headline($key),
'status' => $status,
'label' => $statusMeta['label'],
'short' => $statusMeta['short'],
'color' => $statusMeta['color'],
'icon' => $statusMeta['icon'],
];
})
->values();
$d4SosialEkonomi = [
'jumlah_tanggungan' => $sosialEkonomi->jumlah_tanggungan,
'kecukupan_penghasilan' => [
'skor' => $kecukupanPenghasilan?->value,
'label' => $kecukupanPenghasilan?->label(),
'color' => $this->getScoreColor(
$kecukupanPenghasilan?->value
),
],
'kemampuan_menabung' => [
'skor' => $kemampuanMenabung?->value,
'label' => $kemampuanMenabung?->label(),
'color' => $this->getScoreColor(
$kemampuanMenabung?->value
),
],
'status_kepemilikan_lahan' => $sosialEkonomi->status_kepemilikan_lahan,
'kelembagaan' => [
'terdaftar' =>
$terdaftarKelompok === TerdaftarKelompokTani::YA,
'status' =>
$terdaftarKelompok?->label(),
'peran' =>
$peranKelompok?->label(),
],
'kondisi_keuangan' => [
'rekening' => [
'label' => $rekening?->label(),
'value' => $rekening?->value,
'color' => $this->getFinancialColor(
$rekening?->value
),
'icon' => 'tabler-building-bank',
],
'kredit' => [
'label' => $kredit?->label(),
'value' => $kredit?->value,
'color' => $this->getFinancialColor(
$kredit?->value
),
'icon' => 'tabler-credit-card',
],
'hutang_panen' => [
'label' => $hutangPanen?->label(),
'value' => $hutangPanen?->value,
'color' => $this->getFinancialColor(
$hutangPanen?->value
),
'icon' => 'tabler-coins',
],
'ijon' => [
'label' => $ijon?->label(),
'value' => $ijon?->value,
'color' => $this->getFinancialColor(
$ijon?->value
),
'icon' => 'tabler-link',
],
],
'program_bantuan' => $programBantuan,
];
}
$surveyPelatihan = SurveyPelatihan::where('petani_id', $id)
->orderByDesc('tahun_pelaksanaan')
->get();
$surveySertifikasi = SurveySertifikasi::where('petani_id', $id)
->orderByDesc('tahun_pelaksanaan')
->get();
$aksesPasar = AksesPasar::where('petani_id', $id)->first();
$saluranTerdahulu = collect($aksesPasar?->saluran_terdahulu ?? [] );
$d6SaluranPasar = [
[
'key' => 'tengkulak',
'label' => 'Tengkulak',
'icon' => 'tabler-user-dollar',
'aktif' => $saluranTerdahulu->contains(
fn ($item) => Str::contains(
Str::lower($item),
['tengkulak', 'pedagang lokal']
)
),
],
[
'key' => 'koperasi',
'label' => 'Koperasi',
'icon' => 'tabler-users-group',
'aktif' => $saluranTerdahulu->contains(
fn ($item) => Str::contains(
Str::lower($item),
'koperasi'
)
),
],
[
'key' => 'bumdes',
'label' => 'BUMDes',
'icon' => 'tabler-building-community',
'aktif' => $saluranTerdahulu->contains(
fn ($item) => Str::contains(
Str::lower($item),
'bumdes'
)
),
],
[
'key' => 'eksportir',
'label' => 'Eksportir',
'icon' => 'tabler-plane-departure',
'aktif' => $saluranTerdahulu->contains(
fn ($item) => Str::contains(
Str::lower($item),
'eksportir'
)
),
],
];
$hargaJualPanen = HargaJualPanen::where('petani_id', $id)->get();
$d6HargaJual = $hargaJualPanen->map(function ($item) {
$hargaSekarang = $item->harga_panen_terakhir !== null
? (float) $item->harga_panen_terakhir
: null;
$hargaTahunLalu = $item->harga_tahun_lalu !== null
? (float) $item->harga_tahun_lalu
: null;
$perubahan = null;
if (
$hargaSekarang !== null &&
$hargaTahunLalu !== null &&
$hargaTahunLalu > 0
) {
$perubahan = (
($hargaSekarang - $hargaTahunLalu)
/ $hargaTahunLalu
) * 100;
}
return [
'bentuk_produk' => $item->bentuk_produk,
'harga_sekarang' => $hargaSekarang,
'harga_tahun_lalu' => $hargaTahunLalu,
'harga_dua_tahun_lalu' =>
$item->harga_dua_tahun_lalu !== null
? (float) $item->harga_dua_tahun_lalu
: null,
'perubahan' => $perubahan,
'trend' => match (true) {
$perubahan === null => 'neutral',
$perubahan > 0 => 'up',
$perubahan < 0 => 'down',
default => 'stable',
},
];
});
$kebebasanPembeli = $sosialEkonomi?->kebebasan_memilih_pembeli;
$d6RantaiNilai = [
'saluran_pasar' => $d6SaluranPasar,
'harga_jual' => $d6HargaJual,
'kebebasan_memilih_pembeli' => [
'skor' => $kebebasanPembeli?->value,
'label' => $kebebasanPembeli?->label(),
'persentase' => $kebebasanPembeli
? ($kebebasanPembeli->value / 5) * 100
: 0,
'color' => $this->getScoreColor(
$kebebasanPembeli?->value
),
],
];
$data = [ $data = [
'petani' => $petani, 'petani' => $petani,
'skorPetani' => $skorPetani, 'skorPetani' => $skorPetani,
@@ -161,6 +450,16 @@ class ProfilPetaniController extends Controller
'praktikBudidaya' => $praktikBudidaya, 'praktikBudidaya' => $praktikBudidaya,
'indikatorOnFarm' => $indikatorOnFarm, 'indikatorOnFarm' => $indikatorOnFarm,
'detailOnFarm' => $detailOnFarm, 'detailOnFarm' => $detailOnFarm,
'sosialEkonomi' => $sosialEkonomi,
'd4SosialEkonomi' => $d4SosialEkonomi,
'surveyPelatihan' => $surveyPelatihan,
'surveySertifikasi' => $surveySertifikasi,
'aksesPasar' => $aksesPasar,
'd6SaluranPasar' => $d6SaluranPasar,
'hargaJualPanen' => $hargaJualPanen,
'd6HargaJual' => $d6HargaJual,
'kebebasanPembeli' => $kebebasanPembeli,
'd6RantaiNilai' => $d6RantaiNilai
]; ];
return view('produktivitas.profil-petani.index', $data); return view('produktivitas.profil-petani.index', $data);
} }
@@ -180,6 +479,20 @@ class ProfilPetaniController extends Controller
}; };
} }
private function getFinancialColor(?int $score): string
{
if ($score === null || $score === 0) {
return 'secondary';
}
return match (true) {
$score >= 5 => 'success',
$score >= 4 => 'info',
$score >= 2 => 'warning',
default => 'danger',
};
}
private function buildProfiling(SkorPetani $skorPetani): array private function buildProfiling(SkorPetani $skorPetani): array
{ {
$skorAkhir = $this->normalizeScore($skorPetani->skor_kesiapan_adopsi); $skorAkhir = $this->normalizeScore($skorPetani->skor_kesiapan_adopsi);
File diff suppressed because it is too large Load Diff
@@ -14,41 +14,37 @@
margin-bottom: .35rem; margin-bottom: .35rem;
} }
.indicator-filter-row {
padding-bottom: 1.5rem;
padding-top: 1.5rem;
}
.indicator-filter-bar { .indicator-filter-bar {
align-items: end; display: block;
}
.indicator-filter-line {
align-items: center;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: .75rem; gap: .5rem;
margin-bottom: 1.25rem;
} }
.indicator-filter-group { .indicator-filter-section-label {
flex: 1 1 150px; align-items: center;
min-width: 150px;
}
.indicator-filter-actions {
display: flex; display: flex;
flex: 999 1 240px; font-weight: 500;
gap: .75rem; margin-right: .5rem;
justify-content: space-between; white-space: nowrap;
} }
.indicator-filter-primary-actions { .indicator-filter-export-action {
display: flex; margin-left: auto;
gap: .75rem;
}
.indicator-filter-label {
color: var(--bs-body-color);
font-size: .75rem;
font-weight: 600;
margin-bottom: .3rem;
} }
.indicator-filter-bar .form-select, .indicator-filter-bar .form-select,
.indicator-filter-bar .btn { .indicator-filter-bar .btn {
min-height: 38px; min-height: 31px;
} }
.indicator-filter-bar .form-select { .indicator-filter-bar .form-select {
@@ -56,15 +52,10 @@
border-color: var(--bs-border-color); border-color: var(--bs-border-color);
border-radius: var(--bs-border-radius); border-radius: var(--bs-border-radius);
color: var(--bs-body-color); color: var(--bs-body-color);
font-size: .8125rem;
padding-bottom: .375rem;
padding-top: .375rem;
} }
.indicator-filter-bar .btn { .indicator-filter-bar .btn {
font-size: .8125rem; white-space: nowrap;
padding-bottom: .375rem;
padding-top: .375rem;
} }
.indicator-filter-bar .form-select:focus { .indicator-filter-bar .form-select:focus {
@@ -90,29 +81,16 @@
color: var(--bs-body-color); color: var(--bs-body-color);
display: flex; display: flex;
font-size: .8125rem; font-size: .8125rem;
min-height: 38px; min-height: 31px;
padding: .375rem .75rem; padding: .25rem .75rem;
} }
.indicator-filter-bar .input-group-text { .indicator-filter-bar .input-group-text {
background: var(--bs-paper-bg); background: var(--bs-paper-bg);
border-color: var(--bs-border-color); border-color: var(--bs-border-color);
color: var(--bs-secondary-color); color: var(--bs-secondary-color);
padding-left: .625rem; padding-left: .5rem;
padding-right: .625rem; padding-right: .5rem;
}
.indicator-export-btn {
border-color: #28a745;
color: #28a745;
white-space: nowrap;
}
.indicator-export-btn:hover,
.indicator-export-btn:focus {
background: rgba(40, 167, 69, .08);
border-color: #28a745;
color: #28a745;
} }
.indicator-summary-value { .indicator-summary-value {
@@ -190,16 +168,18 @@
} }
@media (max-width: 767.98px) { @media (max-width: 767.98px) {
.indicator-filter-bar, .indicator-filter-line {
.indicator-filter-actions,
.indicator-filter-primary-actions {
display: grid; display: grid;
grid-template-columns: 1fr; grid-template-columns: 1fr;
width: 100%; width: 100%;
} }
.indicator-filter-group { .indicator-filter-section-label {
min-width: 100%; margin-right: 0;
}
.indicator-filter-export-action {
margin-left: 0;
} }
.indicator-filter-bar .btn { .indicator-filter-bar .btn {
@@ -225,18 +205,27 @@
</p> </p>
</div> </div>
<div class="indicator-filter-bar" id="indicator-filter-bar" aria-label="Filter dashboard indikator pertanian"> @php
@foreach ($filterOptions as $filter) $filtersByKey = collect($filterOptions)->keyBy('key');
<div class="indicator-filter-group"> @endphp
<label for="filter-{{ $filter['key'] }}" class="indicator-filter-label">
{{ $filter['label'] }}
</label>
@if (!empty($filter['icon'])) <div class="row g-6 indicator-filter-row">
<div class="input-group"> <div class="col-12">
<span class="input-group-text" aria-hidden="true"> <div class="card card-border-shadow-primary">
<i class="ti {{ $filter['icon'] }}"></i> <div class="card-body py-3">
</span> <div class="indicator-filter-bar" id="indicator-filter-bar" aria-label="Filter dashboard indikator pertanian">
<div class="indicator-filter-line">
<div class="indicator-filter-section-label">
<i class="icon-base ti tabler-map-2 me-2"></i>
<span>Wilayah</span>
</div>
@foreach (['kabupaten', 'kecamatan', 'desa'] as $filterKey)
@php
$filter = $filtersByKey[$filterKey];
@endphp
<div class="filter-item">
@if (!empty($filter['readonly'])) @if (!empty($filter['readonly']))
@php @php
$selectedOption = collect($filter['options']) $selectedOption = collect($filter['options'])
@@ -245,7 +234,7 @@
<div <div
id="filter-{{ $filter['key'] }}" id="filter-{{ $filter['key'] }}"
class="form-control indicator-filter-static" class="form-control form-control-sm indicator-filter-static"
data-filter-key="{{ $filter['key'] }}" data-filter-key="{{ $filter['key'] }}"
data-filter-value="{{ $initialFilters[$filter['key']] }}" data-filter-value="{{ $initialFilters[$filter['key']] }}"
aria-label="Filter {{ $filter['label'] }}" aria-label="Filter {{ $filter['label'] }}"
@@ -256,25 +245,7 @@
@else @else
<select <select
id="filter-{{ $filter['key'] }}" id="filter-{{ $filter['key'] }}"
class="form-select indicator-filter-select" class="form-select form-select-sm indicator-filter-select"
data-filter-key="{{ $filter['key'] }}"
aria-label="Filter {{ $filter['label'] }}"
>
@foreach ($filter['options'] as $option)
<option
value="{{ $option['value'] }}"
@selected($initialFilters[$filter['key']] === $option['value'])
>
{{ $option['label'] }}
</option>
@endforeach
</select>
@endif
</div>
@else
<select
id="filter-{{ $filter['key'] }}"
class="form-select indicator-filter-select"
data-filter-key="{{ $filter['key'] }}" data-filter-key="{{ $filter['key'] }}"
aria-label="Filter {{ $filter['label'] }}" aria-label="Filter {{ $filter['label'] }}"
@disabled($filter['key'] === 'desa' && $initialFilters['kecamatan'] === 'all') @disabled($filter['key'] === 'desa' && $initialFilters['kecamatan'] === 'all')
@@ -292,31 +263,77 @@
@endif @endif
</div> </div>
@endforeach @endforeach
</div>
<hr class="my-3">
<div class="indicator-filter-line">
<div class="indicator-filter-section-label">
<i class="icon-base ti tabler-adjustments-horizontal me-2"></i>
<span>Data</span>
</div>
@foreach (['komoditas', 'segmentasi'] as $filterKey)
@php
$filter = $filtersByKey[$filterKey];
@endphp
<div class="filter-item">
<select
id="filter-{{ $filter['key'] }}"
class="form-select form-select-sm indicator-filter-select"
data-filter-key="{{ $filter['key'] }}"
aria-label="Filter {{ $filter['label'] }}"
>
@foreach ($filter['options'] as $option)
<option
value="{{ $option['value'] }}"
@selected($initialFilters[$filter['key']] === $option['value'])
>
{{ $option['label'] }}
</option>
@endforeach
</select>
</div>
@endforeach
<div class="indicator-filter-actions">
<div class="indicator-filter-primary-actions">
<button <button
type="button" type="button"
class="btn btn-outline-secondary" class="btn btn-outline-secondary btn-sm"
id="indicator-apply-filter"
aria-label="Terapkan filter indikator pertanian"
>
<i class="icon-base ti tabler-filter me-1"></i>
Filter
</button>
<button
type="button"
class="btn btn-outline-secondary btn-sm"
id="indicator-reset-filter" id="indicator-reset-filter"
aria-label="Reset filter indikator pertanian" aria-label="Reset filter indikator pertanian"
> >
<i class="ti tabler-rotate-clockwise-2 me-1"></i> <i class="icon-base ti tabler-refresh me-1"></i>
Reset Filter Reset
</button> </button>
</div>
<div class="indicator-filter-export-action">
<button <button
type="button" type="button"
class="btn btn-outline-success indicator-export-btn" class="btn btn-outline-secondary btn-sm"
id="indicator-export-data" id="indicator-export-data"
aria-label="Export data indikator pertanian" aria-label="Export data indikator pertanian"
> >
<i class="ti tabler-download me-1"></i> <i class="icon-base ti tabler-download me-1"></i>
Export Data Export Data
</button> </button>
</div> </div>
</div> </div>
</div>
</div>
</div>
</div>
</div>
<div class="row g-6" id="indicator-summary-row"> <div class="row g-6" id="indicator-summary-row">
@foreach ($summaryData as $summary) @foreach ($summaryData as $summary)
@@ -685,6 +702,7 @@
const komoditasSelect = document.querySelector('[data-filter-key="komoditas"]'); const komoditasSelect = document.querySelector('[data-filter-key="komoditas"]');
const segmentasiSelect = document.querySelector('[data-filter-key="segmentasi"]'); const segmentasiSelect = document.querySelector('[data-filter-key="segmentasi"]');
const selectedKabupaten = kabupatenFilter?.dataset.filterValue || initialFilters.kabupaten || 'all'; const selectedKabupaten = kabupatenFilter?.dataset.filterValue || initialFilters.kabupaten || 'all';
const applyFilterButton = document.getElementById('indicator-apply-filter');
const resetButton = document.getElementById('indicator-reset-filter'); const resetButton = document.getElementById('indicator-reset-filter');
const exportButton = document.getElementById('indicator-export-data'); const exportButton = document.getElementById('indicator-export-data');
const chartInstances = {}; const chartInstances = {};
@@ -729,6 +747,10 @@
resetButton.disabled = isLoading; resetButton.disabled = isLoading;
} }
if (applyFilterButton) {
applyFilterButton.disabled = isLoading;
}
if (exportButton) { if (exportButton) {
exportButton.disabled = isLoading; exportButton.disabled = isLoading;
} }
@@ -970,11 +992,13 @@
filters.desa = 'all'; filters.desa = 'all';
await loadDesaOptions('all'); await loadDesaOptions('all');
} }
loadIndicatorData();
}); });
}); });
applyFilterButton?.addEventListener('click', function () {
loadIndicatorData();
});
resetButton?.addEventListener('click', async function () { resetButton?.addEventListener('click', async function () {
Object.assign(filters, { Object.assign(filters, {
kecamatan: 'all', kecamatan: 'all',
File diff suppressed because it is too large Load Diff
+8
View File
@@ -52,6 +52,14 @@ Route::middleware('auth')
Route::get('/dashboard/petani/indikator-pertanian', [App\Http\Controllers\Web\Dashboard\IndikatorPertanianController::class, 'index'])->name('dashboard.indikator-pertanian'); Route::get('/dashboard/petani/indikator-pertanian', [App\Http\Controllers\Web\Dashboard\IndikatorPertanianController::class, 'index'])->name('dashboard.indikator-pertanian');
Route::get('/dashboard/petani/indeks', [App\Http\Controllers\Web\Dashboard\IndeksPetaniController::class, 'index'])->name('dashboard.indeks-petani'); Route::get('/dashboard/petani/indeks', [App\Http\Controllers\Web\Dashboard\IndeksPetaniController::class, 'index'])->name('dashboard.indeks-petani');
Route::get('/dashboard/petani/indeks/summary', [App\Http\Controllers\Web\Dashboard\IndeksPetaniController::class, 'summary'])->name('dashboard.indeks-petani.summary');
Route::get('/dashboard/petani/indeks/segmen', [App\Http\Controllers\Web\Dashboard\IndeksPetaniController::class, 'segmen'])->name('dashboard.indeks-petani.segmen');
Route::get('/dashboard/petani/indeks/segmen/komoditas', [App\Http\Controllers\Web\Dashboard\IndeksPetaniController::class, 'segmenByKomoditas'])->name('dashboard.indeks-petani.segmen.komoditas');
Route::get('/dashboard/petani/indeks/dimensi', [App\Http\Controllers\Web\Dashboard\IndeksPetaniController::class, 'dimensi'])->name('dashboard.indeks-petani.dimensi');
Route::get('/dashboard/petani/indeks/komponen', [App\Http\Controllers\Web\Dashboard\IndeksPetaniController::class, 'komponen'])->name('dashboard.indeks-petani.komponen');
Route::get('/dashboard/petani/indeks/map', [App\Http\Controllers\Web\Dashboard\IndeksPetaniController::class, 'map'])->name('dashboard.indeks-petani.map');
Route::get('/dashboard/petani/indeks/desa', [App\Http\Controllers\Web\Dashboard\IndeksPetaniController::class, 'desa'])->name('dashboard.indeks-petani.desa');
Route::get('/dashboard/petani/indeks/data', [App\Http\Controllers\Web\Dashboard\IndeksPetaniController::class, 'data'])->name('dashboard.indeks-petani.data');
Route::get('/dashboard/profil/petani/{id}',[App\Http\Controllers\Web\Produktivitas\ProfilPetaniController::class, 'index'])->name('dashboard.profil-petani'); Route::get('/dashboard/profil/petani/{id}',[App\Http\Controllers\Web\Produktivitas\ProfilPetaniController::class, 'index'])->name('dashboard.profil-petani');