Merge branch 'main' of https://git.probindo.com/Probindo/database-pertani-web
This commit is contained in:
@@ -6,6 +6,9 @@ use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
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\Komoditas;
|
||||
@@ -13,41 +16,181 @@ use App\Models\Pertanian\Lahan;
|
||||
use App\Models\Pertanian\Tanaman;
|
||||
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
|
||||
{
|
||||
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'])) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$filters = $this->filters($request);
|
||||
|
||||
$title = 'Dashboard Profil Petani';
|
||||
|
||||
$komoditas = Komoditas::where('is_utama', true)->get();
|
||||
$petaniQuery = $this->petaniQuery($filters);
|
||||
|
||||
$petani = Petani::pluck('id');
|
||||
$lahan = Lahan::has('petani')->get();
|
||||
$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();
|
||||
|
||||
$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
|
||||
";
|
||||
$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();
|
||||
|
||||
$countPetani = Petani::count();
|
||||
$countKomoditas = Petani::whereIn('komoditas_id', $komoditas->pluck('id'))->distinct()->count('komoditas_id');
|
||||
$sumLahan = Lahan::has('petani')->whereIn('komoditas_id', $komoditas->pluck('id'))->sum('luas_lahan');
|
||||
$avgLahan = Lahan::has('petani')->whereIn('komoditas_id', $komoditas->pluck('id'))->avg('luas_lahan');
|
||||
return view('dashboard.indeks-petani', array_merge($filters,
|
||||
compact(
|
||||
'komoditas',
|
||||
'desaKelurahan',
|
||||
'wilayah',
|
||||
)));
|
||||
}
|
||||
|
||||
$avgSkor = SkorPetani::query()
|
||||
->join('petani', 'petani_skor.petani_id', '=', 'petani.id')
|
||||
->whereNull('petani.deleted_at')
|
||||
->whereIn('petani.komoditas_id', $komoditas->pluck('id'))
|
||||
->avg('skor_kesiapan_adopsi');
|
||||
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';
|
||||
@@ -61,19 +204,120 @@ class IndeksPetaniController extends Controller
|
||||
$avgSegmen = 'Belum Lengkap';
|
||||
}
|
||||
|
||||
$countDesa = Petani::whereIn('komoditas_id', $komoditas->pluck('id'))->distinct()->count('desa_kelurahan_id');
|
||||
$countKecamatan = 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')
|
||||
->whereIn('komoditas_id', $komoditas->pluck('id'))->distinct()->count('master_kecamatan.id');
|
||||
return response()->json([
|
||||
'petani' => $petaniQuery->clone()->count(),
|
||||
'komoditas' => $countKomoditas,
|
||||
'sum_lahan' => $sumLahan,
|
||||
'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)
|
||||
->get();
|
||||
|
||||
$countSegmentasiByKomoditas = SkorPetani::query()
|
||||
->join('petani', 'petani_skor.petani_id', '=', 'petani.id')
|
||||
->whereNull('petani.deleted_at')
|
||||
$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,
|
||||
@@ -83,20 +327,64 @@ class IndeksPetaniController extends Controller
|
||||
->groupByRaw($case)
|
||||
->get();
|
||||
|
||||
$avgDimensi = SkorPetani::query()
|
||||
->join('petani', 'petani_skor.petani_id', '=', 'petani.id')
|
||||
->whereNull('petani.deleted_at')
|
||||
->whereIn('petani.komoditas_id', $komoditas->pluck('id'))
|
||||
$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();
|
||||
|
||||
$avgKomponen = SkorPetani::query()
|
||||
->join('petani', 'petani_skor.petani_id', '=', 'petani.id')
|
||||
->whereNull('petani.deleted_at')
|
||||
->whereIn('petani.komoditas_id', $komoditas->pluck('id'))
|
||||
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,
|
||||
@@ -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")
|
||||
->first();
|
||||
|
||||
$desaKelurahan = 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')
|
||||
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,
|
||||
@@ -121,13 +432,15 @@ class IndeksPetaniController extends Controller
|
||||
master_provinsi.id as provinsi_id,
|
||||
master_provinsi.nama as provinsi
|
||||
")
|
||||
->whereIn('petani.id', $petani)
|
||||
->distinct()
|
||||
->get();
|
||||
|
||||
$mapSegmentasi = SkorPetani::query()
|
||||
->join('petani', 'petani_skor.petani_id', '=', 'petani.id')
|
||||
->whereNull('petani.deleted_at')
|
||||
$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
|
||||
@@ -136,9 +449,7 @@ class IndeksPetaniController extends Controller
|
||||
->groupByRaw($case)
|
||||
->get();
|
||||
|
||||
$mapAvgSkorSegmentasi = SkorPetani::query()
|
||||
->join('petani', 'petani_skor.petani_id', '=', 'petani.id')
|
||||
->whereNull('petani.deleted_at')
|
||||
$mapAvgSkorSegmentasi = $skorQuery->clone()
|
||||
->selectRaw("petani.desa_kelurahan_id,
|
||||
COUNT(petani.id) AS jumlah_petani,
|
||||
avg(skor_kesiapan_adopsi) AS skor,
|
||||
@@ -153,28 +464,195 @@ class IndeksPetaniController extends Controller
|
||||
->groupBy('petani.desa_kelurahan_id')
|
||||
->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'))
|
||||
->get();
|
||||
|
||||
return view('dashboard.indeks-petani', compact(
|
||||
'komoditas',
|
||||
'countPetani',
|
||||
'countKomoditas',
|
||||
'sumLahan',
|
||||
'avgLahan',
|
||||
'avgSkor',
|
||||
'avgSegmen',
|
||||
'countDesa',
|
||||
'countKecamatan',
|
||||
'countSegmentasi',
|
||||
'countSegmentasiByKomoditas',
|
||||
'avgDimensi',
|
||||
'avgKomponen',
|
||||
'desaKelurahan',
|
||||
'mapSegmentasi',
|
||||
'mapAvgSkorSegmentasi',
|
||||
'daftarPetani',
|
||||
));
|
||||
$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);
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,11 @@ use App\Models\Pertanian\Lahan;
|
||||
use App\Models\Pertanian\Tanaman;
|
||||
use App\Models\Pertanian\PraktikBudidaya;
|
||||
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\Wilayah\DesaKelurahan;
|
||||
use App\Models\Profile;
|
||||
@@ -23,6 +28,15 @@ use App\Enums\PraktikBudidaya\MetodePenangananHamaPenyakit;
|
||||
use App\Enums\PraktikBudidaya\FrekuensiSanitasiLahan;
|
||||
use App\Enums\PraktikBudidaya\PenangananGulma;
|
||||
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
|
||||
{
|
||||
@@ -62,6 +76,7 @@ class ProfilPetaniController extends Controller
|
||||
|
||||
$praktikBudidaya = PraktikBudidaya::where('petani_id', $petani->id)->first();
|
||||
$surveyPanen = SurveyPanen::where('petani_id', $petani->id)->first();
|
||||
$sosialEkonomi = SosialEkonomi::where('petani_id', $id)->first();
|
||||
|
||||
$indikatorOnFarm = collect();
|
||||
|
||||
@@ -145,6 +160,280 @@ class ProfilPetaniController extends Controller
|
||||
'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 = [
|
||||
'petani' => $petani,
|
||||
'skorPetani' => $skorPetani,
|
||||
@@ -161,6 +450,16 @@ class ProfilPetaniController extends Controller
|
||||
'praktikBudidaya' => $praktikBudidaya,
|
||||
'indikatorOnFarm' => $indikatorOnFarm,
|
||||
'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);
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
$skorAkhir = $this->normalizeScore($skorPetani->skor_kesiapan_adopsi);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,41 +14,37 @@
|
||||
margin-bottom: .35rem;
|
||||
}
|
||||
|
||||
.indicator-filter-row {
|
||||
padding-bottom: 1.5rem;
|
||||
padding-top: 1.5rem;
|
||||
}
|
||||
|
||||
.indicator-filter-bar {
|
||||
align-items: end;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.indicator-filter-line {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: .75rem;
|
||||
margin-bottom: 1.25rem;
|
||||
gap: .5rem;
|
||||
}
|
||||
|
||||
.indicator-filter-group {
|
||||
flex: 1 1 150px;
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.indicator-filter-actions {
|
||||
.indicator-filter-section-label {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex: 999 1 240px;
|
||||
gap: .75rem;
|
||||
justify-content: space-between;
|
||||
font-weight: 500;
|
||||
margin-right: .5rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.indicator-filter-primary-actions {
|
||||
display: flex;
|
||||
gap: .75rem;
|
||||
}
|
||||
|
||||
.indicator-filter-label {
|
||||
color: var(--bs-body-color);
|
||||
font-size: .75rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: .3rem;
|
||||
.indicator-filter-export-action {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.indicator-filter-bar .form-select,
|
||||
.indicator-filter-bar .btn {
|
||||
min-height: 38px;
|
||||
min-height: 31px;
|
||||
}
|
||||
|
||||
.indicator-filter-bar .form-select {
|
||||
@@ -56,15 +52,10 @@
|
||||
border-color: var(--bs-border-color);
|
||||
border-radius: var(--bs-border-radius);
|
||||
color: var(--bs-body-color);
|
||||
font-size: .8125rem;
|
||||
padding-bottom: .375rem;
|
||||
padding-top: .375rem;
|
||||
}
|
||||
|
||||
.indicator-filter-bar .btn {
|
||||
font-size: .8125rem;
|
||||
padding-bottom: .375rem;
|
||||
padding-top: .375rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.indicator-filter-bar .form-select:focus {
|
||||
@@ -90,29 +81,16 @@
|
||||
color: var(--bs-body-color);
|
||||
display: flex;
|
||||
font-size: .8125rem;
|
||||
min-height: 38px;
|
||||
padding: .375rem .75rem;
|
||||
min-height: 31px;
|
||||
padding: .25rem .75rem;
|
||||
}
|
||||
|
||||
.indicator-filter-bar .input-group-text {
|
||||
background: var(--bs-paper-bg);
|
||||
border-color: var(--bs-border-color);
|
||||
color: var(--bs-secondary-color);
|
||||
padding-left: .625rem;
|
||||
padding-right: .625rem;
|
||||
}
|
||||
|
||||
.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;
|
||||
padding-left: .5rem;
|
||||
padding-right: .5rem;
|
||||
}
|
||||
|
||||
.indicator-summary-value {
|
||||
@@ -190,16 +168,18 @@
|
||||
}
|
||||
|
||||
@media (max-width: 767.98px) {
|
||||
.indicator-filter-bar,
|
||||
.indicator-filter-actions,
|
||||
.indicator-filter-primary-actions {
|
||||
.indicator-filter-line {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.indicator-filter-group {
|
||||
min-width: 100%;
|
||||
.indicator-filter-section-label {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.indicator-filter-export-action {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.indicator-filter-bar .btn {
|
||||
@@ -225,18 +205,27 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="indicator-filter-bar" id="indicator-filter-bar" aria-label="Filter dashboard indikator pertanian">
|
||||
@foreach ($filterOptions as $filter)
|
||||
<div class="indicator-filter-group">
|
||||
<label for="filter-{{ $filter['key'] }}" class="indicator-filter-label">
|
||||
{{ $filter['label'] }}
|
||||
</label>
|
||||
@php
|
||||
$filtersByKey = collect($filterOptions)->keyBy('key');
|
||||
@endphp
|
||||
|
||||
@if (!empty($filter['icon']))
|
||||
<div class="input-group">
|
||||
<span class="input-group-text" aria-hidden="true">
|
||||
<i class="ti {{ $filter['icon'] }}"></i>
|
||||
</span>
|
||||
<div class="row g-6 indicator-filter-row">
|
||||
<div class="col-12">
|
||||
<div class="card card-border-shadow-primary">
|
||||
<div class="card-body py-3">
|
||||
<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']))
|
||||
@php
|
||||
$selectedOption = collect($filter['options'])
|
||||
@@ -245,7 +234,7 @@
|
||||
|
||||
<div
|
||||
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-value="{{ $initialFilters[$filter['key']] }}"
|
||||
aria-label="Filter {{ $filter['label'] }}"
|
||||
@@ -256,25 +245,7 @@
|
||||
@else
|
||||
<select
|
||||
id="filter-{{ $filter['key'] }}"
|
||||
class="form-select 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"
|
||||
class="form-select form-select-sm indicator-filter-select"
|
||||
data-filter-key="{{ $filter['key'] }}"
|
||||
aria-label="Filter {{ $filter['label'] }}"
|
||||
@disabled($filter['key'] === 'desa' && $initialFilters['kecamatan'] === 'all')
|
||||
@@ -292,31 +263,77 @@
|
||||
@endif
|
||||
</div>
|
||||
@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
|
||||
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"
|
||||
aria-label="Reset filter indikator pertanian"
|
||||
>
|
||||
<i class="ti tabler-rotate-clockwise-2 me-1"></i>
|
||||
Reset Filter
|
||||
<i class="icon-base ti tabler-refresh me-1"></i>
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="indicator-filter-export-action">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-outline-success indicator-export-btn"
|
||||
class="btn btn-outline-secondary btn-sm"
|
||||
id="indicator-export-data"
|
||||
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
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-6" id="indicator-summary-row">
|
||||
@foreach ($summaryData as $summary)
|
||||
@@ -685,6 +702,7 @@
|
||||
const komoditasSelect = document.querySelector('[data-filter-key="komoditas"]');
|
||||
const segmentasiSelect = document.querySelector('[data-filter-key="segmentasi"]');
|
||||
const selectedKabupaten = kabupatenFilter?.dataset.filterValue || initialFilters.kabupaten || 'all';
|
||||
const applyFilterButton = document.getElementById('indicator-apply-filter');
|
||||
const resetButton = document.getElementById('indicator-reset-filter');
|
||||
const exportButton = document.getElementById('indicator-export-data');
|
||||
const chartInstances = {};
|
||||
@@ -729,6 +747,10 @@
|
||||
resetButton.disabled = isLoading;
|
||||
}
|
||||
|
||||
if (applyFilterButton) {
|
||||
applyFilterButton.disabled = isLoading;
|
||||
}
|
||||
|
||||
if (exportButton) {
|
||||
exportButton.disabled = isLoading;
|
||||
}
|
||||
@@ -970,11 +992,13 @@
|
||||
filters.desa = 'all';
|
||||
await loadDesaOptions('all');
|
||||
}
|
||||
|
||||
loadIndicatorData();
|
||||
});
|
||||
});
|
||||
|
||||
applyFilterButton?.addEventListener('click', function () {
|
||||
loadIndicatorData();
|
||||
});
|
||||
|
||||
resetButton?.addEventListener('click', async function () {
|
||||
Object.assign(filters, {
|
||||
kecamatan: 'all',
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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/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');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user