<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 }} </span > <span>-</span> <span> {{ localPaginationInfo.offset }}</span> <span> از </span> <span>{{ localPaginationInfo.total }}</span> <span> رکورد</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>