salix-front/src/components/ui/VnPaginate.vue

189 lines
4.5 KiB
Vue

<script setup>
import { onMounted, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useArrayData } from 'composables/useArrayData';
const { t } = useI18n();
const props = defineProps({
dataKey: {
type: String,
required: true,
},
autoLoad: {
type: Boolean,
default: false,
},
data: {
type: Array,
default: null,
},
url: {
type: String,
default: '',
},
filter: {
type: Object,
default: null,
},
where: {
type: Object,
default: null,
},
order: {
type: String,
default: '',
},
limit: {
type: Number,
default: 10,
},
userParams: {
type: Object,
default: null,
},
offset: {
type: Number,
default: 500,
},
skeleton: {
type: Boolean,
default: true,
},
});
const emit = defineEmits(['onFetch', 'onPaginate']);
defineExpose({ fetch });
const isLoading = ref(false);
const pagination = ref({
sortBy: props.order,
rowsPerPage: props.limit,
page: 1,
});
const arrayData = useArrayData(props.dataKey, {
url: props.url,
filter: props.filter,
where: props.where,
limit: props.limit,
order: props.order,
userParams: props.userParams,
});
const store = arrayData.store;
onMounted(() => {
if (props.autoLoad) fetch();
});
watch(
() => props.data,
() => {
store.data = props.data;
}
);
async function fetch() {
await arrayData.fetch({ append: false });
if (!arrayData.hasMoreData.value) {
isLoading.value = false;
}
emit('onFetch', store.data);
}
async function paginate() {
const { page, rowsPerPage, sortBy, descending } = pagination.value;
if (!props.url) return;
isLoading.value = true;
await arrayData.loadMore();
if (!arrayData.hasMoreData.value) {
isLoading.value = false;
return;
}
pagination.value.rowsNumber = store.data.length;
pagination.value.page = page;
pagination.value.rowsPerPage = rowsPerPage;
pagination.value.sortBy = sortBy;
pagination.value.descending = descending;
isLoading.value = false;
emit('onFetch', store.data);
emit('onPaginate');
}
async function onLoad(...params) {
if (!store.data) return;
const done = params[1];
if (store.data.length === 0 || !props.url) return done(false);
pagination.value.page = pagination.value.page + 1;
await paginate();
const endOfPages = !arrayData.hasMoreData.value;
done(endOfPages);
}
</script>
<template>
<div>
<div
v-if="!props.autoLoad && !store.data && !isLoading"
class="info-row q-pa-md text-center"
>
<h5>
{{ t('No data to display') }}
</h5>
</div>
<div
v-if="props.skeleton && props.autoLoad && !store.data"
class="card-list q-gutter-y-md"
>
<QCard class="card" v-for="$index in $props.limit" :key="$index">
<QItem v-ripple class="q-pa-none items-start cursor-pointer q-hoverable">
<QItemSection class="q-pa-md">
<QSkeleton type="rect" class="q-mb-md" square />
<QSkeleton type="text" square />
<QSkeleton type="text" class="q-mb-md" square />
<QSkeleton type="text" square />
<QSkeleton type="text" square />
</QItemSection>
<QSeparator vertical />
<QCardActions vertical class="justify-between">
<QSkeleton type="circle" class="q-mb-md" size="40px" />
<QSkeleton type="circle" class="q-mb-md" size="40px" />
<QSkeleton type="circle" class="q-mb-md" size="40px" />
</QCardActions>
</QItem>
</QCard>
</div>
</div>
<QInfiniteScroll v-if="store.data" @load="onLoad" :offset="offset" class="full-width">
<slot name="body" :rows="store.data"></slot>
<div v-if="isLoading" class="info-row q-pa-md text-center">
<QSpinner color="orange" size="md" />
</div>
</QInfiniteScroll>
</template>
<style lang="scss" scoped>
.info-row {
width: 100%;
h5 {
margin: 0;
}
}
</style>
<i18n>
es:
No data to display: Sin datos que mostrar
No results found: No se han encontrado resultados
</i18n>