From 86c6a514016a5a19b78a939020e78c3c8dd952f5 Mon Sep 17 00:00:00 2001 From: E31232303evimr <158023512+E31232303evimr@users.noreply.github.com> Date: Wed, 25 Feb 2026 03:46:16 +0700 Subject: [PATCH] admin-gejala dan rule basis done --- .../Controllers/Admin/GejalaController.php | 21 +- .../Controllers/Admin/RuleBasisController.php | 157 ++++++++++++ app/Models/MasterGejala.php | 33 ++- app/Models/RuleBasis.php | 74 ++++-- resources/views/admin/gejala/create.blade.php | 100 ++++++++ resources/views/admin/gejala/edit.blade.php | 97 +++++++ resources/views/admin/gejala/index.blade.php | 4 +- .../views/admin/penyakit/create.blade.php | 6 +- resources/views/admin/penyakit/edit.blade.php | 2 +- .../views/admin/penyakit/index.blade.php | 6 +- .../views/admin/rule-basis/create.blade.php | 208 +++++++++++++++ .../views/admin/rule-basis/edit.blade.php | 189 ++++++++++++++ .../views/admin/rule-basis/index.blade.php | 239 ++++++++++++++++++ resources/views/layouts/admin-app.blade.php | 13 + routes/web.php | 8 +- 15 files changed, 1101 insertions(+), 56 deletions(-) create mode 100644 app/Http/Controllers/Admin/RuleBasisController.php create mode 100644 resources/views/admin/gejala/create.blade.php create mode 100644 resources/views/admin/gejala/edit.blade.php create mode 100644 resources/views/admin/rule-basis/create.blade.php create mode 100644 resources/views/admin/rule-basis/edit.blade.php create mode 100644 resources/views/admin/rule-basis/index.blade.php diff --git a/app/Http/Controllers/Admin/GejalaController.php b/app/Http/Controllers/Admin/GejalaController.php index 956d8ba..0661d24 100644 --- a/app/Http/Controllers/Admin/GejalaController.php +++ b/app/Http/Controllers/Admin/GejalaController.php @@ -13,7 +13,7 @@ class GejalaController extends Controller */ public function index() { - $gejalas = MasterGejala::latest()->paginate(10); + $gejalas = MasterGejala::orderByRaw('LENGTH(id_gejala) ASC, id_gejala ASC')->paginate(10); return view('admin.gejala.index', compact('gejalas')); } @@ -31,11 +31,11 @@ public function create() public function store(Request $request) { $validated = $request->validate([ - 'kode_gejala' => ['required', 'string', 'max:10', 'unique:gejala,kode_gejala'], + 'id_gejala' => ['required', 'string', 'max:10', 'unique:master_gejala,id_gejala'], 'nama_gejala' => ['required', 'string', 'max:255'], ], [ - 'kode_gejala.unique' => 'Kode gejala sudah digunakan', - 'kode_gejala.required' => 'Kode gejala wajib diisi', + 'id_gejala.required' => 'Kode gejala wajib diisi', + 'id_gejala.unique' => 'Kode gejala sudah digunakan', 'nama_gejala.required' => 'Nama gejala wajib diisi', ]); @@ -46,15 +46,7 @@ public function store(Request $request) } /** - * Display the specified gejala. - */ - public function show(MasterGejala $gejala) - { - return view('admin.gejala.show', compact('gejala')); - } - - /** - * Show the form for editing gejala. + * Show the form for editing the specified gejala. */ public function edit(MasterGejala $gejala) { @@ -67,10 +59,9 @@ public function edit(MasterGejala $gejala) public function update(Request $request, MasterGejala $gejala) { $validated = $request->validate([ - 'kode_gejala' => ['required', 'string', 'max:10', 'unique:gejala,kode_gejala,' . $gejala->id], 'nama_gejala' => ['required', 'string', 'max:255'], ], [ - 'kode_gejala.unique' => 'Kode gejala sudah digunakan', + 'nama_gejala.required' => 'Nama gejala wajib diisi', ]); $gejala->update($validated); diff --git a/app/Http/Controllers/Admin/RuleBasisController.php b/app/Http/Controllers/Admin/RuleBasisController.php new file mode 100644 index 0000000..5398ce7 --- /dev/null +++ b/app/Http/Controllers/Admin/RuleBasisController.php @@ -0,0 +1,157 @@ +filled('penyakit')) { + $query->where('id_penyakit', $request->penyakit); + } + + // Filter by gejala + if ($request->filled('gejala')) { + $query->where('id_gejala', $request->gejala); + } + + // Search by keterangan + if ($request->filled('search')) { + $query->where('keterangan', 'like', '%' . $request->search . '%'); + } + + $rules = $query->orderBy('id_penyakit', 'asc') + ->orderBy('id_gejala', 'asc') + ->paginate(15); + + // Statistics + $totalRules = RuleBasis::count(); + $avgCF = RuleBasis::avg('cf_pakar'); + $highConfidenceRules = RuleBasis::where('cf_pakar', '>=', 0.7)->count(); + $totalPenyakitWithRules = RuleBasis::distinct('id_penyakit')->count('id_penyakit'); + + // Data for filter dropdowns + $penyakits = MasterPenyakit::orderByRaw('LENGTH(id_penyakit) ASC, id_penyakit ASC')->get(); + $gejalas = MasterGejala::orderByRaw('LENGTH(id_gejala) ASC, id_gejala ASC')->get(); + + return view('admin.rule-basis.index', compact( + 'rules', + 'penyakits', + 'gejalas', + 'totalRules', + 'avgCF', + 'highConfidenceRules', + 'totalPenyakitWithRules' + )); + } + + /** + * Show the form for creating a new rule. + */ + public function create() + { + $penyakits = MasterPenyakit::orderByRaw('LENGTH(id_penyakit) ASC, id_penyakit ASC')->get(); + $gejalas = MasterGejala::orderByRaw('LENGTH(id_gejala) ASC, id_gejala ASC')->get(); + + return view('admin.rule-basis.create', compact('penyakits', 'gejalas')); + } + + /** + * Store a newly created rule. + */ + public function store(Request $request) + { + $validated = $request->validate([ + 'id_penyakit' => ['required', 'exists:master_penyakit,id_penyakit'], + 'id_gejala' => ['required', 'exists:master_gejala,id_gejala'], + 'mb' => ['required', 'numeric', 'min:0', 'max:1'], + 'md' => ['required', 'numeric', 'min:0', 'max:1'], + 'keterangan' => ['nullable', 'string'], + ], [ + 'id_penyakit.required' => 'Penyakit wajib dipilih', + 'id_penyakit.exists' => 'Penyakit tidak valid', + 'id_gejala.required' => 'Gejala wajib dipilih', + 'id_gejala.exists' => 'Gejala tidak valid', + 'mb.required' => 'Nilai MB wajib diisi', + 'mb.min' => 'Nilai MB minimal 0', + 'mb.max' => 'Nilai MB maksimal 1', + 'md.required' => 'Nilai MD wajib diisi', + 'md.min' => 'Nilai MD minimal 0', + 'md.max' => 'Nilai MD maksimal 1', + ]); + + // Check if rule already exists + $exists = RuleBasis::where('id_penyakit', $validated['id_penyakit']) + ->where('id_gejala', $validated['id_gejala']) + ->exists(); + + if ($exists) { + return back()->withInput()->withErrors([ + 'id_gejala' => 'Rule untuk penyakit dan gejala ini sudah ada!' + ]); + } + + RuleBasis::create($validated); + + return redirect()->route('admin.rule-basis.index') + ->with('success', 'Rule basis berhasil ditambahkan!'); + } + + /** + * Show the form for editing the specified rule. + */ + public function edit(RuleBasis $ruleBasis) + { + $penyakits = MasterPenyakit::orderByRaw('LENGTH(id_penyakit) ASC, id_penyakit ASC')->get(); + $gejalas = MasterGejala::orderByRaw('LENGTH(id_gejala) ASC, id_gejala ASC')->get(); + + return view('admin.rule-basis.edit', compact('ruleBasis', 'penyakits', 'gejalas')); + } + + /** + * Update the specified rule. + */ + public function update(Request $request, RuleBasis $ruleBasis) + { + $validated = $request->validate([ + 'mb' => ['required', 'numeric', 'min:0', 'max:1'], + 'md' => ['required', 'numeric', 'min:0', 'max:1'], + 'keterangan' => ['nullable', 'string'], + ], [ + 'mb.required' => 'Nilai MB wajib diisi', + 'mb.min' => 'Nilai MB minimal 0', + 'mb.max' => 'Nilai MB maksimal 1', + 'md.required' => 'Nilai MD wajib diisi', + 'md.min' => 'Nilai MD minimal 0', + 'md.max' => 'Nilai MD maksimal 1', + ]); + + $ruleBasis->update($validated); + + return redirect()->route('admin.rule-basis.index') + ->with('success', 'Rule basis berhasil diupdate!'); + } + + /** + * Remove the specified rule. + */ + public function destroy(RuleBasis $ruleBasis) + { + $ruleBasis->delete(); + + return redirect()->route('admin.rule-basis.index') + ->with('success', 'Rule basis berhasil dihapus!'); + } +} \ No newline at end of file diff --git a/app/Models/MasterGejala.php b/app/Models/MasterGejala.php index f9d5fb5..63709e3 100644 --- a/app/Models/MasterGejala.php +++ b/app/Models/MasterGejala.php @@ -2,23 +2,46 @@ namespace App\Models; +use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class MasterGejala extends Model { + use HasFactory; + + /** + * The table associated with the model. + */ protected $table = 'master_gejala'; + + /** + * The primary key associated with the table. + */ protected $primaryKey = 'id_gejala'; + + /** + * Indicates if the model's ID is auto-incrementing. + */ public $incrementing = false; + + /** + * The data type of the primary key. + */ protected $keyType = 'string'; + /** + * The attributes that are mass assignable. + */ protected $fillable = [ 'id_gejala', 'nama_gejala', ]; - // Relationships - public function ruleBasis() - { - return $this->hasMany(RuleBasis::class, 'id_gejala', 'id_gejala'); - } + /** + * The attributes that should be cast. + */ + protected $casts = [ + 'created_at' => 'datetime', + 'updated_at' => 'datetime', + ]; } \ No newline at end of file diff --git a/app/Models/RuleBasis.php b/app/Models/RuleBasis.php index 3a34431..3d1cb7b 100644 --- a/app/Models/RuleBasis.php +++ b/app/Models/RuleBasis.php @@ -2,62 +2,84 @@ namespace App\Models; +use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; class RuleBasis extends Model { + use HasFactory; + + /** + * The table associated with the model. + */ protected $table = 'rule_basis'; + + /** + * The primary key associated with the table. + */ protected $primaryKey = 'id_rule'; + /** + * FIX: Paksa Laravel pakai 'id_rule' sebagai route key. + * Tanpa ini, Laravel auto-generate nama parameter dari nama class: + * RuleBasis -> 'rule_basi' (typo otomatis) -> UrlGenerationException. + */ + public function getRouteKeyName(): string + { + return 'id_rule'; + } + + /** + * The attributes that are mass assignable. + */ protected $fillable = [ 'id_penyakit', 'id_gejala', - 'mb', // ← TAMBAH - 'md', // ← TAMBAH + 'mb', + 'md', 'cf_pakar', 'keterangan', ]; - // Relationships + /** + * The attributes that should be cast. + */ + protected $casts = [ + 'mb' => 'decimal:2', + 'md' => 'decimal:2', + 'cf_pakar' => 'decimal:2', + 'created_at' => 'datetime', + 'updated_at' => 'datetime', + ]; + + /** + * Relationship with MasterPenyakit + */ public function penyakit() { return $this->belongsTo(MasterPenyakit::class, 'id_penyakit', 'id_penyakit'); } + /** + * Relationship with MasterGejala + */ public function gejala() { return $this->belongsTo(MasterGejala::class, 'id_gejala', 'id_gejala'); } - // ============================================ - // AUTO-CALCULATE CF dari MB & MD - // ============================================ - /** - * Otomatis hitung CF sebelum save + * Auto-calculate CF when MB and MD are set */ protected static function boot() { parent::boot(); - - // Event: Sebelum create - static::creating(function ($rule) { - $rule->cf_pakar = $rule->mb - $rule->md; - }); - - // Event: Sebelum update - static::updating(function ($rule) { - if ($rule->isDirty(['mb', 'md'])) { - $rule->cf_pakar = $rule->mb - $rule->md; + + static::saving(function ($model) { + // Auto-calculate CF = MB - MD + if (!is_null($model->mb) && !is_null($model->md)) { + $model->cf_pakar = $model->mb - $model->md; } }); } - - /** - * Accessor: Hitung CF on-the-fly (alternatif) - */ - public function getCfAttribute() - { - return $this->mb - $this->md; - } } \ No newline at end of file diff --git a/resources/views/admin/gejala/create.blade.php b/resources/views/admin/gejala/create.blade.php new file mode 100644 index 0000000..573d8c2 --- /dev/null +++ b/resources/views/admin/gejala/create.blade.php @@ -0,0 +1,100 @@ +@extends('layouts.admin-app') + +@section('page-title', 'Tambah Gejala') +@section('page-subtitle', 'Tambah data gejala penyakit baru') + +@section('content') + @if ($errors->any()) +
Terdapat kesalahan:
+Terdapat kesalahan:
+{{ $message }}
diff --git a/resources/views/admin/penyakit/edit.blade.php b/resources/views/admin/penyakit/edit.blade.php index 47d07f7..876f150 100644 --- a/resources/views/admin/penyakit/edit.blade.php +++ b/resources/views/admin/penyakit/edit.blade.php @@ -1,6 +1,6 @@ @extends('layouts.admin-app') -@section('page-title', '✏️ Edit Penyakit') +@section('page-title', 'Edit Penyakit') @section('page-subtitle', 'Edit data penyakit tanaman kopi') @section('content') diff --git a/resources/views/admin/penyakit/index.blade.php b/resources/views/admin/penyakit/index.blade.php index 49bb130..3a9c17c 100644 --- a/resources/views/admin/penyakit/index.blade.php +++ b/resources/views/admin/penyakit/index.blade.php @@ -1,6 +1,6 @@ @extends('layouts.admin-app') -@section('page-title', '🦠 Manajemen Penyakit') +@section('page-title', 'Manajemen Penyakit') @section('page-subtitle', 'Kelola data penyakit tanaman kopi') @section('content') @@ -111,11 +111,11 @@ class="w-16 h-16 object-cover rounded-lg shadow-sm cursor-pointer hover:scale-11Terdapat kesalahan:
+Terdapat kesalahan:
+Total Rule
+Rata-rata CF
+CF Tinggi (≥0.7)
+Penyakit Terintegrasi
+| No | +Penyakit | +Gejala | +MB | +MD | +CF | +Keterangan | +Aksi | +
|---|---|---|---|---|---|---|---|
| {{ $rules->firstItem() + $index }} | +
+
+
+ {{ $rule->id_penyakit }}
+
+
+ {{ $rule->penyakit->nama_penyakit ?? '-' }} + |
+
+
+
+ {{ $rule->id_gejala }}
+
+
+ {{ $rule->gejala->nama_gejala ?? '-' }} + |
+ + + {{ number_format($rule->mb, 2) }} + + | ++ + {{ number_format($rule->md, 2) }} + + | ++ + {{ number_format($rule->cf_pakar, 2) }} + + | ++ {{ $rule->keterangan ?? '-' }} + | +
+
+ {{-- FIX: Gunakan id_rule eksplisit untuk route model binding --}}
+
+
+ Edit
+
+ {{-- FIX: Form delete dengan id_rule eksplisit --}}
+
+
+ |
+
|
+
+
+
+ Belum ada rule basis +Klik "Tambah Rule" untuk menambahkan aturan diagnosa + |
+ |||||||