progres itulah

This commit is contained in:
rijalhabibullah 2026-05-16 03:29:53 +07:00
parent 6b792d779c
commit 57faf795c5
10 changed files with 386 additions and 34 deletions

View File

@ -233,7 +233,9 @@ class _ResultScreenState extends State<ResultScreen> {
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
...widget.result.allPredictions.entries.map((entry) { ...widget.result.allPredictions.entries.map((entry) {
final score = entry.value as double; final score = (entry.value is num)
? (entry.value as num).toDouble()
: 0.0;
final percentage = (score * 100).toStringAsFixed(2); final percentage = (score * 100).toStringAsFixed(2);
return Padding( return Padding(
padding: const EdgeInsets.only(bottom: 12), padding: const EdgeInsets.only(bottom: 12),
@ -268,9 +270,12 @@ class _ResultScreenState extends State<ResultScreen> {
), ),
const SizedBox(height: 30), const SizedBox(height: 30),
const Align( Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text("Rekomendasi Produk:", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), child: Text(
"Rekomendasi Produk untuk ${_normalizeDiseaseName(widget.result.diseaseInfo.name)}:",
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
), ),
const SizedBox(height: 15), const SizedBox(height: 15),
@ -312,6 +317,8 @@ class _ResultScreenState extends State<ResultScreen> {
} }
final products = snapshot.data ?? []; final products = snapshot.data ?? [];
final diseaseName = _normalizeDiseaseName(widget.result.diseaseInfo.name);
final filteredProducts = _filterProducts(products, diseaseName);
if (products.isEmpty) { if (products.isEmpty) {
return Container( return Container(
@ -326,7 +333,10 @@ class _ResultScreenState extends State<ResultScreen> {
); );
} }
return GridView.builder( return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GridView.builder(
shrinkWrap: true, shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
@ -335,10 +345,12 @@ class _ResultScreenState extends State<ResultScreen> {
mainAxisSpacing: 15, mainAxisSpacing: 15,
childAspectRatio: 0.75, childAspectRatio: 0.75,
), ),
itemCount: products.length, itemCount: filteredProducts.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
return _buildProductCard(products[index]); return _buildProductCard(filteredProducts[index]);
}, },
),
],
); );
}, },
), ),
@ -542,6 +554,47 @@ class _ResultScreenState extends State<ResultScreen> {
return buffer.toString(); return buffer.toString();
} }
String _normalizeDiseaseName(String diseaseName) {
final normalized = {
'Bacterial Blight': 'Bacterial Blight',
'bacterial blight': 'Bacterial Blight',
'Bacterialblight': 'Bacterial Blight',
'Bercak Bakteri (Bacterial Blight)': 'Bacterial Blight',
'Brown Spot': 'Brown Spot',
'brown spot': 'Brown Spot',
'Brownspot': 'Brown Spot',
'Bercak Coklat (Brown Spot)': 'Brown Spot',
'Leaf Smut': 'Leaf Smut',
'leaf smut': 'Leaf Smut',
'Leafsmut': 'Leaf Smut',
'Jamur Daun (Leaf Smut)': 'Leaf Smut',
'Healthy': 'Healthy',
'healthy': 'Healthy',
'Sehat (Healthy)': 'Healthy',
};
return normalized[diseaseName] ?? diseaseName;
}
List<ProductItem> _filterProducts(
List<ProductItem> products,
String disease,
) {
if (disease == 'Healthy') {
return products;
}
final tagged = products.where((product) {
final tag = product.diseaseTag;
if (tag == null || tag.trim().isEmpty) {
return false;
}
return _normalizeDiseaseName(tag) == disease;
}).toList();
return tagged;
}
void _showDetailPopup(BuildContext context) { void _showDetailPopup(BuildContext context) {
showDialog( showDialog(
context: context, context: context,

View File

@ -210,7 +210,7 @@ class ClassificationService {
final response = await _httpClient final response = await _httpClient
.get( .get(
Uri.parse('$_historyUrl?page=$page$userParam'), Uri.parse('$_historyUrl?page=$page&per_page=1000$userParam'),
headers: {'Accept': 'application/json'}, headers: {'Accept': 'application/json'},
) )
.timeout(const Duration(seconds: 15)); .timeout(const Duration(seconds: 15));
@ -278,7 +278,9 @@ class ClassificationResult {
return ClassificationResult( return ClassificationResult(
predictedClass: json['predicted_class'] ?? '', predictedClass: json['predicted_class'] ?? '',
confidence: json['confidence'] ?? '0%', confidence: json['confidence'] ?? '0%',
confidenceValue: json['confidence_value'] ?? 0.0, confidenceValue: (json['confidence_value'] is num)
? (json['confidence_value'] as num).toDouble()
: 0.0,
allPredictions: Map<String, dynamic>.from( allPredictions: Map<String, dynamic>.from(
json['all_predictions'] ?? {}, json['all_predictions'] ?? {},
), ),

View File

@ -9,6 +9,7 @@ class ProductItem {
final double price; final double price;
final String? imageUrl; final String? imageUrl;
final String? marketplaceLink; final String? marketplaceLink;
final String? diseaseTag;
ProductItem({ ProductItem({
required this.id, required this.id,
@ -17,6 +18,7 @@ class ProductItem {
this.description, this.description,
this.imageUrl, this.imageUrl,
this.marketplaceLink, this.marketplaceLink,
this.diseaseTag,
}); });
factory ProductItem.fromJson(Map<String, dynamic> json) { factory ProductItem.fromJson(Map<String, dynamic> json) {
@ -35,6 +37,7 @@ class ProductItem {
price: priceValue, price: priceValue,
imageUrl: json['image_url'], imageUrl: json['image_url'],
marketplaceLink: json['marketplace_link'], marketplaceLink: json['marketplace_link'],
diseaseTag: json['disease_tag'],
); );
} }
} }

View File

@ -19,7 +19,15 @@ public function index(Request $request)
$query->where('user_id', (int) $request->input('user_id')); $query->where('user_id', (int) $request->input('user_id'));
} }
$classifications = $query->paginate(15); $perPage = (int) $request->input('per_page', 15);
if ($perPage < 1) {
$perPage = 15;
}
if ($perPage > 1000) {
$perPage = 1000;
}
$classifications = $query->paginate($perPage);
return response()->json([ return response()->json([
'success' => true, 'success' => true,

View File

@ -12,12 +12,51 @@ public function index() {
return view('admin.products.index', compact('products')); return view('admin.products.index', compact('products'));
} }
public function edit(Product $product) {
return view('admin.products.edit', compact('product'));
}
public function update(Request $request, Product $product) {
$request->validate([
'name' => 'required',
'price' => 'required|numeric',
'image' => 'nullable|image|mimes:jpeg,png,jpg|max:2048',
'marketplace_link' => 'required|url|max:2048',
'disease_tag' => 'nullable|string|max:50'
]);
$imagePath = $product->image;
if ($request->hasFile('image')) {
$newPath = $this->compressAndStoreProductImage($request->file('image'))
?? $request->file('image')->store('products', 'public');
if ($newPath) {
if ($imagePath) {
Storage::disk('public')->delete($imagePath);
}
$imagePath = $newPath;
}
}
$product->update([
'name' => $request->name,
'description' => $request->description,
'price' => $request->price,
'image' => $imagePath,
'marketplace_link' => $request->marketplace_link,
'disease_tag' => $request->disease_tag ?: null
]);
return redirect()->route('produk.index')->with('success', 'Produk berhasil diperbarui!');
}
public function store(Request $request) { public function store(Request $request) {
$request->validate([ $request->validate([
'name' => 'required', 'name' => 'required',
'price' => 'required|numeric', 'price' => 'required|numeric',
'image' => 'image|mimes:jpeg,png,jpg|max:2048', 'image' => 'image|mimes:jpeg,png,jpg|max:2048',
'marketplace_link' => 'required|url|max:2048' 'marketplace_link' => 'required|url|max:2048',
'disease_tag' => 'nullable|string|max:50'
]); ]);
$imagePath = null; $imagePath = null;
@ -31,7 +70,8 @@ public function store(Request $request) {
'description' => $request->description, 'description' => $request->description,
'price' => $request->price, 'price' => $request->price,
'image' => $imagePath, 'image' => $imagePath,
'marketplace_link' => $request->marketplace_link 'marketplace_link' => $request->marketplace_link,
'disease_tag' => $request->disease_tag ?: null
]); ]);
return back()->with('success', 'Produk berhasil ditambahkan!'); return back()->with('success', 'Produk berhasil ditambahkan!');
@ -55,6 +95,7 @@ public function apiIndex(Request $request) {
'price' => $product->price, 'price' => $product->price,
'image_url' => $imageUrl, 'image_url' => $imageUrl,
'marketplace_link' => $product->marketplace_link, 'marketplace_link' => $product->marketplace_link,
'disease_tag' => $product->disease_tag,
]; ];
}); });

View File

@ -15,6 +15,7 @@ class Product extends Model
'description', 'description',
'price', 'price',
'image', 'image',
'marketplace_link' 'marketplace_link',
'disease_tag'
]; ];
} }

