From 0b333ab4e98712471f80de3d7f2784265825cafd Mon Sep 17 00:00:00 2001 From: ahmadafriadi Date: Wed, 12 Aug 2026 17:33:53 +0700 Subject: [PATCH] Update Profil Detail Petani --- .../Produktivitas/ProfilPetaniController.php | 432 ++++++++++++ .../profil-petani/index.blade.php | 651 ++++++++++++++++++ routes/web.php | 4 +- 3 files changed, 1086 insertions(+), 1 deletion(-) create mode 100644 app/Http/Controllers/Web/Produktivitas/ProfilPetaniController.php create mode 100644 resources/views/produktivitas/profil-petani/index.blade.php diff --git a/app/Http/Controllers/Web/Produktivitas/ProfilPetaniController.php b/app/Http/Controllers/Web/Produktivitas/ProfilPetaniController.php new file mode 100644 index 0000000..e73552e --- /dev/null +++ b/app/Http/Controllers/Web/Produktivitas/ProfilPetaniController.php @@ -0,0 +1,432 @@ +first(); + $enumerator = Profile::where('user_id', $petani->created_by)->first(); + $komoditas = Komoditas::where('id', $petani->komoditas_id)->get(); + $lahan = Lahan::where('petani_id', $id )->get(); + + $desaKelurahan = DesaKelurahan::with('kecamatan') + ->where('id', $petani->desa_kelurahan_id) + ->first(); + + $ktpMasked = $petani->ktp ? Str::mask($petani->ktp, '*', 4, -4) : '-'; + $profiling = $skorPetani ? $this->buildProfiling($skorPetani) : null; + + $data = [ + 'petani' => $petani, + 'skorPetani' => $skorPetani, + 'enumerator' => $enumerator, + 'komoditas' => $komoditas, + 'lahan' => $lahan, + 'desaKelurahan' => $desaKelurahan, + 'ktpMasked' => $ktpMasked, + 'profiling' => $profiling, + ]; + return view('produktivitas.profil-petani.index', $data); + } + + private function buildProfiling(SkorPetani $skorPetani): array + { + $skorAkhir = $this->normalizeScore($skorPetani->skor_kesiapan_adopsi); + $segmen = $this->getSegmen($skorAkhir); + + $dimensions = [ + 'd2' => [ + 'kode' => 'D2', + 'nama' => 'Sistem & Praktik Budidaya', + 'skor' => $this->normalizeScore( + $skorPetani->skor_d2_sistem_praktik_budidaya + ), + ], + + 'd4' => [ + 'kode' => 'D4', + 'nama' => 'Sosial-Ekonomi Rumah Tangga', + 'skor' => $this->normalizeScore( + $skorPetani->skor_d4_sosial_ekonomi + ), + ], + + 'd6' => [ + 'kode' => 'D6', + 'nama' => 'Rantai Nilai & Akses Pasar', + 'skor' => $this->normalizeScore( + $skorPetani->skor_d6_rantai_nilai_akses_pasar + ), + ], + ]; + + foreach ($dimensions as $key => $dimension) { + $dimensions[$key]['level'] = $this->getDimensionLevel($dimension['skor']); + } + + $components = collect([ + [ + 'key' => 'motivasi', + 'nama' => 'Motivasi & Kapasitas Adopsi', + 'short' => 'Motivasi', + 'dimensi' => 'D4', + 'bobot' => 25, + 'icon' => 'tabler-bulb', + 'skor' => $this->normalizeScore($skorPetani->skor_komp_1_d4_k3_motivasi_kapasitas_adopsi), + ], + + [ + 'key' => 'ekonomi', + 'nama' => 'Kondisi Ekonomi Rumah Tangga', + 'short' => 'Ekonomi', + 'dimensi' => 'D4', + 'bobot' => 20, + 'icon' => 'tabler-home-dollar', + 'skor' => $this->normalizeScore($skorPetani->skor_komp_2_d4_k2_ekonomi_rumah_tangga), + ], + + [ + 'key' => 'gap', + 'nama' => 'Praktik Budidaya & GAP', + 'short' => 'Budidaya / GAP', + 'dimensi' => 'D2', + 'bobot' => 20, + 'icon' => 'tabler-plant-2', + 'skor' => $this->normalizeScore($skorPetani->skor_komp_3_d2_praktik_budidaya_gap), + ], + + [ + 'key' => 'kelembagaan', + 'nama' => 'Keterlibatan Kelembagaan', + 'short' => 'Kelembagaan', + 'dimensi' => 'D4', + 'bobot' => 15, + 'icon' => 'tabler-users-group', + 'skor' => $this->normalizeScore($skorPetani->skor_komp_4_d4_k4_keterlibatan_kelembagaan), + ], + + [ + 'key' => 'keuangan', + 'nama' => 'Akses & Kebebasan Keuangan', + 'short' => 'Keuangan', + 'dimensi' => 'D4', + 'bobot' => 10, + 'icon' => 'tabler-building-bank', + 'skor' => $this->normalizeScore($skorPetani->skor_komp_5_d4_k5_k6_akses_kebebasan_keuangan), + ], + + [ + 'key' => 'pasar', + 'nama' => 'Rantai Nilai & Akses Pasar', + 'short' => 'Akses Pasar', + 'dimensi' => 'D6', + 'bobot' => 10, + 'icon' => 'tabler-building-store', + 'skor' => $this->normalizeScore($skorPetani->skor_komp_6_d6_k1_k4_k5_rantai_nilai_akses_pasar), + ], + ]); + + $availableComponents = $components + ->filter(fn ($item) => $item['skor'] !== null) + ->values(); + + $strengths = $availableComponents + ->sortByDesc('skor') + ->take(2) + ->values(); + + $barriers = $availableComponents + ->filter(fn ($item) => $item['skor'] < 3) + ->sortBy('skor') + ->values(); + + $specialPattern = $this->detectSpecialPattern( + $segmen, + $dimensions, + $skorPetani + ); + + $title = $this->buildProfileTitle( + $segmen, + $specialPattern, + $barriers + ); + + $narrative = $this->buildNarrative( + $segmen, + $specialPattern, + $strengths, + $barriers + ); + + $recommendations = $this->buildRecommendations( + $specialPattern, + $barriers + ); + + return [ + 'skor_akhir' => $skorAkhir, + 'segmen' => $segmen, + 'title' => $title, + 'dimensions' => $dimensions, + 'components' => $components, + 'strengths' => $strengths, + 'barriers' => $barriers, + 'special_pattern' => $specialPattern, + 'narrative' => $narrative, + 'recommendations' => $recommendations, + ]; + } + + private function normalizeScore($score): ?float + { + if ($score === null || $score === '') { + return null; + } + + $score = (float) $score; + + if ($score <= 0) { + return null; + } + + return $score; + } + + private function getSegmen(?float $score): string + { + if ($score === null) { + return 'Belum Dinilai'; + } + + return match (true) { + $score >= 4.0 => 'Penggerak', + $score >= 3.0 => 'Perintis', + $score >= 2.0 => 'Pemerhati', + default => 'Pemula', + }; + } + + private function getDimensionLevel(?float $score): string + { + if ($score === null) { + return 'belum_dinilai'; + } + + if ($score <= self::DIMENSION_LOW_MAX) { + return 'rendah'; + } + + if ($score <= self::DIMENSION_MEDIUM_MAX) { + return 'sedang'; + } + + return 'tinggi'; + } + + private function detectSpecialPattern( + string $segmen, + array $dimensions, + SkorPetani $skorPetani + ): ?array { + + $d2 = $dimensions['d2']['level']; + $d4 = $dimensions['d4']['level']; + $d6 = $dimensions['d6']['level']; + + if ( + $segmen === 'Perintis' && + $d4 === 'tinggi' && + $d2 === 'rendah' && + $d6 === 'sedang' + ) { + return [ + 'kode' => 'perintis_teknis', + 'nama' => 'Perintis dengan Hambatan Teknis', + 'prioritas' => 'gap', + ]; + } + + if ( + $segmen === 'Perintis' && + $d4 === 'tinggi' && + in_array($d2, ['sedang', 'tinggi']) && $d6 === 'rendah' + ) { + return [ + 'kode' => 'perintis_pasar', + 'nama' => 'Perintis dengan Hambatan Pasar', + 'prioritas' => 'pasar', + ]; + } + + if ( + $segmen === 'Pemerhati' && + $d4 === 'sedang' && + $d2 === 'rendah' && + $d6 === 'sedang' + ) { + return [ + 'kode' => 'pemerhati_teknis', + 'nama' => 'Pemerhati Teknis', + 'prioritas' => 'gap', + ]; + } + + + if ( + $segmen === 'Pemula' && + $d4 === 'rendah' && + $d2 === 'rendah' && + $d6 === 'rendah' + ) { + return [ + 'kode' => 'pemula_struktural', + 'nama' => 'Pemula Struktural', + 'prioritas' => 'struktural', + ]; + } + return null; + } + + private function buildProfileTitle( + string $segmen, + ?array $specialPattern, + $barriers + ): string { + if ($specialPattern) { + return $specialPattern['nama']; + } + + if ($barriers->isNotEmpty()) { + $mainBarrier = $barriers->first(); + return $segmen . ' dengan Prioritas ' . $mainBarrier['short']; + } + + return $segmen . ' dengan Profil Relatif Seimbang'; + } + + private function buildNarrative( + string $segmen, + ?array $specialPattern, + $strengths, + $barriers + ): string { + if ($specialPattern) { + return match ($specialPattern['kode']) { + 'perintis_teknis' => + 'Petani memiliki fondasi sosial-ekonomi yang relatif siap ' + . 'untuk berkembang, tetapi penerapannya belum sepenuhnya ' + . 'tercermin dalam praktik budidaya. Hambatan utama berada ' + . 'pada aspek teknis di lapangan.', + + 'perintis_pasar' => + 'Petani memiliki fondasi sosial-ekonomi dan kesiapan ' + . 'budidaya yang relatif baik, tetapi manfaat ekonominya ' + . 'masih dibatasi oleh rantai nilai dan akses pasar.', + + 'pemerhati_teknis' => + 'Petani telah memiliki sebagian fondasi untuk berkembang, ' + . 'namun praktik budidaya masih menjadi hambatan utama. ' + . 'Pendekatan berbasis demonstrasi hasil nyata akan lebih ' + . 'relevan sebelum intervensi teknis yang lebih lanjut.', + + 'pemula_struktural' => + 'Petani menghadapi hambatan pada beberapa dimensi sekaligus. ' + . 'Kondisi sosial-ekonomi, praktik budidaya, serta akses ' + . 'pasar perlu dibaca bersama untuk menentukan hambatan ' + . 'mendasar yang paling mendesak.', + + default => + $this->buildGenericNarrative($segmen, $strengths, $barriers), + }; + } + + return $this->buildGenericNarrative($segmen, $strengths, $barriers); + } + + private function buildGenericNarrative( + string $segmen, + $strengths, + $barriers + ): string { + + $text = 'Petani berada pada segmen ' . $segmen . '. '; + if ($strengths->isNotEmpty()) { + $strengthNames = $strengths->pluck('nama')->implode(' dan '); + $text .= 'Kekuatan relatif terlihat pada ' . $strengthNames . '. '; + } + + if ($barriers->isNotEmpty()) { + $barrierNames = $barriers->take(3)->pluck('nama')->implode(', '); + $text .= + 'Area yang masih memerlukan perhatian terutama pada ' . $barrierNames . '. Prioritas intervensi sebaiknya mengikuti ' . 'hambatan dengan skor paling rendah.'; + } else { + $text .= 'Tidak terdapat komponen dengan skor rendah yang ' . 'menonjol. Pendampingan dapat difokuskan pada ' . 'pemeliharaan dan penguatan capaian yang sudah ada.'; + } + + return $text; + } + + private function buildRecommendations( + ?array $specialPattern, + $barriers + ): array { + if ($specialPattern) { + $specialRecommendation = match ($specialPattern['kode']) { + 'perintis_teknis' => [ + 'Prioritaskan pendampingan GAP langsung di lapangan.', + 'Perkuat koneksi petani terhadap sumber input dan pelatihan teknis.', + ], + 'perintis_pasar' => [ + 'Perkuat koneksi ke saluran pasar yang lebih baik.', + 'Fasilitasi akses pembeli, negosiasi, atau penguatan koperasi.', + ], + 'pemerhati_teknis' => [ + 'Gunakan demonstrasi lapangan untuk menunjukkan hasil nyata.', + 'Lakukan pendampingan teknis secara bertahap sebelum pelatihan formal.', + ], + 'pemula_struktural' => [ + 'Identifikasi hambatan dasar seperti lahan, hutang, atau logistik.', + 'Tangani hambatan struktural sebelum mendorong adopsi praktik baru.', + ], + default => [], + }; + if (!empty($specialRecommendation)) { + return $specialRecommendation; + } + } + $recommendationMap = [ + 'motivasi' => 'Gunakan demonstrasi hasil nyata, role model, dan pendekatan perubahan secara bertahap.', + 'ekonomi' => 'Perkuat ruang gerak ekonomi rumah tangga sebelum mendorong investasi atau perubahan praktik yang berisiko.', + 'gap' => 'Prioritaskan pendampingan praktik budidaya dan GAP langsung di kebun.', + 'kelembagaan' => 'Perkuat keterlibatan petani dalam kelompok tani sebagai ruang belajar dan penguatan posisi tawar.', + 'keuangan' => 'Tinjau akses keuangan formal serta kemungkinan ikatan hutang panen atau ijon yang membatasi ruang gerak petani.', + 'pasar' => 'Perkuat koneksi dengan pembeli dan saluran pasar alternatif serta kemampuan negosiasi petani.', + ]; + + return $barriers->take(3)->map( + fn ($item) => + $recommendationMap[$item['key']] ?? null + )->filter()->values()->all(); + } +} + + \ No newline at end of file diff --git a/resources/views/produktivitas/profil-petani/index.blade.php b/resources/views/produktivitas/profil-petani/index.blade.php new file mode 100644 index 0000000..d0d1155 --- /dev/null +++ b/resources/views/produktivitas/profil-petani/index.blade.php @@ -0,0 +1,651 @@ +@extends('layout.main') + +@push('styles') + + +@endpush + +@section('content') +
+
+
+
+
+
+
+
+
+ Foto profil petani + + + +
+
+
+

