Penyesuaian tabel dan SEO

This commit is contained in:
Baghaztra 2025-10-24 05:16:15 +07:00
parent 8ad64a986d
commit 9ccc26455e
3 changed files with 60 additions and 53 deletions

View File

@ -52,45 +52,52 @@
{{ props.search ? 'Item tidak ditemukan.' : 'Brankas kosong.' }} {{ props.search ? 'Item tidak ditemukan.' : 'Brankas kosong.' }}
</div> </div>
<div v-else class="overflow-x-auto border border-C rounded-lg shadow-sm"> <div class="bg-white rounded-lg shadow-md overflow-x-auto">
<table class="min-w-full divide-y divide-C"> <table class="w-full">
<thead class="bg-A"> <thead>
<tr> <tr class="bg-C text-white border-D border">
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-D uppercase tracking-wider"> <th class="px-6 py-4 text-center border-r border-D text-D">No</th>
Gambar <th class="px-6 py-4 text-center border-r border-D text-D">Nama Produk</th>
</th> <th class="px-6 py-4 text-center border-r border-D text-D">Kode Item</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-D uppercase tracking-wider"> <th class="px-6 py-4 text-center border-r border-D text-D">Berat</th>
Nama Produk <th class="px-6 py-4 text-center text-D">Aksi</th>
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-D uppercase tracking-wider">
Kode Item
</th>
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-D uppercase tracking-wider">
Berat
</th>
</tr> </tr>
</thead> </thead>
<tbody class="bg-white divide-y divide-gray-200"> <tbody>
<tr v-for="item in filteredItems" :key="item.id" <tr v-for="(item, index) in filteredItems" :key="item.id"
class="hover:bg-gray-50 transition cursor-pointer" class="border-b border-C border-t-0 border-x hover:bg-gray-50 transition duration-150"
@click="openMovePopup(item)"> :class="{ 'bg-gray-50': index % 2 === 1 }">
<td class="px-6 py-4 whitespace-nowrap"> <td class="px-6 py-4 border-r border-C text-center font-medium text-gray-900">
<img v-if="item.produk?.foto?.length" :src="item.produk?.foto[0].url" {{ index + 1 }}
class="size-12 object-cover rounded" </td>
@error="handleImageError" /> <td class="px-6 py-4 border-r border-C text-D font-semibold">
<div class="size-12 bg-gray-200 rounded flex items-center justify-center" v-else> {{ item.produk?.nama }}
<i class="fas fa-image text-gray-400"></i> </td>
<td class="px-6 py-4 border-r border-C text-gray-800 font-semibold">
{{ item.kode_item }}
</td>
<td class="px-6 py-4 border-r border-C text-D font-medium">
{{ item.produk?.berat }}g
</td>
<td class="px-6 py-4 text-center">
<button @click="openMovePopup(item)"
class="px-3 py-1 bg-blue-500 text-white text-sm rounded hover:bg-blue-600 transition duration-200">
Detail
</button>
</td>
</tr>
<!-- Empty State -->
<tr v-if="filteredItems.length === 0">
<td colspan="5" class="px-6 py-8 text-center text-gray-500">
<div class="flex flex-col items-center">
<svg class="w-12 h-12 text-gray-400 mb-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2M4 13h2" />
</svg>
<p>Tidak ada data item di brankas</p>
</div> </div>
</td> </td>
<td class="px-6 py-4 whitespace-nowrap">
<p class="font-semibold text-D">{{ item.produk?.nama }}</p>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<p class="text-sm text-gray-500 font-semibold">{{ item.kode_item }}</p>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<span class="font-medium text-D">{{ item.produk?.berat }}g</span>
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@ -202,7 +209,7 @@ const selectedItem = ref(null);
const selectedTrayId = ref(""); const selectedTrayId = ref("");
const errorMove = ref(""); const errorMove = ref("");
const isMoving = ref(false); const isMoving = ref(false);
const isAdmin = localStorage.getItem('role') == 'admin' const isAdmin = localStorage.getItem('role') == 'owner'
const showDeleteConfirm = ref(false); const showDeleteConfirm = ref(false);
@ -223,19 +230,19 @@ const totalWeight = computed(() => {
const filteredItems = computed(() => { const filteredItems = computed(() => {
let filtered = items.value; let filtered = items.value;
if (props.search) { if (props.search) {
filtered = filtered.filter((item) => filtered = filtered.filter((item) =>
item.produk?.nama?.toLowerCase().includes(props.search.toLowerCase()) || item.produk?.nama?.toLowerCase().includes(props.search.toLowerCase()) ||
item.kode_item?.toLowerCase().includes(props.search.toLowerCase()) item.kode_item?.toLowerCase().includes(props.search.toLowerCase())
); );
} }
// Sorting berdasarkan nama produk // Sorting berdasarkan nama produk
return filtered.sort((a, b) => { return filtered.sort((a, b) => {
const nameA = (a.produk?.nama || "").toLowerCase(); const nameA = (a.produk?.nama || "").toLowerCase();
const nameB = (b.produk?.nama || "").toLowerCase(); const nameB = (b.produk?.nama || "").toLowerCase();
if (sortOrder.value === "asc") { if (sortOrder.value === "asc") {
return nameA.localeCompare(nameB); return nameA.localeCompare(nameB);
} else { } else {

View File

@ -91,17 +91,17 @@
<!-- Dropdown --> <!-- Dropdown -->
<div class="mb-4"> <div class="mb-4">
<label for="tray-select" class="block text-sm font-medium mb-1">Nama Nampan</label> <label for="tray-select" class="block text-sm font-medium mb-1">Nama Nampan</label>
<InputSelect v-if="isAdmin" v-model="selectedTrayId" <InputSelect v-model="selectedTrayId"
:options="[ { label: 'Brankas', value: 0 }, ...trays.map(tray => ({ label: tray.nama, value: tray.id })) ]" placeholder="Pilih Nampan" :options="[ { label: 'Brankas', value: 0 }, ...trays.map(tray => ({ label: tray.nama, value: tray.id })) ]" placeholder="Pilih Nampan"
class="mt-2" /> class="mt-2" />
<div class="bg-A px-3 py-2 rounded text-D font-medium" v-else> <!-- <div class="bg-A px-3 py-2 rounded text-D font-medium" v-else>
{{trays.find(tray => tray.id === selectedTrayId)?.nama}} {{trays.find(tray => tray.id === selectedTrayId)?.nama}}
</div> </div> -->
</div> </div>
<div class="flex justify-end gap-2"> <div class="flex justify-end gap-2">
<button @click="closePopup" class="px-4 py-2 rounded bg-gray-400 hover:bg-gray-500 text-white transition"> <button @click="closePopup" class="px-4 py-2 rounded bg-gray-400 hover:bg-gray-500 text-white transition">
{{ isAdmin ? 'Batal' : 'Tutup' }} Batal
</button> </button>
<!-- Tombol Hapus hanya muncul kalau Admin --> <!-- Tombol Hapus hanya muncul kalau Admin -->
@ -110,7 +110,7 @@
<i class="fas fa-trash mr-2"></i>Hapus <i class="fas fa-trash mr-2"></i>Hapus
</button> </button>
<button v-if="isAdmin" @click="saveMove" :disabled="!selectedTrayId" class="px-4 py-2 rounded transition" <button @click="saveMove" :disabled="!selectedTrayId" class="px-4 py-2 rounded transition"
:class="selectedTrayId ? 'bg-C hover:bg-C/80 text-D' : 'bg-gray-400 cursor-not-allowed'"> :class="selectedTrayId ? 'bg-C hover:bg-C/80 text-D' : 'bg-gray-400 cursor-not-allowed'">
Simpan Simpan
</button> </button>

View File

@ -5,21 +5,21 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@yield('title', config('app.name', 'Abbauf App'))</title> <title>@yield('title', 'Kasir Toko Mas Jakarta Citayam')</title>
<meta name="description" content="@yield('description', 'Deskripsi default untuk aplikasi Abbauf.')"> <meta name="description" content="@yield('description', 'Aplikasi kasir internal untuk pengelolaan transaksi dan stok emas di Toko Mas Jakarta Citayam.')">
<meta name="author" content="Nama Anda atau Perusahaan Anda"> <meta name="author" content="Abbauf Tech">
<meta property="og:title" content="@yield('title', config('app.name', 'Abbauf App'))" /> <meta property="og:title" content="@yield('title', 'Kasir Toko Mas Jakarta Citayam')" />
<meta property="og:description" content="@yield('description', 'Deskripsi default untuk aplikasi Abbauf.')" /> <meta property="og:description" content="@yield('description', 'Aplikasi kasir internal untuk pengelolaan transaksi dan stok emas di Toko Mas Jakarta Citayam.')" />
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:url" content="{{ url()->current() }}" /> <meta property="og:url" content="{{ url()->current() }}" />
<meta property="og:image" content="@yield('og_image', asset('images/default-social-image.jpg'))" /> <meta property="og:image" content="@yield('og_image', asset('build/assets/logo-BATkcDH-.png'))" />
<meta name="twitter:card" content="summary_large_image"> <meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="@yield('title', config('app.name', 'Abbauf App'))"> <meta name="twitter:title" content="@yield('title', 'Kasir Toko Mas Jakarta Citayam')">
<meta name="twitter:description" content="@yield('description', 'Deskripsi default untuk aplikasi Abbauf.')"> <meta name="twitter:description" content="@yield('description', 'Aplikasi kasir internal untuk pengelolaan transaksi dan stok emas di Toko Mas Jakarta Citayam.')">
<meta name="twitter:image" content="@yield('og_image', asset('images/default-social-image.jpg'))"> <meta name="twitter:image" content="@yield('og_image', asset('build/assets/logo-BATkcDH-.png'))">
<link rel="icon" href="{{ asset('logo.ico') }}" type="image/x-icon"> <link rel="icon" href="{{ asset('logo.ico') }}" type="image/x-icon">
<link rel="apple-touch-icon" href="{{ asset('apple-touch-icon.png') }}"> <link rel="apple-touch-icon" href="{{ asset('apple-touch-icon.png') }}">