View File

@ -0,0 +1,28 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('products', function (Blueprint $table) {
$table->string('disease_tag', 50)->nullable()->after('marketplace_link');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('products', function (Blueprint $table) {
$table->dropColumn('disease_tag');
});
}
};

View File

@ -0,0 +1,68 @@
@extends('layouts.admin')
@section('title', 'Edit Produk')
@section('content')
@if(session('success'))
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded mb-4">
{{ session('success') }}
</div>
@endif
@if($errors->any())
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
<ul class="list-disc list-inside">
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<div class="max-w-2xl">
<div class="bg-white p-6 rounded-2xl shadow-sm border border-gray-100">
<h3 class="text-lg font-bold text-gray-800 mb-4 border-b pb-2">Edit Produk</h3>
<form action="{{ route('produk.update', $product) }}" method="POST" enctype="multipart/form-data">
@csrf
@method('PUT')
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Nama Produk</label>
<input type="text" name="name" value="{{ old('name', $product->name) }}" class="w-full border-gray-300 rounded-lg shadow-sm focus:ring-emerald-500 focus:border-emerald-500 p-2 border" required>
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Harga (Rp)</label>
<input type="number" name="price" value="{{ old('price', $product->price) }}" class="w-full border-gray-300 rounded-lg shadow-sm p-2 border" required>
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Deskripsi</label>
<textarea name="description" rows="3" class="w-full border-gray-300 rounded-lg shadow-sm p-2 border">{{ old('description', $product->description) }}</textarea>
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Link Marketplace</label>
<input type="url" name="marketplace_link" value="{{ old('marketplace_link', $product->marketplace_link) }}" class="w-full border-gray-300 rounded-lg shadow-sm p-2 border" required>
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Foto Produk</label>
<input type="file" name="image" class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-emerald-50 file:text-emerald-700 hover:file:bg-emerald-100">
<p class="text-xs text-gray-500 mt-1">Kosongkan jika tidak ingin mengganti.</p>
@if($product->image)
<div class="mt-3 flex items-center gap-3">
<img class="h-12 w-12 rounded-lg object-cover" src="{{ asset('storage/' . $product->image) }}" alt="">
<span class="text-xs text-gray-500">Foto saat ini</span>
</div>
@endif
</div>
<div class="flex items-center gap-3">
<button type="submit" class="bg-emerald-600 hover:bg-emerald-700 text-white font-bold py-2 px-4 rounded-lg transition">Simpan Perubahan</button>
<a href="{{ route('produk.index') }}" class="text-gray-600 hover:text-gray-900">Batal</a>
</div>
</form>
</div>
</div>
@endsection