{{ $petani->nama }}

+ NIK: {{ $ktpMasked }} +
+
+ {{ \Carbon\Carbon::parse($petani->tanggal_lahir)->age }} tahun + • + {{ $petani->pendidikan_terakhir }} + {{ $petani->status_perkawinan }} +
+
+ + + {{ $desaKelurahan->nama }}, {{ $desaKelurahan->kecamatan->nama }} + + + + {{ $komoditas->first()->nama }} + + @if($petani->sertifikat === 1) + + + Hak Milik (SHM) + + @endif +
+
+
+
+
+
+
+
+
+ Skor Kesiapan Adopsi +
+
+

+ {{ number_format($skorPetani->skor_kesiapan_adopsi, 1) }} +

+ / 5.0 +
+ + @if($skorPetani->skor_kesiapan_adopsi < 2.0) + Pemula + @elseif($skorPetani->skor_kesiapan_adopsi >= 2.0 && $skorPetani->skor_kesiapan_adopsi < 3.0) + Pemerhati + @elseif($skorPetani->skor_kesiapan_adopsi >= 3.0 && $skorPetani->skor_kesiapan_adopsi < 4.0) + Perintis + @elseif($skorPetani->skor_kesiapan_adopsi >= 4.0) + Penggerak + @endif + +
+
+
+ + +
+
+
+
+
+ + {{ number_format(4.0 - $skorPetani->skor_kesiapan_adopsi, 1) }} poin lagi menuju batas Segmen Penggerak + +
+
+ + + Enu: {{ $enumerator->nama ?? 'N/A' }} + + + + Terakhir Update: {{ \Carbon\Carbon::parse($petani->updated_at)->format('d M Y : H:i' ) }} + +
+
+
+
+
+
+
+
+
+
+
+
+
Profil Dimensi
+

Profil berdasarkan 6 dimensi penilaian

+
+ +
+
+
+
+
+
+
+
+
Skor per Komponen
+

Nilai masing-masing komponen penilaian petani

+
+
+
+
+
+
+
+ @if($profiling) +
+
+
+
+ +
+ +
+ + + + + +
+
+ Profil Hambatan & Rekomendasi Intervensi +
+ +

+ Pembacaan multidimensi berdasarkan profil petani +

+
+ +
+ + + {{-- Nama Profil --}} + + {{ $profiling['title'] }} + + +
+ + + {{-- Narasi --}} +

+ {{ $profiling['narrative'] }} +

+ + + {{-- Kekuatan & Hambatan --}} +
+ + {{-- Kekuatan --}} +
+ +
+ + Kekuatan Relatif + +
+ +
+ + @forelse($profiling['strengths'] as $strength) + + + + + + {{ $strength['short'] }} + + + {{ number_format($strength['skor'], 1) }} + + + + + @empty + + + Belum ada data yang cukup. + + + @endforelse + +
+ +
+ + + {{-- Hambatan --}} +
+ +
+ + Area Prioritas + +
+ +
+ + @forelse($profiling['barriers'] as $barrier) + + + + + + {{ $barrier['short'] }} + + + {{ number_format($barrier['skor'], 1) }} + + + + + @empty + + + + Tidak ada hambatan utama yang menonjol + + + @endforelse + +
+ +
+ +
+ + + {{-- Rekomendasi --}} + @if(!empty($profiling['recommendations'])) + +
+ +
+ + + +
+ Rekomendasi Intervensi +
+ +
+ + +
+ + @foreach($profiling['recommendations'] as $recommendation) + +
+ +
+ + + {{ $loop->iteration }} + + + + {{ $recommendation }} + + +
+ +
+ + @endforeach + +
+ +
+ + @endif + +
+
+ +
+
+ + @endif +
+@endsection + +@push('scripts') + + +@endpush \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index d799ef9..af250ec 100644 --- a/routes/web.php +++ b/routes/web.php @@ -51,7 +51,9 @@ 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/indeks', [App\Http\Controllers\Web\Dashboard\IndeksPetaniController::class, 'index'])->name('dashboard.indeks-petani'); - + + Route::get('/dashboard/profil/petani/{id}',[App\Http\Controllers\Web\Produktivitas\ProfilPetaniController::class, 'index'])->name('dashboard.profil-petani'); + Route::get('/user-profile', [App\Http\Controllers\Web\Konfigurasi\ProfileController::class, 'index'])->name('userProfile.index'); Route::get('/user-profile/security', [App\Http\Controllers\Web\Konfigurasi\ProfileController::class, 'security'])->name('userProfile.security'); Route::get('/user-profile/activities', [App\Http\Controllers\Web\Konfigurasi\ProfileController::class, 'activities'])->name('userProfile.activities');