Files
panel/resources/js/views/demos/forms/tables/data-table/DemoDataTableKitchenSink.vue

306 lines
6.5 KiB
Vue
Raw Normal View History

2025-08-04 16:33:07 +03:30
<script setup>
const {
data: productList,
error,
} = await useApi('pages/datatable')
const search = ref('')
// headers
const headers = [
{
title: 'PRODUCT',
key: 'product.name',
},
{
title: 'DATE',
key: 'date',
},
{
title: 'CATEGORY',
key: 'product.category',
},
{
title: 'BUYERS',
key: 'buyer.name',
},
{
title: 'PAYMENT',
key: 'payment',
sortable: false,
},
{
title: 'STATUS',
key: 'status',
sortable: false,
},
{
title: 'DELETE',
key: 'delete',
sortable: false,
},
]
const deleteItem = itemId => {
if (!productList.value)
return
const index = productList.value.findIndex(item => item.product.id === itemId)
productList.value.splice(index, 1)
}
const categoryIcons = [
{
name: 'Mouse',
icon: 'tabler-mouse',
color: 'warning',
},
{
name: 'Glass',
icon: 'tabler-eyeglass',
color: 'primary',
},
{
name: 'Smart Watch',
icon: 'tabler-device-watch',
color: 'success',
},
{
name: 'Bag',
icon: 'tabler-briefcase',
color: 'info',
},
{
name: 'Storage Device',
icon: 'tabler-device-audio-tape',
color: 'warning',
},
{
name: 'Bluetooth',
icon: 'tabler-bluetooth',
color: 'error',
},
{
name: 'Gaming',
icon: 'tabler-device-gamepad-2',
color: 'warning',
},
{
name: 'Home',
icon: 'tabler-home',
color: 'error',
},
{
name: 'VR',
icon: 'tabler-badge-vr',
color: 'primary',
},
{
name: 'Shoes',
icon: 'tabler-shoe',
color: 'success',
},
{
name: 'Electronics',
icon: 'tabler-cpu',
color: 'info',
},
{
name: 'Projector',
icon: 'tabler-theater',
color: 'warning',
},
{
name: 'iPod',
icon: 'tabler-device-airpods',
color: 'error',
},
{
name: 'Keyboard',
icon: 'tabler-keyboard',
color: 'primary',
},
{
name: 'Smart Phone',
icon: 'tabler-device-mobile',
color: 'success',
},
{
name: 'Smart TV',
icon: 'tabler-device-tv',
color: 'info',
},
{
name: 'Google Home',
icon: 'tabler-brand-google',
color: 'warning',
},
{
name: 'Mac',
icon: 'tabler-brand-apple',
color: 'error',
},
{
name: 'Headphone',
icon: 'tabler-headphones',
color: 'primary',
},
{
name: 'iMac',
icon: 'tabler-device-imac',
color: 'success',
},
{
name: 'iPhone',
icon: 'tabler-brand-apple',
color: 'warning',
},
]
const resolveStatusColor = status => {
if (status === 'Confirmed')
return 'primary'
if (status === 'Completed')
return 'success'
if (status === 'Cancelled')
return 'error'
}
const categoryIconFilter = categoryName => {
const index = categoryIcons.findIndex(category => category.name === categoryName)
if (index !== -1)
return [{
icon: categoryIcons[index].icon,
color: categoryIcons[index].color,
}]
return [{
icon: 'tabler-help-circle',
color: 'primary',
}]
}
if (error.value)
console.error(error.value)
</script>
<template>
<div>
<VCardText>
<VRow>
<VCol
cols="12"
offset-md="8"
md="4"
>
<AppTextField
v-model="search"
placeholder="Search ..."
append-inner-icon="tabler-search"
single-line
hide-details
dense
outlined
/>
</VCol>
</VRow>
</VCardText>
<!-- 👉 Data Table -->
<VDataTable
:headers="headers"
:items="productList || []"
:search="search"
:items-per-page="5"
class="text-no-wrap"
>
<!-- product -->
<template #item.product.name="{ item }">
<div class="d-flex align-center">
<div>
<VImg
:src="item.product.image"
height="40"
width="40"
/>
</div>
<div class="d-flex flex-column ms-3">
<span class="d-block font-weight-medium text-truncate text-high-emphasis">{{ item.product.name }}</span>
<span class="text-xs">{{ item.product.brand }}</span>
</div>
</div>
</template>
<!-- category -->
<template #item.product.category="{ item }">
<div class="d-flex align-center">
<VAvatar
v-for="(category, index) in categoryIconFilter(item.product.category)"
:key="index"
size="26"
:color="category.color"
variant="tonal"
>
<VIcon
size="20"
:color="category.color"
class="rounded-0"
>
{{ category.icon }}
</VIcon>
</VAvatar>
<span class="ms-1 text-no-wrap">{{ item.product.category }}</span>
</div>
</template>
<!-- buyer -->
<template #item.buyer.name="{ item }">
<div class="d-flex align-center">
<VAvatar
size="1.875rem"
:color="!item.buyer.avatar ? 'primary' : undefined"
:variant="!item.buyer.avatar ? 'tonal' : undefined"
>
<VImg
v-if="item.buyer.avatar"
:src="item.buyer.avatar"
/>
<span v-else>{{ item.buyer.name.slice(0, 2).toUpperCase() }}</span>
</VAvatar>
<span class="text-no-wrap font-weight-medium text-high-emphasis ms-2">{{ item.buyer.name }}</span>
</div>
</template>
<!-- Payment -->
<template #item.payment="{ item }">
<div class="d-flex flex-column">
<div class="d-flex align-center">
<span class="text-high-emphasis font-weight-medium">${{ item.payment.paidAmount }}</span>
<span v-if="item.payment.paidAmount !== item.payment.total">/{{ item.payment.total }}</span>
</div>
<span class="text-xs text-no-wrap">{{ item.payment.receivedPaymentStatus }}</span>
</div>
</template>
<!-- Status -->
<template #item.status="{ item }">
<VChip
:color="resolveStatusColor(item.payment.status)"
:class="`text-${resolveStatusColor(item.payment.status)}`"
size="small"
class="font-weight-medium"
>
{{ item.payment.status }}
</VChip>
</template>
<!-- Delete -->
<template #item.delete="{ item }">
<IconBtn @click="deleteItem(item.product.id)">
<VIcon icon="tabler-trash" />
</IconBtn>
</template>
</VDataTable>
</div>
</template>