View File

@ -46,6 +46,17 @@
<input type="url" name="marketplace_link" value="{{ old('marketplace_link') }}" class="w-full border-gray-300 rounded-lg shadow-sm p-2 border" placeholder="https://shopee.co.id/..." required> <input type="url" name="marketplace_link" value="{{ old('marketplace_link') }}" class="w-full border-gray-300 rounded-lg shadow-sm p-2 border" placeholder="https://shopee.co.id/..." required>
</div> </div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Kategori Penyakit</label>
<select name="disease_tag" class="w-full border-gray-300 rounded-lg shadow-sm p-2 border">
<option value="">Tidak terkait</option>
<option value="Bacterial Blight" {{ old('disease_tag') == 'Bacterial Blight' ? 'selected' : '' }}>Bacterial Blight</option>
<option value="Brown Spot" {{ old('disease_tag') == 'Brown Spot' ? 'selected' : '' }}>Brown Spot</option>
<option value="Leaf Smut" {{ old('disease_tag') == 'Leaf Smut' ? 'selected' : '' }}>Leaf Smut</option>
</select>
<p class="text-xs text-gray-500 mt-1">Kosongkan jika produk untuk umum.</p>
</div>
<div class="mb-4"> <div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Foto Produk</label> <label class="block text-sm font-medium text-gray-700 mb-1">Foto Produk</label>
<input type="file" name="image" class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-emerald-50 file:text-emerald-700 hover:file:bg-emerald-100"> <input type="file" name="image" class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-emerald-50 file:text-emerald-700 hover:file:bg-emerald-100">
@ -59,18 +70,18 @@
<div class="w-full lg:w-2/3"> <div class="w-full lg:w-2/3">
<div class="bg-white rounded-2xl shadow-sm border border-gray-100 overflow-hidden"> <div class="bg-white rounded-2xl shadow-sm border border-gray-100 overflow-hidden">
<table class="min-w-full divide-y divide-gray-200"> <table class="w-full table-fixed divide-y divide-gray-200">
<thead class="bg-gray-50"> <thead class="bg-gray-50">
<tr> <tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Info Produk</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider w-2/3">Info Produk</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Harga</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider w-32">Harga</th>
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Aksi</th> <th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider w-32">Aksi</th>
</tr> </tr>
</thead> </thead>
<tbody class="bg-white divide-y divide-gray-200"> <tbody class="bg-white divide-y divide-gray-200">
@foreach($products as $product) @foreach($products as $product)
<tr> <tr>
<td class="px-6 py-4 whitespace-nowrap"> <td class="px-6 py-4">
<div class="flex items-center"> <div class="flex items-center">
<div class="h-10 w-10 flex-shrink-0"> <div class="h-10 w-10 flex-shrink-0">
@if($product->image) @if($product->image)
@ -79,17 +90,36 @@
<div class="h-10 w-10 rounded-full bg-gray-200 flex items-center justify-center">📦</div> <div class="h-10 w-10 rounded-full bg-gray-200 flex items-center justify-center">📦</div>
@endif @endif
</div> </div>
<div class="ml-4"> <div class="ml-4 min-w-0">
<div class="text-sm font-medium text-gray-900">{{ $product->name }}</div> <div class="text-sm font-medium text-gray-900 truncate">{{ $product->name }}</div>
<div class="text-xs text-gray-500 truncate">
{{ $product->disease_tag ?: 'Tidak terkait' }}
</div>
</div> </div>
</div> </div>
</td> </td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Rp {{ number_format($product->price) }}</td> <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">Rp {{ number_format($product->price) }}</td>
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<div class="inline-flex items-center justify-end gap-3">
<button
type="button"
class="text-emerald-600 hover:text-emerald-900"
data-edit-product
data-id="{{ $product->id }}"
data-name="{{ $product->name }}"
data-price="{{ $product->price }}"
data-description="{{ $product->description }}"
data-marketplace="{{ $product->marketplace_link }}"
data-disease="{{ $product->disease_tag }}"
data-image="{{ $product->image ? asset('storage/' . $product->image) : '' }}"
>
Edit
</button>
<form action="{{ route('produk.destroy', $product->id) }}" method="POST" onsubmit="return confirm('Yakin hapus?')"> <form action="{{ route('produk.destroy', $product->id) }}" method="POST" onsubmit="return confirm('Yakin hapus?')">
@csrf @method('DELETE') @csrf @method('DELETE')
<button type="submit" class="text-red-600 hover:text-red-900">Hapus</button> <button type="submit" class="text-red-600 hover:text-red-900">Hapus</button>
</form> </form>
</div>
</td> </td>
</tr> </tr>
@endforeach @endforeach
@ -98,4 +128,120 @@
</div> </div>
</div> </div>
</div> </div>
<div id="editProductModal" class="fixed inset-0 z-50 hidden">
<div class="absolute inset-0 bg-black/40" data-edit-close></div>
<div class="absolute inset-0 flex items-center justify-center p-4">
<div class="bg-white w-full max-w-2xl rounded-2xl shadow-lg border border-gray-100">
<div class="flex items-center justify-between px-6 py-4 border-b">
<h3 class="text-lg font-bold text-gray-800">Edit Produk</h3>
<button type="button" class="text-gray-400 hover:text-gray-600" data-edit-close></button>
</div>
<form id="editProductForm" method="POST" enctype="multipart/form-data" class="p-6">
@csrf
@method('PUT')
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Nama Produk</label>
<input type="text" name="name" id="editName" class="w-full border-gray-300 rounded-lg shadow-sm focus:ring-emerald-500 focus:border-emerald-500 p-2 border" required>
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Harga (Rp)</label>
<input type="number" name="price" id="editPrice" class="w-full border-gray-300 rounded-lg shadow-sm p-2 border" required>
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Deskripsi</label>
<textarea name="description" id="editDescription" rows="3" class="w-full border-gray-300 rounded-lg shadow-sm p-2 border"></textarea>
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Link Marketplace</label>
<input type="url" name="marketplace_link" id="editMarketplace" class="w-full border-gray-300 rounded-lg shadow-sm p-2 border" required>
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Kategori Penyakit</label>
<select name="disease_tag" id="editDisease" class="w-full border-gray-300 rounded-lg shadow-sm p-2 border">
<option value="">Tidak terkait</option>
<option value="Bacterial Blight">Bacterial Blight</option>
<option value="Brown Spot">Brown Spot</option>
<option value="Leaf Smut">Leaf Smut</option>
</select>
<p class="text-xs text-gray-500 mt-1">Kosongkan jika produk untuk umum.</p>
</div>
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-1">Foto Produk</label>
<input type="file" name="image" class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-emerald-50 file:text-emerald-700 hover:file:bg-emerald-100">
<p class="text-xs text-gray-500 mt-1">Kosongkan jika tidak ingin mengganti.</p>
<div id="editImageWrap" class="mt-3 hidden items-center gap-3">
<img id="editImagePreview" class="h-12 w-12 rounded-lg object-cover" src="" alt="">
<span class="text-xs text-gray-500">Foto saat ini</span>
</div>
</div>
<div class="flex items-center gap-3">
<button type="submit" class="bg-emerald-600 hover:bg-emerald-700 text-white font-bold py-2 px-4 rounded-lg transition">Simpan Perubahan</button>
<button type="button" class="text-gray-600 hover:text-gray-900" data-edit-close>Batal</button>
</div>
</form>
</div>
</div>
</div>
<script>
const editModal = document.getElementById('editProductModal');
const editForm = document.getElementById('editProductForm');
const editName = document.getElementById('editName');
const editPrice = document.getElementById('editPrice');
const editDescription = document.getElementById('editDescription');
const editMarketplace = document.getElementById('editMarketplace');
const editDisease = document.getElementById('editDisease');
const editImageWrap = document.getElementById('editImageWrap');
const editImagePreview = document.getElementById('editImagePreview');
const openEditModal = (button) => {
const id = button.dataset.id;
editForm.action = `{{ url('produk') }}/${id}`;
editName.value = button.dataset.name || '';
editPrice.value = button.dataset.price || '';
editDescription.value = button.dataset.description || '';
editMarketplace.value = button.dataset.marketplace || '';
editDisease.value = button.dataset.disease || '';
if (button.dataset.image) {
editImagePreview.src = button.dataset.image;
editImageWrap.classList.remove('hidden');
editImageWrap.classList.add('flex');
} else {
editImagePreview.src = '';
editImageWrap.classList.add('hidden');
editImageWrap.classList.remove('flex');
}
editModal.classList.remove('hidden');
document.body.classList.add('overflow-hidden');
};
const closeEditModal = () => {
editModal.classList.add('hidden');
document.body.classList.remove('overflow-hidden');
};
document.querySelectorAll('[data-edit-product]').forEach((button) => {
button.addEventListener('click', () => openEditModal(button));
});
document.querySelectorAll('[data-edit-close]').forEach((button) => {
button.addEventListener('click', closeEditModal);
});
document.addEventListener('keydown', (event) => {
if (event.key === 'Escape' && !editModal.classList.contains('hidden')) {
closeEditModal();
}
});
</script>
@endsection @endsection

View File

@ -19,7 +19,9 @@
// Halaman Dashboard (Hanya bisa diakses jika sudah login) // Halaman Dashboard (Hanya bisa diakses jika sudah login)
Route::get('/dashboard', [DashboardController::class, 'index'])->middleware('auth')->name('dashboard'); Route::get('/dashboard', [DashboardController::class, 'index'])->middleware('auth')->name('dashboard');
Route::resource('produk', ProductController::class); Route::resource('produk', ProductController::class)->parameters([
'produk' => 'product'
]);
Route::resource('dataset', DatasetController::class); Route::resource('dataset', DatasetController::class);
Route::resource('history-klasifikasi', ClassificationHistoryAdminController::class) Route::resource('history-klasifikasi', ClassificationHistoryAdminController::class)
->only(['index', 'update', 'destroy']) ->only(['index', 'update', 'destroy'])