From d231ebe90999183e2a8d18197eb0745d21219172 Mon Sep 17 00:00:00 2001 From: adityaalfarison Date: Fri, 29 Aug 2025 11:07:46 +0700 Subject: [PATCH 1/3] brankaslist, traylist --- resources/js/components/BrankasList.vue | 3 +- resources/js/components/TrayList.vue | 220 ++++++++++++++++-------- 2 files changed, 150 insertions(+), 73 deletions(-) diff --git a/resources/js/components/BrankasList.vue b/resources/js/components/BrankasList.vue index 0135531..5532207 100644 --- a/resources/js/components/BrankasList.vue +++ b/resources/js/components/BrankasList.vue @@ -20,7 +20,7 @@ - {{ item.berat }}g + {{ item.produk.berat }}g @@ -39,6 +39,7 @@ const props = defineProps({ }); const items = ref([]); +const produk = ref([]) const loading = ref(true); const error = ref(null); diff --git a/resources/js/components/TrayList.vue b/resources/js/components/TrayList.vue index 85e8124..9453e41 100644 --- a/resources/js/components/TrayList.vue +++ b/resources/js/components/TrayList.vue @@ -1,66 +1,49 @@ + +
+
+
+
+ QR Code +
+
+
{{ selectedItem.produk.nama }}
+
{{ selectedItem.produk.kategori }}
+
+ +
+
+ + +
+
+ + +
+
+
+ \ No newline at end of file + +// Daftar nampan lain (selain tempat item saat ini) +const availableTrays = computed(() => { + if (!selectedItem.value || !trays.value) return []; + return trays.value.filter( + (tray) => Number(tray.id) !== Number(selectedItem.value.id_nampan) + ); +}); + +onMounted(() => { + refreshData(); +}); + From 8a0ded4b3e26d80316211cb0f0e3a9cb367516d5 Mon Sep 17 00:00:00 2001 From: adityaalfarison Date: Fri, 29 Aug 2025 11:22:18 +0700 Subject: [PATCH 2/3] update itemcontroller, traylist DONE --- app/Http/Controllers/ItemController.php | 4 ++-- resources/js/components/TrayList.vue | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/app/Http/Controllers/ItemController.php b/app/Http/Controllers/ItemController.php index 399e5e0..3e336d4 100644 --- a/app/Http/Controllers/ItemController.php +++ b/app/Http/Controllers/ItemController.php @@ -52,8 +52,8 @@ class ItemController extends Controller public function update(Request $request, int $id) { $validated = $request->validate([ - 'id_produk' => 'required|in:produks.id', - 'id_nampan' => 'nullable|in:nampans.id' + 'id_produk' => 'required|exists:produks,id', + 'id_nampan' => 'nullable|exists:nampans,id' ],[ 'id_produk' => 'Id produk tidak valid.', 'id_nampan' => 'Id nampan tidak valid' diff --git a/resources/js/components/TrayList.vue b/resources/js/components/TrayList.vue index 9453e41..de19062 100644 --- a/resources/js/components/TrayList.vue +++ b/resources/js/components/TrayList.vue @@ -34,10 +34,12 @@
+ v-for="item in tray.items" + :key="item.id" + class="flex justify-between items-center border rounded-lg p-2" + @click="openMovePopup(item)" +> +
{{ item.produk.berat }}g -
@@ -168,16 +164,20 @@ const closePopup = () => { const saveMove = async () => { if (!selectedTrayId.value || !selectedItem.value) return; try { - await axios.put(`/api/item/${selectedItem.value.id}`, { nampan_id: selectedTrayId.value }); + await axios.put(`/api/item/${selectedItem.value.id}`, { + id_nampan: selectedTrayId.value, + id_produk: selectedItem.value.id_produk, // ikutkan id_produk karena API minta + }); await refreshData(); closePopup(); } catch (err) { - console.error("Gagal memindahkan item:", err); + console.error("Gagal memindahkan item:", err.response?.data || err); alert("Gagal memindahkan item. Silakan coba lagi."); } }; + // --- Ambil data nampan + item --- const refreshData = async () => { try { From 2eb29d6dc9bbb8a5b7d1bd9d4b46d1d726a73c38 Mon Sep 17 00:00:00 2001 From: Baghaztra Date: Fri, 29 Aug 2025 15:20:30 +0700 Subject: [PATCH 3/3] [update] Filter kategori --- app/Http/Controllers/ProdukController.php | 2 +- app/Models/Kategori.php | 2 +- database/seeders/DatabaseSeeder.php | 2 +- resources/js/pages/InputProduk.vue | 38 +++++++++------ resources/js/pages/Produk.vue | 56 +++++++++++++++-------- routes/web.php | 2 + 6 files changed, 66 insertions(+), 36 deletions(-) diff --git a/app/Http/Controllers/ProdukController.php b/app/Http/Controllers/ProdukController.php index 404dff9..d91f2a8 100644 --- a/app/Http/Controllers/ProdukController.php +++ b/app/Http/Controllers/ProdukController.php @@ -28,7 +28,7 @@ class ProdukController extends Controller { $validated = $request->validate([ 'nama' => 'required|string|max:100', - 'id_kategori' => 'required|exists:users,id', + 'id_kategori' => 'required|exists:kategoris,id', 'berat' => 'required|numeric', 'kadar' => 'required|integer', 'harga_per_gram' => 'required|numeric', diff --git a/app/Models/Kategori.php b/app/Models/Kategori.php index 3abc4fa..b76a659 100644 --- a/app/Models/Kategori.php +++ b/app/Models/Kategori.php @@ -15,7 +15,7 @@ class Kategori extends Model protected $hidden = ['created_at', 'updated_at', 'deleted_at']; - public function produks() + public function produk() { return $this->hasMany(Produk::class, 'id_kategori'); } diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 70d55af..5ec537c 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -37,7 +37,7 @@ class DatabaseSeeder extends Seeder } } - $kategoriList = ['cincin', 'gelang', 'kalung', 'anting']; + $kategoriList = ['cincin', 'gelang rantai', 'gelang bulat', 'kalung', 'liontin', 'anting', 'giwang']; foreach ($kategoriList as $kategori) { Kategori::factory()->create([ 'nama' => $kategori diff --git a/resources/js/pages/InputProduk.vue b/resources/js/pages/InputProduk.vue index 5f4a1ae..05fcfe8 100644 --- a/resources/js/pages/InputProduk.vue +++ b/resources/js/pages/InputProduk.vue @@ -20,7 +20,7 @@
- +
@@ -69,20 +69,20 @@
+ class="w-12 h-12 bg-D rounded-lg flex items-center justify-center mx-auto mb-2 group-hover:bg-D transition-colors">
-
+
{ + try { + const response = await axios.get('/api/kategori'); + if (response.data && Array.isArray(response.data)) { + category.value = response.data.map(cat => ({ + value: cat.id, + label: cat.nama + })); + } + } catch (error) { + console.error('Error loading categories:', error); + } +}; const loading = ref(false); const uploadLoading = ref(false); @@ -163,7 +172,7 @@ const createdProduct = ref(null); const isFormValid = computed(() => { return form.value.nama && - form.value.kategori && + form.value.id_kategori && form.value.berat > 0 && form.value.kadar > 0 && form.value.harga_per_gram > 0 && @@ -311,7 +320,7 @@ const submitForm = async (addItem) => { // Reset form form.value = { nama: '', - kategori: '', + id_kategori: '', berat: 0, kadar: 0, harga_per_gram: 0, @@ -347,7 +356,7 @@ const submitForm = async (addItem) => { const resetForm = async () => { form.value = { nama: '', - kategori: '', + id_kategori: '', berat: 0, kadar: 0, harga_per_gram: 0, @@ -372,5 +381,6 @@ const back = () => { onMounted(() => { loadExistingPhotos(); + loadKategori(); }); diff --git a/resources/js/pages/Produk.vue b/resources/js/pages/Produk.vue index e57a268..5ea1019 100644 --- a/resources/js/pages/Produk.vue +++ b/resources/js/pages/Produk.vue @@ -21,16 +21,7 @@
- + @@ -160,10 +151,11 @@ import ProductCard from "../components/ProductCard.vue"; import searchbar from "../components/searchbar.vue"; import CreateItemModal from "../components/CreateItemModal.vue"; import ConfirmDeleteModal from "../components/ConfirmDeleteModal.vue"; +import InputSelect from "../components/InputSelect.vue"; const products = ref([]); const searchQuery = ref(""); -const selectedCategory = ref("semua"); +const selectedCategory = ref(0); const creatingItem = ref(false); const deleting = ref(false); @@ -171,6 +163,36 @@ const detail = ref({}); const showOverlay = ref(false); const currentFotoIndex = ref(0); +const kategori = ref([]); + +const loadKategori = async () => { + try { + const response = await axios.get('/api/kategori'); + if (response.data && Array.isArray(response.data)) { + kategori.value = [ + { value: 0, label: "Semua" }, + ...response.data.map(cat => ({ + value: cat.id, + label: cat.nama + })) + ]; + } + } catch (error) { + console.error('Error loading categories:', error); + } +}; + +const loadProduk = async () => { + try { + const response = await axios.get('/api/produk'); + if (response.data && Array.isArray(response.data)) { + products.value = response.data; + } + } catch (error) { + console.error('Error loading products:', error); + } +}; + // Buka modal item const openItemModal = () => { creatingItem.value = true; @@ -181,21 +203,17 @@ const closeItemModal = () => { // Fetch data awal onMounted(async () => { - try { - const res = await axios.get("/api/produk"); - products.value = res.data; - } catch (error) { - console.error("Gagal ambil data produk:", error); - } + loadKategori() + loadProduk(); }); // Filter produk (kategori + search) const filteredProducts = computed(() => { let hasil = products.value; - if (selectedCategory.value !== "semua") { + if (selectedCategory.value != 0) { hasil = hasil.filter( - (p) => p.kategori.toLowerCase() === selectedCategory.value + (p) => p.id_kategori == selectedCategory.value ); } diff --git a/routes/web.php b/routes/web.php index ac3aef3..e4d9f5a 100644 --- a/routes/web.php +++ b/routes/web.php @@ -2,6 +2,7 @@ use App\Http\Controllers\FotoSementaraController; use App\Http\Controllers\ItemController; +use App\Http\Controllers\KategoriController; use App\Http\Controllers\NampanController; use App\Http\Controllers\ProdukController; use App\Http\Controllers\SalesController; @@ -17,6 +18,7 @@ Route::prefix('api')->group(function () { Route::apiResource('sales', SalesController::class); Route::apiResource('user', UserController::class); Route::apiResource('transaksi', TransaksiController::class); + Route::apiResource('kategori', KategoriController::class); Route::get('brankas', [ItemController::class, 'brankasItem']);