Files

177 lines
5.2 KiB
Vue
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup>
import { ref, watch } from 'vue';
import Pagination from './Pagination.vue';
import DataTable from 'primevue/datatable';
import Column from 'primevue/column';
import Button from 'primevue/button';
import InputText from 'primevue/inputtext';
import Toolbar from 'primevue/toolbar';
const props = defineProps({
data: {
type: Array,
required: true,
default: () => []
},
columns: {
type: Array,
required: true,
default: () => []
},
selectable: {
type: Boolean,
default: false
},
modelValue: {
type: Array,
default: () => []
},
pagination: {
type: Object,
default: () => null
},
searchable: {
type: Boolean,
default: true
},
searchValue: {
type: String,
default: ''
}
});
const emit = defineEmits(['update:modelValue', 'selection-change', 'page-change', 'search-change']);
const localSelection = ref(props.modelValue);
watch(() => props.modelValue, (newValue) => {
localSelection.value = newValue;
}, { immediate: true });
const handleSelectionChange = (event) => {
localSelection.value = event;
emit('update:modelValue', event);
emit('selection-change', event);
};
const localSearchValue = ref(props.searchValue);
watch(() => props.searchValue, (newValue) => {
localSearchValue.value = newValue;
}, { immediate: true });
const handleSearchClick = () => {
emit('search-change', localSearchValue.value);
};
const renderColumnContent = (column, data) => {
let content = '';
if (column.render && typeof column.render === 'function') {
content = column.render(data);
} else {
content = data[column.key];
}
const defaultStyle = '!text-[11px] !font-normal';
const customStyle = column.style || defaultStyle;
return `<span class="${customStyle} text-right wrap-break-word text-sm">${content}</span>`;
};
const getColumnStyle = (column) => {
const baseStyle = { minWidth: '120px' };
if (column.width) {
baseStyle.width = column.width + 'px';
baseStyle.minWidth = column.width + 'px';
baseStyle.maxWidth = column.width + 'px';
}
return baseStyle;
};
</script>
<template>
<div class="table-generic">
<div v-if="searchable" class="p-4">
<Toolbar class="">
<template #start>
<div class="grid grid-cols-2a justify-start gap-2">
<InputText
size="small"
class="placeholder:!font-light placeholder:!text-xs"
placeholder="جستجو..."
type="text"
v-model="localSearchValue"
/>
<Button
:pt="{icon : 'flex'}"
icon="fi fi-rr-search"
class="!text-xs"
severity="secondary"
@click="handleSearchClick"
/>
</div>
<div v-if="localSelection && localSelection.length > 0" class="mr-2 !h-9 grid grid-cols-1">
<slot name="bulk-action" :selection="localSelection"></slot>
</div>
</template>
<template #end>
<slot name="toolbar-actions"></slot>
</template>
</Toolbar>
</div>
<div class="table-generic-scroll">
<DataTable
:value="data"
dataKey="id"
v-model:selection="localSelection"
:showGridlines="false"
:stripedRows="false"
@selection-change="handleSelectionChange"
>
<template #empty>
<div class="flex justify-center py-4 items-center h-full">
<span class="text-center text-sm">هیچ داده‌ای پیدا نشده!</span>
</div>
</template>
<Column
v-if="selectable"
selectionMode="multiple"
headerStyle="width: 4rem"
/>
<Column
v-for="column in columns"
:key="column.key"
:field="column.key"
:header="column.title"
:sortable="column.hasSort === true"
:style="getColumnStyle(column)"
>
<template #body="{ data }">
<slot v-if="column.slot" :name="`column-${column.key}`" :data="data" :column="column">
<div v-html="renderColumnContent(column, data)"></div>
</slot>
<div v-else v-html="renderColumnContent(column, data)"></div>
</template>
</Column>
</DataTable>
</div>
<Pagination
v-if="pagination && pagination.total"
:total="pagination.total"
:current-page="pagination.current_page"
:perPage="pagination.per_page"
:lastPage="pagination.last_page"
:links="pagination.links"
@page-change="(page) => emit('page-change', page)"
/>
</div>
</template>