diff --git a/app/Http/Controllers/FotoSementaraController.php b/app/Http/Controllers/FotoSementaraController.php index 3aa5ecb..339ad6d 100644 --- a/app/Http/Controllers/FotoSementaraController.php +++ b/app/Http/Controllers/FotoSementaraController.php @@ -11,7 +11,7 @@ class FotoSementaraController extends Controller public function upload(Request $request) { $request->validate([ - 'id_produk' => 'required|exists:produk,id', + 'id_user' => 'required|exists:users,id', 'foto' => 'required|image|mimes:jpg,jpeg,png|max:2048', ]); @@ -19,11 +19,11 @@ class FotoSementaraController extends Controller $url = asset('storage/' . $path); $foto = FotoSementara::create([ - 'id_produk' => $request->id_produk, + 'id_user' => $request->id_user, 'url' => $url, ]); - return response()->json(['message' => 'Foto berhasil disimpan'], 201); + return response()->json($foto, 201); } public function hapus($id) @@ -45,6 +45,9 @@ class FotoSementaraController extends Controller public function getAll($user_id) { $data = FotoSementara::where('id_user', $user_id); + if (!$data->exists()) { + return response()->json(['message' => 'Tidak ada foto ditemukan'], 404); + } return response()->json($data); } diff --git a/app/Http/Controllers/NampanController.php b/app/Http/Controllers/NampanController.php index 396f90a..7bf5049 100644 --- a/app/Http/Controllers/NampanController.php +++ b/app/Http/Controllers/NampanController.php @@ -13,7 +13,7 @@ class NampanController extends Controller public function index() { return response()->json( - Nampan::withCount('items')->get() + Nampan::with('items.produk.foto')->withCount('items')->get() ); } @@ -43,7 +43,7 @@ class NampanController extends Controller public function show(int $id) { return response()->json( - Nampan::with('items')->find($id) + Nampan::with('items.produk.foto')->find($id) ); } diff --git a/app/Http/Controllers/TransaksiController.php b/app/Http/Controllers/TransaksiController.php index 0eb206a..055a1bb 100644 --- a/app/Http/Controllers/TransaksiController.php +++ b/app/Http/Controllers/TransaksiController.php @@ -13,14 +13,20 @@ class TransaksiController extends Controller // List semua transaksi public function index() { - $transaksi = Transaksi::with(['kasir', 'sales', 'items.item.produk'])->get(); + $limit = request()->query('limit', null); + $query = Transaksi::with(['kasir', 'sales', 'items.item.produk'])->latest(); + if ($limit) { + $query->limit((int)$limit); + } + $transaksi = $query->get(); + $transaksi = Transaksi::with(['kasir', 'sales', 'items.item.produk'])->latest()->limit(100)->get(); return response()->json($transaksi); } // Detail transaksi by ID public function show($id) { - $transaksi = Transaksi::with(['kasir', 'sales', 'items.item.produk'])->findOrFail($id); + $transaksi = Transaksi::with(['kasir', 'sales', 'items.item.produk.foto'])->findOrFail($id); return response()->json($transaksi); } diff --git a/app/Models/Nampan.php b/app/Models/Nampan.php index 80c8c4f..5044fba 100644 --- a/app/Models/Nampan.php +++ b/app/Models/Nampan.php @@ -13,9 +13,18 @@ class Nampan extends Model protected $fillable = [ 'nama' ]; + protected $appends = ['berat_total']; + public function items() { return $this->hasMany(Item::class, 'id_nampan'); } + + public function getBeratTotalAttribute() + { + return $this->items() + ->join('produks', 'items.id_produk', '=', 'produks.id') + ->sum('produks.berat'); + } } diff --git a/resources/js/components/InputField.vue b/resources/js/components/InputField.vue new file mode 100644 index 0000000..b82db89 --- /dev/null +++ b/resources/js/components/InputField.vue @@ -0,0 +1,28 @@ + + + diff --git a/resources/js/components/InputSelect.vue b/resources/js/components/InputSelect.vue new file mode 100644 index 0000000..1a3833e --- /dev/null +++ b/resources/js/components/InputSelect.vue @@ -0,0 +1,31 @@ + + + diff --git a/resources/js/components/ProductCard.vue b/resources/js/components/ProductCard.vue index 1253d5b..650784a 100644 --- a/resources/js/components/ProductCard.vue +++ b/resources/js/components/ProductCard.vue @@ -1,65 +1,31 @@ diff --git a/resources/js/pages/InputProduk.vue b/resources/js/pages/InputProduk.vue new file mode 100644 index 0000000..8ecfacd --- /dev/null +++ b/resources/js/pages/InputProduk.vue @@ -0,0 +1,384 @@ + + + diff --git a/resources/js/pages/Produk.vue b/resources/js/pages/Produk.vue index 8fe0318..566dce7 100644 --- a/resources/js/pages/Produk.vue +++ b/resources/js/pages/Produk.vue @@ -4,14 +4,27 @@

