mirror of https://github.com/halo-dev/halo
refactor: refactor pagination component to support display total items (#4303)
#### What type of PR is this? /area console /kind improvement /milestone 2.8.x #### What this PR does / why we need it: 重构 Console 的分页组件,以支持显示数据总条数。 #### Which issue(s) this PR fixes: Fixes #4268 #### Special notes for your reviewer: 需要测试: - 测试各个页面的分页功能是否正常 #### Does this PR introduce a user-facing change? ```release-note 重构 Console 的分页组件,以支持显示数据总条数。 ```pull/4323/head
parent
4733008e16
commit
02c47f552a
|
@ -8,16 +8,20 @@ const props = withDefaults(
|
|||
size?: number;
|
||||
total?: number;
|
||||
sizeOptions?: number[];
|
||||
showTotal?: boolean;
|
||||
pageLabel?: string;
|
||||
sizeLabel?: string;
|
||||
totalLabel?: string;
|
||||
}>(),
|
||||
{
|
||||
page: 1,
|
||||
size: 10,
|
||||
total: 0,
|
||||
sizeOptions: () => [10],
|
||||
showTotal: true,
|
||||
pageLabel: "页",
|
||||
sizeLabel: "条 / 页",
|
||||
totalLabel: undefined,
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -33,6 +37,13 @@ const hasNext = computed(() => props.page < totalPages.value);
|
|||
|
||||
const hasPrevious = computed(() => props.page > 1);
|
||||
|
||||
const totalLabelText = computed(() => {
|
||||
if (props.totalLabel) {
|
||||
return props.totalLabel;
|
||||
}
|
||||
return `共 ${props.total} 项数据`;
|
||||
});
|
||||
|
||||
const onPageChange = (event: Event) => {
|
||||
const target = event.target as HTMLSelectElement;
|
||||
const page = Number(target.value);
|
||||
|
@ -67,64 +78,45 @@ const next = () => {
|
|||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="bg-white flex items-center justify-between">
|
||||
<div class="flex-1 flex justify-between sm:!hidden items-center">
|
||||
<button
|
||||
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:bg-gray-50 cursor-pointer"
|
||||
:disabled="!hasPrevious"
|
||||
@click="previous"
|
||||
>
|
||||
<IconArrowLeft />
|
||||
</button>
|
||||
<span class="text-sm text-gray-500"> {{ page }} / {{ totalPages }} </span>
|
||||
<button
|
||||
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:bg-gray-50 cursor-pointer"
|
||||
:disabled="!hasNext"
|
||||
@click="next"
|
||||
>
|
||||
<IconArrowRight />
|
||||
</button>
|
||||
<div class="pagination">
|
||||
<div v-if="showTotal" class="pagination__total">
|
||||
{{ totalLabelText }}
|
||||
</div>
|
||||
<div class="hidden sm:flex-1 sm:flex sm:items-center items-center gap-2">
|
||||
<nav
|
||||
aria-label="Pagination"
|
||||
class="relative z-0 inline-flex rounded-base shadow-sm -space-x-px"
|
||||
>
|
||||
<div class="pagination__controller">
|
||||
<nav aria-label="Pagination" class="pagination__nav">
|
||||
<button
|
||||
class="relative h-8 outline-none inline-flex items-center px-2 py-1.5 rounded-l-base border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 cursor-pointer disabled:cursor-not-allowed"
|
||||
class="pagination__btn pagination__btn--prev"
|
||||
:disabled="!hasPrevious"
|
||||
@click="previous"
|
||||
>
|
||||
<IconArrowLeft />
|
||||
</button>
|
||||
<button
|
||||
class="relative h-8 outline-none inline-flex items-center px-2 py-1.5 rounded-r-base border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 cursor-pointer disabled:cursor-not-allowed"
|
||||
class="pagination__btn pagination__btn--next"
|
||||
:disabled="!hasNext"
|
||||
@click="next"
|
||||
>
|
||||
<IconArrowRight />
|
||||
</button>
|
||||
</nav>
|
||||
<div class="inline-flex items-center gap-2">
|
||||
<div class="pagination__select-wrap">
|
||||
<select
|
||||
:value="page"
|
||||
:disabled="totalPages === 0"
|
||||
class="h-8 border outline-none rounded-base px-2 text-gray-800 text-sm border-gray-300"
|
||||
class="pagination__select"
|
||||
@change="onPageChange"
|
||||
>
|
||||
<option v-if="totalPages === 0" :value="0">0 / 0</option>
|
||||
<option v-for="i in totalPages" :key="i" :value="i">
|
||||
<option v-if="totalPages === 0" :value="1">0 / 0</option>
|
||||
<option v-for="i in totalPages || 1" :key="i" :value="i">
|
||||
{{ i }} / {{ totalPages }}
|
||||
</option>
|
||||
</select>
|
||||
<span class="text-sm text-gray-500">{{ pageLabel }}</span>
|
||||
<span class="pagination__select-label">
|
||||
{{ pageLabel }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="inline-flex items-center gap-2">
|
||||
<select
|
||||
:value="size"
|
||||
class="h-8 border outline-none rounded-base px-2 text-gray-800 text-sm border-gray-300"
|
||||
@change="onSizeChange"
|
||||
>
|
||||
<div class="pagination__select-wrap">
|
||||
<select :value="size" class="pagination__select" @change="onSizeChange">
|
||||
<option
|
||||
v-for="(sizeOption, index) in sizeOptions"
|
||||
:key="index"
|
||||
|
@ -133,8 +125,52 @@ const next = () => {
|
|||
{{ sizeOption }}
|
||||
</option>
|
||||
</select>
|
||||
<span class="text-sm text-gray-500">{{ sizeLabel }}</span>
|
||||
<span class="pagination__select-label">
|
||||
{{ sizeLabel }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.pagination {
|
||||
@apply bg-white flex items-center flex-1 gap-2;
|
||||
|
||||
&__total {
|
||||
@apply hidden sm:block text-sm text-gray-500;
|
||||
}
|
||||
|
||||
&__controller {
|
||||
@apply flex items-center gap-2 flex-1 justify-end;
|
||||
}
|
||||
|
||||
&__nav {
|
||||
@apply relative z-0 inline-flex rounded-base shadow-sm -space-x-px;
|
||||
}
|
||||
|
||||
&__btn {
|
||||
@apply relative h-8 outline-none inline-flex items-center px-2 py-1.5 rounded-base border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50 cursor-pointer disabled:cursor-not-allowed;
|
||||
|
||||
&--prev {
|
||||
@apply rounded-r-none;
|
||||
}
|
||||
|
||||
&--next {
|
||||
@apply rounded-l-none;
|
||||
}
|
||||
}
|
||||
|
||||
&__select-wrap {
|
||||
@apply inline-flex items-center gap-2;
|
||||
}
|
||||
|
||||
&__select {
|
||||
@apply h-8 border outline-none rounded-base px-2 text-gray-800 text-sm border-gray-300;
|
||||
}
|
||||
|
||||
&__select-label {
|
||||
@apply text-sm text-gray-500;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1149,6 +1149,7 @@ core:
|
|||
pagination:
|
||||
page_label: page
|
||||
size_label: items per page
|
||||
total_label: Total {total} items
|
||||
social_auth_providers:
|
||||
title: Third-party login
|
||||
app_download_alert:
|
||||
|
|
|
@ -1149,6 +1149,7 @@ core:
|
|||
pagination:
|
||||
page_label: 页
|
||||
size_label: 条 / 页
|
||||
total_label: 共 {total} 项数据
|
||||
social_auth_providers:
|
||||
title: 三方登录
|
||||
app_download_alert:
|
||||
|
|
|
@ -1149,6 +1149,7 @@ core:
|
|||
pagination:
|
||||
page_label: 頁
|
||||
size_label: 條 / 頁
|
||||
total_label: 共 {total} 項資料
|
||||
social_auth_providers:
|
||||
title: 三方登入
|
||||
app_download_alert:
|
||||
|
|
|
@ -669,16 +669,17 @@ onMounted(() => {
|
|||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="bg-white sm:flex sm:items-center sm:justify-end">
|
||||
<VPagination
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:page-label="$t('core.components.pagination.page_label')"
|
||||
:size-label="$t('core.components.pagination.size_label')"
|
||||
:total="total"
|
||||
:size-options="[60, 120, 200]"
|
||||
/>
|
||||
</div>
|
||||
<VPagination
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:page-label="$t('core.components.pagination.page_label')"
|
||||
:size-label="$t('core.components.pagination.size_label')"
|
||||
:total-label="
|
||||
$t('core.components.pagination.total_label', { total: total })
|
||||
"
|
||||
:total="total"
|
||||
:size-options="[60, 120, 200]"
|
||||
/>
|
||||
</template>
|
||||
</VCard>
|
||||
</div>
|
||||
|
|
|
@ -196,12 +196,15 @@ const isDisabled = (attachment: Attachment) => {
|
|||
</div>
|
||||
</VCard>
|
||||
</div>
|
||||
<div class="mt-4 bg-white sm:flex sm:items-center sm:justify-end">
|
||||
<div class="mt-4">
|
||||
<VPagination
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:page-label="$t('core.components.pagination.page_label')"
|
||||
:size-label="$t('core.components.pagination.size_label')"
|
||||
:total-label="
|
||||
$t('core.components.pagination.total_label', { total: total })
|
||||
"
|
||||
:total="total"
|
||||
:size-options="[60, 120, 200]"
|
||||
/>
|
||||
|
|
|
@ -387,16 +387,17 @@ const handleApproveInBatch = async () => {
|
|||
</Transition>
|
||||
|
||||
<template #footer>
|
||||
<div class="bg-white sm:flex sm:items-center sm:justify-end">
|
||||
<VPagination
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:page-label="$t('core.components.pagination.page_label')"
|
||||
:size-label="$t('core.components.pagination.size_label')"
|
||||
:total="total"
|
||||
:size-options="[20, 30, 50, 100]"
|
||||
/>
|
||||
</div>
|
||||
<VPagination
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:page-label="$t('core.components.pagination.page_label')"
|
||||
:size-label="$t('core.components.pagination.size_label')"
|
||||
:total-label="
|
||||
$t('core.components.pagination.total_label', { total: total })
|
||||
"
|
||||
:total="total"
|
||||
:size-options="[20, 30, 50, 100]"
|
||||
/>
|
||||
</template>
|
||||
</VCard>
|
||||
</div>
|
||||
|
|
|
@ -409,16 +409,17 @@ watch(
|
|||
</Transition>
|
||||
|
||||
<template #footer>
|
||||
<div class="bg-white sm:flex sm:items-center sm:justify-end">
|
||||
<VPagination
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:page-label="$t('core.components.pagination.page_label')"
|
||||
:size-label="$t('core.components.pagination.size_label')"
|
||||
:total="total"
|
||||
:size-options="[20, 30, 50, 100]"
|
||||
/>
|
||||
</div>
|
||||
<VPagination
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:page-label="$t('core.components.pagination.page_label')"
|
||||
:size-label="$t('core.components.pagination.size_label')"
|
||||
:total-label="
|
||||
$t('core.components.pagination.total_label', { total: total })
|
||||
"
|
||||
:total="total"
|
||||
:size-options="[20, 30, 50, 100]"
|
||||
/>
|
||||
</template>
|
||||
</VCard>
|
||||
</div>
|
||||
|
|
|
@ -472,16 +472,17 @@ watch(selectedPageNames, (newValue) => {
|
|||
</Transition>
|
||||
|
||||
<template #footer>
|
||||
<div class="bg-white sm:flex sm:items-center sm:justify-end">
|
||||
<VPagination
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:page-label="$t('core.components.pagination.page_label')"
|
||||
:size-label="$t('core.components.pagination.size_label')"
|
||||
:total="total"
|
||||
:size-options="[20, 30, 50, 100]"
|
||||
/>
|
||||
</div>
|
||||
<VPagination
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:page-label="$t('core.components.pagination.page_label')"
|
||||
:size-label="$t('core.components.pagination.size_label')"
|
||||
:total-label="
|
||||
$t('core.components.pagination.total_label', { total: total })
|
||||
"
|
||||
:total="total"
|
||||
:size-options="[20, 30, 50, 100]"
|
||||
/>
|
||||
</template>
|
||||
</VCard>
|
||||
</div>
|
||||
|
|
|
@ -422,16 +422,17 @@ watch(
|
|||
</Transition>
|
||||
|
||||
<template #footer>
|
||||
<div class="bg-white sm:flex sm:items-center sm:justify-end">
|
||||
<VPagination
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:page-label="$t('core.components.pagination.page_label')"
|
||||
:size-label="$t('core.components.pagination.size_label')"
|
||||
:total="total"
|
||||
:size-options="[20, 30, 50, 100]"
|
||||
/>
|
||||
</div>
|
||||
<VPagination
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:page-label="$t('core.components.pagination.page_label')"
|
||||
:size-label="$t('core.components.pagination.size_label')"
|
||||
:total-label="
|
||||
$t('core.components.pagination.total_label', { total: total })
|
||||
"
|
||||
:total="total"
|
||||
:size-options="[20, 30, 50, 100]"
|
||||
/>
|
||||
</template>
|
||||
</VCard>
|
||||
</div>
|
||||
|
|
|
@ -483,16 +483,17 @@ watch(selectedPostNames, (newValue) => {
|
|||
</Transition>
|
||||
|
||||
<template #footer>
|
||||
<div class="bg-white sm:flex sm:items-center sm:justify-end">
|
||||
<VPagination
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:page-label="$t('core.components.pagination.page_label')"
|
||||
:size-label="$t('core.components.pagination.size_label')"
|
||||
:total="total"
|
||||
:size-options="[20, 30, 50, 100]"
|
||||
/>
|
||||
</div>
|
||||
<VPagination
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:page-label="$t('core.components.pagination.page_label')"
|
||||
:size-label="$t('core.components.pagination.size_label')"
|
||||
:total-label="
|
||||
$t('core.components.pagination.total_label', { total: total })
|
||||
"
|
||||
:total="total"
|
||||
:size-options="[20, 30, 50, 100]"
|
||||
/>
|
||||
</template>
|
||||
</VCard>
|
||||
</div>
|
||||
|
|
|
@ -243,16 +243,17 @@ onMounted(() => {
|
|||
</Transition>
|
||||
|
||||
<template #footer>
|
||||
<div class="bg-white sm:flex sm:items-center sm:justify-end">
|
||||
<VPagination
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:page-label="$t('core.components.pagination.page_label')"
|
||||
:size-label="$t('core.components.pagination.size_label')"
|
||||
:total="total"
|
||||
:size-options="[10, 20, 30, 50, 100]"
|
||||
/>
|
||||
</div>
|
||||
<VPagination
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:page-label="$t('core.components.pagination.page_label')"
|
||||
:size-label="$t('core.components.pagination.size_label')"
|
||||
:total-label="
|
||||
$t('core.components.pagination.total_label', { total: total })
|
||||
"
|
||||
:total="total"
|
||||
:size-options="[10, 20, 30, 50, 100]"
|
||||
/>
|
||||
</template>
|
||||
</VCard>
|
||||
</div>
|
||||
|
|
|
@ -501,16 +501,17 @@ onMounted(() => {
|
|||
</Transition>
|
||||
|
||||
<template #footer>
|
||||
<div class="bg-white sm:flex sm:items-center sm:justify-end">
|
||||
<VPagination
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:total="total"
|
||||
:page-label="$t('core.components.pagination.page_label')"
|
||||
:size-label="$t('core.components.pagination.size_label')"
|
||||
:size-options="[20, 30, 50, 100]"
|
||||
/>
|
||||
</div>
|
||||
<VPagination
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:total="total"
|
||||
:page-label="$t('core.components.pagination.page_label')"
|
||||
:size-label="$t('core.components.pagination.size_label')"
|
||||
:total-label="
|
||||
$t('core.components.pagination.total_label', { total: total })
|
||||
"
|
||||
:size-options="[20, 30, 50, 100]"
|
||||
/>
|
||||
</template>
|
||||
</VCard>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue