base_ui/components/global/JahatPagination.vue

310 lines
11 KiB
Vue
Raw Normal View History

2025-02-01 09:34:55 +00:00
<template>
<div
class="jahat-pagination d-flex align-items-center flex-wrap border-top mt-3 p-2 rounded-0"
:class="pagination.alignment['between']"
>
<div
v-if="showTotalRecords"
class="form-group d-flex align-items-center ml-3 mb-0"
>
<span
>{{
localPaginationInfo.offset + localPaginationInfo.limit
}}&nbsp;</span
>
<span>-</span>
<span>&nbsp;{{ localPaginationInfo.offset }}</span>
<span>&nbsp;از&nbsp;</span>
<span>{{ localPaginationInfo.total }}</span>
<span>&nbsp;رکورد</span>
<label
style="width: auto; font-size: inherit; color: inherit"
for="exampleFormControlSelect1"
class="no-wrap ml-2 mr-4 mb-0"
>
تعداد سطرها
</label>
<select
style="min-width: 3.5em"
v-model="localPaginationInfo.limit"
@change="limitChanged"
class="form-control"
id="exampleFormControlSelect1"
>
<option :value="5">5</option>
<option :value="10">10</option>
<option :value="15">15</option>
<option :value="20">20</option>
<option :value="25">25</option>
<option :value="50">50</option>
<option :value="75">75</option>
<option :value="100">100</option>
</select>
</div>
<div v-if="showPageSelection" class="d-flex align-items-center">
<input
type="number"
dir="ltr"
v-model.number="localPaginationInfo.page"
class="form-control font-weight-bold"
id="page-id"
placeholder="00"
name="page-id"
aria-label="وارد کردن شماره صفحه"
size="10000"
@keyup="sendQuery()"
@keydown="onKeyDown()"
/>
<UPagination
:active-button="{ variant: 'outline' }"
:inactive-button="{ color: 'gray' }"
:total="localPaginationInfo.total"
:prev-button="{
icon: '',
label: 'قبلی',
color: 'gray',
}"
:next-button="{
icon: '',
trailing: true,
label: 'بعدی',
color: 'gray',
}"
v-model="localPaginationInfo.page"
:max="3"
:page-count="localPaginationInfo.pages"
@click.prevent="clickCallback"
>
</UPagination>
<!-- :first-button="{
icon: 'i-heroicons-arrow-small-right-20-solid',
label: 'ابتدا',
color: 'gray',
}"
:last-button="{
icon: 'i-heroicons-arrow-small-left-20-solid',
trailing: true,
label: 'آخر',
color: 'gray',
}"
show-first
show-last -->
<!-- :prev-text="'قبلی'"
:margin-pages="2"
:next-text="'بعدی'"
:last-button-text="'آخر'"
:first-button-text="'ابتدا'"
:container-class="pagination.containerClass"
:page-class="pagination.pageClass"
:page-link-class="pagination.linkClass"
:prev-class="pagination.prevClass"
:prev-link-class="pagination.prevLinkClass"
:next-class="pagination.nextClass"
:next-link-class="pagination.nextLinkClass" -->
</div>
</div>
</template>
<script>
import { mapActions } from "pinia";
import { useCommonStore } from "~/stores/commonStore";
// import Paginate from "vuejs-paginate-next";
/**
* @vue-prop {Object} [paginationInfo] - اطلاعات صفحه بندی
* @vue-prop {Number} [paginationInfo.pages=0] - تعداد کل صفحات
* @vue-prop {Number} [paginationInfo.total=0] - تعداد کل آیتمها
* @vue-prop {Number} [paginationInfo.page=1] - صفحه فعلی
* @vue-prop {Number} [paginationInfo.offset=0] - آفست (صفحه * تعداد در هر صفحه)
* @vue-prop {Number} [paginationInfo.limit=10] - تعداد در هر صفحه
*
* @vue-data {Number} [typingTimer=0] - تایمر تایپ
* @vue-data {Number} [doneTypingInterval=500] - فاصله زمانی برای اتمام تایپ (به میلیثانیه)
* @vue-data {Object} [pagination] - تنظیمات صفحه بندی
* @vue-data {String} [pagination.containerClass="pagination"] - کلاس کانتینر صفحه بندی
* @vue-data {String} [pagination.activeClass="active"] - کلاس فعال
* @vue-data {String} [pagination.disabledClass="disabled"] - کلاس غیرفعال
* @vue-data {String} [pagination.pageClass="page-item"] - کلاس آیتم صفحه
* @vue-data {String} [pagination.linkClass="page-link"] - کلاس لینک صفحه
* @vue-data {String} [pagination.prevClass="page-item"] - کلاس آیتم صفحه قبلی
* @vue-data {String} [pagination.prevLinkClass="page-link"] - کلاس لینک صفحه قبلی
* @vue-data {String} [pagination.nextClass="page-item"] - کلاس آیتم صفحه بعدی
* @vue-data {String} [pagination.nextLinkClass="page-link"] - کلاس لینک صفحه بعدی
* @vue-data {Object} [pagination.alignment] - تنظیمات تراز صفحه بندی
* @vue-data {String} [pagination.alignment.start="justify-content-start"] - تراز ابتدا
* @vue-data {String} [pagination.alignment.center="justify-content-center"] - تراز مرکز
* @vue-data {String} [pagination.alignment.end="justify-content-end"] - تراز انتها
* @vue-data {String} [pagination.alignment.between="justify-content-between"] - تراز بین
* @vue-data {Object} [pagination.icons] - آیکونهای صفحه بندی
* @vue-data {String} [pagination.icons.first="fas fa-angle-double-right"] - آیکون صفحه اول
* @vue-data {String} [pagination.icons.prev="fas fa-angle-right"] - آیکون صفحه قبلی
* @vue-data {String} [pagination.icons.next="fas fa-angle-left"] - آیکون صفحه بعدی
* @vue-data {String} [pagination.icons.last="fas fa-angle-double-left"] - آیکون آخرین صفحه
* @vue-data {Object} [localPaginationInfo] - اطلاعات صفحه بندی محلی
* @vue-data {Number} [localPaginationInfo.pages=0] - تعداد کل صفحات
* @vue-data {Number} [localPaginationInfo.total=0] - تعداد کل آیتمها
* @vue-data {Number} [localPaginationInfo.page=1] - صفحه فعلی
* @vue-data {Number} [localPaginationInfo.offset=0] - آفست (صفحه * تعداد در هر صفحه)
* @vue-data {Number} [localPaginationInfo.limit=10] - تعداد در هر صفحه
*/
export default {
props: {
showPageSelection: {
default: true,
},
showTotalRecords: {
default: true,
},
paginationInfo: {
default() {
return {
pages: 0,
total: 0,
page: 1,
offset: 0,
limit: 10,
};
},
},
},
mounted() {
// const plainPaginationInfo = JSON.parse(JSON.stringify(this.paginationInfo));
// this.localPaginationInfo = structuredClone(plainPaginationInfo);
// this.localPaginationInfo = structuredClone(this.paginationInfo);
this.localPaginationInfo = this.paginationInfo;
this.paginationSetter(this.localPaginationInfo);
},
watch: {
paginationInfo(newVal) {
// this.localPaginationInfo = structuredClone(newVal);
this.localPaginationInfo = newVal;
this.paginationSetter(this.localPaginationInfo);
},
},
data() {
return {
typingTimer: 0,
doneTypingInterval: 500,
pagination: {
containerClass: "pagination",
activeClass: "active",
disabledClass: "disabled",
pageClass: "page-item",
linkClass: "page-link",
prevClass: "page-item",
prevLinkClass: "page-link",
nextClass: "page-item",
nextLinkClass: "page-link",
alignment: {
start: "justify-content-start",
center: "justify-content-center",
end: "justify-content-end",
between: "justify-content-between",
},
icons: {
first: "fas fa-angle-double-right",
prev: "fas fa-angle-right",
next: "fas fa-angle-left",
last: "fas fa-angle-double-left",
},
},
localPaginationInfo: {
pages: 0,
total: 0,
page: 1,
offset: 0,
limit: 10,
},
};
},
methods: {
...mapActions(useCommonStore, ["paginationSetter"]),
/**
* ارسال درخواست جستجو پس از اتمام تایپ.
* اگر کاربر تایپ را متوقف کند، پس از مدت زمان مشخصی (doneTypingInterval) این متد اجرا میشود.
* صفحه فعلی و محدودیت نتایج را به روز میکند و آنها را به کامپوننت والد ارسال میکند.
*/
sendQuery() {
clearTimeout(this.typingTimer);
this.typingTimer = setTimeout(() => {
if (this.localPaginationInfo.page.length == 0)
this.localPaginationInfo.page = 1;
this.$emit("page-changed", {
pageNumber: this.localPaginationInfo.page,
limit: this.localPaginationInfo.limit,
});
this.paginationSetter(this.localPaginationInfo);
}, this.doneTypingInterval);
},
/**
* هنگامی که کلیدی فشار داده میشود، تایمر تایپ کردن را متوقف میکند.
*/
onKeyDown() {
clearTimeout(this.typingTimer);
},
/**
* تغییر تعداد نتایج صفحه.
* تعداد جدید را تنظیم کرده و آن را به کامپوننت والد ارسال میکند.
*/
limitChanged() {
this.$emit("page-limit-changed", {
pageNumber: 1,
limit: this.localPaginationInfo.limit,
});
this.paginationSetter(this.localPaginationInfo);
},
/**
* تغییر صفحه هنگامی که کاربر روی شماره صفحه کلیک میکند.
* صفحه جدید را تنظیم کرده و آدرس URL را بهروزرسانی میکند.
* @param {number} pageNumber - شماره صفحه جدید.
*/
clickCallback(evt) {
this.$emit("page-changed", {
pageNumber: this.paginationInfo.page,
limit: this.localPaginationInfo.limit,
});
this.paginationSetter(this.localPaginationInfo);
// this.$router.replace({
// query: { ...this.$route.query, page: pageNumber },
// });
// this.$route.query = {...this.$route.query, page: pageNumber};
let path = this.$route.fullPath;
if (this.$route.query.page)
path = path.replace(
`page=${this.$route.query.page}`,
`page=${this.paginationInfo.page}`
);
else path = path + `?page=${this.paginationInfo.page}`;
history.pushState({}, document.title, path);
},
},
// components: ["Paginate"],
};
</script>
<style scoped>
.form-control[type="number"] {
width: 4em;
text-align: center;
}
</style>