290 lines
11 KiB
Vue
290 lines
11 KiB
Vue
<template>
|
|
<div
|
|
class="pt-5 px-4 py-3 flex items-center justify-between border-t border-gray-200 sm:px-6"
|
|
>
|
|
<div class="flex-1 flex justify-between sm:hidden">
|
|
<a
|
|
href="#"
|
|
class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:text-gray-500"
|
|
>
|
|
Previous
|
|
</a>
|
|
<a
|
|
href="#"
|
|
class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:text-gray-500"
|
|
>
|
|
Next
|
|
</a>
|
|
</div>
|
|
<div
|
|
class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between"
|
|
>
|
|
<div>
|
|
<p class="text-sm text-gray-700">
|
|
Showing
|
|
<span class="font-medium">{{ showingFrom }}</span>
|
|
to
|
|
<span class="font-medium">{{ showingTo }}</span>
|
|
of
|
|
<span class="font-medium">{{ recordsTotal }}</span>
|
|
results
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<nav
|
|
class="relative z-0 inline-flex shadow-sm -space-x-px"
|
|
aria-label="Pagination"
|
|
>
|
|
<a
|
|
href="javascript:void(0)"
|
|
class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50"
|
|
@click="gotoPage('first', 0)"
|
|
>
|
|
<span class="sr-only">First</span>
|
|
<!-- Heroicon name: chevron-double-left -->
|
|
<svg
|
|
class="w-6 h-6"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M11 19l-7-7 7-7m8 14l-7-7 7-7"
|
|
></path>
|
|
</svg>
|
|
</a>
|
|
|
|
<a
|
|
href="javascript:void(0)"
|
|
class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50"
|
|
@click="gotoPage('prev', 0)"
|
|
>
|
|
<span class="sr-only">Previous</span>
|
|
<!-- Heroicon name: chevron-left -->
|
|
<svg
|
|
class="h-5 w-5"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
viewBox="0 0 20 20"
|
|
fill="currentColor"
|
|
aria-hidden="true"
|
|
>
|
|
<path
|
|
fill-rule="evenodd"
|
|
d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z"
|
|
clip-rule="evenodd"
|
|
/>
|
|
</svg>
|
|
</a>
|
|
|
|
<a
|
|
v-for="(item, index) in currentSlots"
|
|
:key="index"
|
|
href="javascript:void(0)"
|
|
:class="
|
|
currentSlots[index] == currentPageNumber
|
|
? 'bg-gray-200'
|
|
: 'bg-white'
|
|
"
|
|
class="relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50"
|
|
@click="gotoPage(currentSlots[index], index)"
|
|
>
|
|
{{ currentSlots[index] }}
|
|
</a>
|
|
|
|
<a
|
|
href="javascript:void(0)"
|
|
class="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50"
|
|
@click="gotoPage('next', 0)"
|
|
>
|
|
<span class="sr-only">Next</span>
|
|
<!-- Heroicon name: chevron-right -->
|
|
<svg
|
|
class="h-5 w-5"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
viewBox="0 0 20 20"
|
|
fill="currentColor"
|
|
aria-hidden="true"
|
|
>
|
|
<path
|
|
fill-rule="evenodd"
|
|
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
|
|
clip-rule="evenodd"
|
|
/>
|
|
</svg>
|
|
</a>
|
|
|
|
<a
|
|
href="javascript:void(0)"
|
|
class="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50"
|
|
@click="gotoPage('last', 0)"
|
|
>
|
|
<span class="sr-only">Last</span>
|
|
<!-- Heroicon name: chevron-double-right -->
|
|
<svg
|
|
class="w-6 h-6"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M13 5l7 7-7 7M5 5l7 7-7 7"
|
|
></path>
|
|
</svg>
|
|
</a>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import {
|
|
ChevronLeftIcon,
|
|
ChevronRightIcon,
|
|
} from '@heroicons/vue/solid/index.js';
|
|
|
|
import { computed } from 'vue';
|
|
|
|
const props = defineProps({
|
|
totalPageCount: { type: Number, default: 1 },
|
|
currentPageNumber: { type: Number, default: 1 },
|
|
pageSize: { type: Number, default: 10 },
|
|
recordsTotal: { type: Number, default: 0 },
|
|
pageMove: { type: Function, required: true },
|
|
});
|
|
|
|
const pagenationSize = 5;
|
|
|
|
//console.log(props);
|
|
|
|
const showingFrom = computed(() => {
|
|
const result = 1 + (props.currentPageNumber - 1) * props.pageSize;
|
|
return result;
|
|
});
|
|
|
|
//console.log(showingFrom.value);
|
|
|
|
const showingTo = computed(() => {
|
|
let result = props.currentPageNumber * props.pageSize;
|
|
if (result > props.recordsTotal) {
|
|
result = props.recordsTotal;
|
|
}
|
|
return result;
|
|
});
|
|
|
|
const currentSlots = computed(() => {
|
|
const result: string[] = [];
|
|
if (props.totalPageCount > pagenationSize) {
|
|
if (props.currentPageNumber < Math.ceil(pagenationSize / 2)) {
|
|
for (let i = 1; i < pagenationSize; i++) {
|
|
// good for 3, 4, ....
|
|
result.push(i.toString());
|
|
}
|
|
result.push('...');
|
|
} else if (
|
|
props.currentPageNumber >
|
|
props.totalPageCount - pagenationSize / 2
|
|
) {
|
|
result.push('...');
|
|
for (
|
|
let i = props.totalPageCount - pagenationSize + 1;
|
|
i <= props.totalPageCount;
|
|
i++
|
|
) {
|
|
// good for 3, 4, ....
|
|
result.push(i.toString());
|
|
}
|
|
} else {
|
|
result.push('...');
|
|
for (
|
|
let i =
|
|
props.currentPageNumber - Math.floor(pagenationSize / 2);
|
|
i < props.currentPageNumber + Math.ceil(pagenationSize / 2);
|
|
i++
|
|
) {
|
|
// good for 3, 4, ....
|
|
result.push(i.toString());
|
|
}
|
|
result.push('...');
|
|
}
|
|
} else {
|
|
for (let i = 1; i <= props.totalPageCount; i++) {
|
|
result.push(i.toString());
|
|
}
|
|
}
|
|
|
|
//console.log('result = ', result);
|
|
|
|
return result;
|
|
});
|
|
|
|
function gotoPage(target, opt) {
|
|
//console.log('gotoPage, target=', target);
|
|
let targetPageIndex = props.currentPageNumber;
|
|
switch (target) {
|
|
case 'first':
|
|
targetPageIndex = 1;
|
|
break;
|
|
case 'prev':
|
|
if (props.currentPageNumber > 1) {
|
|
targetPageIndex = props.currentPageNumber - 1;
|
|
} else {
|
|
targetPageIndex = props.currentPageNumber;
|
|
}
|
|
break;
|
|
case 'next':
|
|
if (props.totalPageCount > props.currentPageNumber) {
|
|
targetPageIndex = props.currentPageNumber + 1;
|
|
} else {
|
|
targetPageIndex = props.currentPageNumber;
|
|
}
|
|
|
|
break;
|
|
case 'last':
|
|
targetPageIndex = props.totalPageCount;
|
|
break;
|
|
|
|
case '...':
|
|
if (opt == 0) {
|
|
if (props.currentPageNumber - pagenationSize > 0) {
|
|
targetPageIndex = props.currentPageNumber - pagenationSize;
|
|
} else {
|
|
targetPageIndex = 1;
|
|
}
|
|
} else {
|
|
if (
|
|
props.currentPageNumber + pagenationSize <
|
|
props.totalPageCount
|
|
) {
|
|
targetPageIndex = props.currentPageNumber + pagenationSize;
|
|
} else {
|
|
targetPageIndex = props.totalPageCount;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
const tmpPageIdx = parseInt(target);
|
|
if (tmpPageIdx >= 1 && tmpPageIdx <= props.totalPageCount) {
|
|
targetPageIndex = tmpPageIdx;
|
|
} else {
|
|
targetPageIndex = props.currentPageNumber;
|
|
}
|
|
}
|
|
//console.log('final targetPageIdex = ', targetPageIndex);
|
|
|
|
// console.log('huk', this);
|
|
// this.$parent.pageMove(targetPageIndex);
|
|
// $emit('pageMove', targetPageIndex);
|
|
props.pageMove(targetPageIndex);
|
|
}
|
|
</script>
|