PRODUK

- - + +
+ + + + + +
-
@@ -22,78 +35,90 @@ v-for="item in filteredProducts" :key="item.id" :product="item" - @showDetail="openOverlay" + @click="openOverlay(item.id)" /> -
-
- - + +
+
+ +
+ + [gambar] - -
- - [gambar] -
- - -

{{ detail.item_count }} pcs

- - -

- {{ detail.nama }} -

- - -
-

Harga Beli : Rp. {{ formatNumber(detail.harga_beli) }}

-

{{ detail.kadar }} K

-

Harga Jual : Rp. {{ formatNumber(detail.harga_jual) }}

-

{{ detail.berat }} gram

-

- Harga/gram : Rp. {{ formatNumber(detail.harga_per_gram) }} -

-
- - -
- - - -
+ +
+ {{ detail.item_count }} pcs
+ + +
+ {{ detail.nama }} +
+ + + + +
+ + +
+ +

Harga Jual : Rp. {{ formatNumber(detail.harga_jual) }}

+

{{ detail.kadar }} K

+

+ Berat : {{ detail.berat }} gram +

+

+ Harga/gram : Rp. {{ formatNumber(detail.harga_per_gram) }} +

+
+ + +
+ + + +
+
+
+ @@ -106,10 +131,12 @@ import searchbar from "../components/searchbar.vue"; const products = ref([]); const searchQuery = ref(""); +const selectedCategory = ref("semua"); // overlay state const showOverlay = ref(false); const detail = ref({}); +const currentFotoIndex = ref(0); // Fetch data awal onMounted(async () => { @@ -121,29 +148,60 @@ onMounted(async () => { } }); -// Filter +// Filter gabungan (kategori + search) const filteredProducts = computed(() => { - if (!searchQuery.value) return products.value; - return products.value.filter((p) => - p.nama.toLowerCase().includes(searchQuery.value.toLowerCase()) - ); + let hasil = products.value; + + // filter kategori + if (selectedCategory.value !== "semua") { + hasil = hasil.filter( + (p) => p.kategori.toLowerCase() === selectedCategory.value + ); + } + + // filter search + if (searchQuery.value) { + hasil = hasil.filter((p) => + p.nama.toLowerCase().includes(searchQuery.value.toLowerCase()) + ); + } + + return hasil; }); -// Fungsi buka overlay +// buka overlay async function openOverlay(id) { try { const res = await axios.get(`http://127.0.0.1:8000/api/produk/${id}`); detail.value = res.data; + currentFotoIndex.value = 0; // reset ke foto pertama showOverlay.value = true; } catch (error) { console.error("Gagal fetch detail produk:", error); } } -// Fungsi tutup overlay +// tutup overlay function closeOverlay() { showOverlay.value = false; detail.value = {}; + currentFotoIndex.value = 0; +} + +// foto navigation +function nextFoto() { + if (detail.value.foto && detail.value.foto.length > 0) { + currentFotoIndex.value = + (currentFotoIndex.value + 1) % detail.value.foto.length; + } +} + +function prevFoto() { + if (detail.value.foto && detail.value.foto.length > 0) { + currentFotoIndex.value = + (currentFotoIndex.value - 1 + detail.value.foto.length) % + detail.value.foto.length; + } } // Format angka diff --git a/resources/js/router/index.js b/resources/js/router/index.js index f7e4dec..a08aa7a 100644 --- a/resources/js/router/index.js +++ b/resources/js/router/index.js @@ -3,6 +3,7 @@ import Home from '../pages/Home.vue' import Produk from '../pages/Produk.vue' import Brankas from '../pages/Brankas.vue' import Tray from '../pages/Tray.vue' +import InputProduk from '../pages/InputProduk.vue' const routes = [ @@ -16,6 +17,11 @@ const routes = [ name: 'Produk', component: Produk }, + { + path: '/produk/baru', + name: 'Produk', + component: InputProduk + }, { path: '/brankas', name: 'Brankas', diff --git a/routes/web.php b/routes/web.php index d6cbe28..fcdea34 100644 --- a/routes/web.php +++ b/routes/web.php @@ -19,10 +19,12 @@ Route::prefix('api')->group(function () { Route::apiResource('transaksi', TransaksiController::class); Route::get('brankas', [ItemController::class, 'brankasItem']); + + // Foto Sementara Route::post('foto/upload', [FotoSementaraController::class, 'upload']); - Route::delete('foto/hapus/', [FotoSementaraController::class, 'hapus']); - Route::get('foto/', [FotoSementaraController::class, 'getAll']); - Route::delete('foto/reset/', [FotoSementaraController::class, 'reset']); + Route::delete('foto/hapus/{id}', [FotoSementaraController::class, 'hapus']); + Route::get('foto/{user_id}', [FotoSementaraController::class, 'getAll']); + Route::delete('foto/reset/{user_id}', [FotoSementaraController::class, 'reset']); }); // Frontend SPA