Unify pagination layout and improve mobile display

- Unify pagination and total footer layout
- Improve pagination display on small screens (no overflow)
- Add truncated pagination with ellipsis
- Standardize paginator style (Bootstrap 4)
This commit is contained in:
BrettonYe
2026-01-30 17:38:31 +08:00
parent 348991af98
commit 167927af13
11 changed files with 174 additions and 70 deletions

View File

@@ -38,7 +38,7 @@ class AppServiceProvider extends ServiceProvider
*/
public function boot(): void
{
Paginator::useBootstrap();
Paginator::useBootstrapFour();
// 检测是否强制跳转https
if (config('session.secure')) {

View File

@@ -178,6 +178,110 @@
});
}
@endauth
function adjustPagination() {
const paginations = document.querySelectorAll('.pagination');
paginations.forEach(pagination => {
const allItems = Array.from(pagination.querySelectorAll('.page-item'));
// 1. 清理动态省略号并恢复显示以进行测量
pagination.querySelectorAll('.dynamic-dot').forEach(el => el.remove());
allItems.forEach(item => item.style.display = '');
const totalWidthNeeded = pagination.scrollWidth;
// 2. 寻找第一个宽度限制容器
let parent = pagination.parentElement;
while (parent && parent.tagName !== 'HTML' && parent.clientWidth === totalWidthNeeded) {
// 如果父容器 clientWidth 明显小于当前 pagination 宽度,说明它就是那个限制框
parent = parent.parentElement;
}
let limitWidth = parent.clientWidth;
// 如果宽度足够(给 60px 缓冲),不需要调整
if (totalWidthNeeded + 60 < limitWidth) return;
// 3. 更加精准的估算容量
// 取最后一页的宽度作为基准(通常三位数页码最宽,最具代表性)
const itemWidth = (allItems[allItems.length - 2] || allItems[0]).offsetWidth || 40;
// 计算最大可用槽位:(容器宽 / 单个宽) - 预留给省略号的 2 个位置
let maxSlots = Math.max(5, Math.floor(limitWidth / itemWidth) - 2);
// 4. 筛选页码(排除 Prev/Next
const numItems = allItems.filter(item => {
const text = item.textContent.trim();
// 排除上一页/下一页图标,只留数字
return !isNaN(text) && text !== '' && !item.querySelector('[rel="prev"]') && !item.querySelector('[rel="next"]');
});
const activeItem = pagination.querySelector('.active');
const firstPage = numItems[0];
const lastPage = numItems[numItems.length - 1];
const prevBtn = allItems[0];
const nextBtn = allItems[allItems.length - 1];
// 5. 构建必须显示的权重集合 (Set)
let visibleSet = new Set([prevBtn, nextBtn, firstPage, lastPage, activeItem]);
// 6. 权重填充:按距离 Active 远近填充剩余槽位
let remaining = maxSlots - visibleSet.size;
if (remaining > 0) {
const activeIdx = allItems.indexOf(activeItem);
const sortedNums = [...numItems]
.filter(item => !visibleSet.has(item))
.sort((a, b) => {
const distA = Math.abs(allItems.indexOf(a) - activeIdx);
const distB = Math.abs(allItems.indexOf(b) - activeIdx);
if (distA === distB) return allItems.indexOf(a) - allItems.indexOf(b); // 距离相等时,左侧优先
return distA - distB;
});
for (let i = 0; i < remaining && i < sortedNums.length; i++) {
visibleSet.add(sortedNums[i]);
}
}
// 7. 执行显示/隐藏
allItems.forEach(item => {
item.style.display = visibleSet.has(item) ? '' : 'none';
});
// 8. 补齐省略号 (检查索引断层)
const finalVisible = allItems.filter(item => item.style.display !== 'none');
for (let i = 0; i < finalVisible.length - 1; i++) {
const currIdx = allItems.indexOf(finalVisible[i]);
const nextIdx = allItems.indexOf(finalVisible[i + 1]);
if (nextIdx - currIdx > 1) {
let nativeDot = null;
for (let j = currIdx + 1; j < nextIdx; j++) {
if (allItems[j].textContent.includes('...')) {
nativeDot = allItems[j];
break;
}
}
if (nativeDot) {
nativeDot.style.display = '';
} else {
// 正确插入 HTML 节点的方法
finalVisible[i + 1].insertAdjacentHTML('beforebegin',
`<li class="page-item disabled dynamic-dot" aria-disabled="true"><span class="page-link">...</span></li>`);
}
}
}
});
}
let resizeTimer;
window.addEventListener('resize', () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(adjustPagination, 100);
});
// 在 DOM 加载完成后执行一次
document.addEventListener('DOMContentLoaded', adjustPagination);
</script>
@yield('layout_javascript')
</body>

View File

@@ -3,6 +3,25 @@
@section('layout_css')
<link href="/assets/global/fonts/font-awesome/css/all.min.css" rel="stylesheet">
<link href="/assets/global/vendor/toastr/toastr.min.css" rel="stylesheet">
<style>
@media (max-width: 768px) {
.pagination .page-link {
padding: .429rem .786rem;
font-size: .858rem;
line-height: 1.5
}
.pagination .page-item:first-child .page-link {
border-top-left-radius: .143rem;
border-bottom-left-radius: .143rem
}
.pagination .page-item:last-child .page-link {
border-top-right-radius: .143rem;
border-bottom-right-radius: .143rem
}
}
</style>
@yield('css')
@endsection
@section('body_class', 'dashboard')

View File

@@ -13,14 +13,20 @@
</tr>
</thead>
<tbody>
@foreach ($inviteList as $invite)
@forelse ($inviteList as $invite)
<tr>
<td>
<a href="{{ route('register', ['code' => $invite->code]) }}" target="_blank">{{ $invite->code }}</a>
</td>
<td> {{ $invite->dateline }} </td>
</tr>
@endforeach
@empty
<tr>
<td class="text-center" colspan="2">
<span class="badge badge-secondary">{{ trans('common.none') }}</span>
</td>
</tr>
@endforelse
</tbody>
@endif
@else
@@ -28,12 +34,14 @@
@endif
</table>
</div>
@endsection
@section('footer')
@if (sysConfig('is_invite_register') && sysConfig('is_free_code'))
<div class="mt-20">
<a class="btn btn-danger btn-lg float-left" href="{{ route('login') }}">{{ trans('common.back') }}</a>
<nav class="Page navigation float-right">
{{ $inviteList->links() }}
</nav>
<div class="panel-footer d-flex justify-content-between">
<div>
<a class="btn btn-danger" href="{{ route('login') }}">{{ trans('common.back') }}</a>
</div>
{{ $inviteList->links() }}
</div>
@endif
@endsection

View File

@@ -97,6 +97,7 @@
<div class="panel-body">
@yield('content')
</div>
@yield('footer')
</div>
</div>
@yield('modal')

View File

@@ -58,13 +58,19 @@
</div>
@if ($count && $pagination)
<div class="panel-footer">
<div class="row">
<div class="col-sm-4">{!! $count !!}</div>
<div class="col-sm-8">
<nav class="Page navigation float-right">{!! $pagination !!}</nav>
</div>
<div class="panel-footer d-flex flex-column flex-lg-row justify-content-between align-items-center">
<div class="mb-3 mb-lg-0">
{!! $count !!}
</div>
{!! $pagination !!}
</div>
@elseif($count)
<div class="panel-footer d-flex justify-content-start">
{!! $count !!}
</div>
@elseif($pagination)
<div class="panel-footer d-flex justify-content-end">
{!! $pagination !!}
</div>
@endif
</div>

View File

@@ -63,17 +63,11 @@
</tbody>
</table>
</div>
<div class="card-footer card-footer-transparent">
<div class="row">
<div class="col-md-4">
{!! trans('user.invite.counts', ['num' => $inviteList->total()]) !!}
</div>
<div class="col-md-8">
<nav class="Page navigation float-right">
{{ $inviteList->links() }}
</nav>
</div>
<div class="card-footer card-footer-transparent d-flex flex-column flex-lg-row justify-content-between align-items-center">
<div class="mb-5 mb-lg-0">
{!! trans('user.invite.counts', ['num' => $inviteList->total()]) !!}
</div>
{{ $inviteList->links() }}
</div>
</div>
</div>

View File

@@ -63,14 +63,8 @@
</tbody>
</table>
</div>
<div class="panel-footer">
<div class="row">
<div class="col-12">
<nav class="Page navigation float-right">
{{ $orderList->links() }}
</nav>
</div>
</div>
<div class="panel-footer d-flex justify-content-end">
{{ $orderList->links() }}
</div>
</div>
</div>

View File

@@ -59,10 +59,8 @@
</tbody>
</table>
</div>
<div class="card-footer card-footer-transparent">
<nav class="Page navigation float-right">
{{ $referralUserList->appends(Arr::except(Request::query(), 'user_page'))->links() }}
</nav>
<div class="card-footer card-footer-transparent d-flex justify-content-end">
{{ $referralUserList->appends(Arr::except(Request::query(), 'user_page'))->links() }}
</div>
</div>
</div>
@@ -106,17 +104,11 @@
</tbody>
</table>
</div>
<div class="panel-footer">
<div class="row">
<div class="col-md-6 col-sm-6">
{{ trans('user.referral.total', ['amount' => $canAmount, 'total' => $referralLogList->total(), 'money' => $referral_money]) }}
</div>
<div class="col-md-6 col-sm-6">
<nav class="Page navigation float-right">
{{ $referralLogList->appends(Arr::except(Request::query(), 'log_page'))->links() }}
</nav>
</div>
<div class="panel-footer d-flex flex-column flex-xxl-row justify-content-between align-items-center">
<div class="mb-3 mb-xxl-0">
{{ trans('user.referral.total', ['amount' => $canAmount, 'total' => $referralLogList->total(), 'money' => $referral_money]) }}
</div>
{{ $referralLogList->appends(Arr::except(Request::query(), 'log_page'))->links() }}
</div>
</div>
<!-- 提现记录 -->
@@ -146,10 +138,8 @@
</tbody>
</table>
</div>
<div class="card-footer card-footer-transparent">
<nav class="Page navigation float-right">
{{ $referralApplyList->appends(Arr::except(Request::query(), 'apply_page'))->links() }}
</nav>
<div class="card-footer card-footer-transparent d-flex justify-content-end">
{{ $referralApplyList->appends(Arr::except(Request::query(), 'apply_page'))->links() }}
</div>
</div>
</div>

View File

@@ -5,7 +5,7 @@
@section('content')
<div class="page-content container-fluid">
<div class="row">
<div class="col-lg-8 order-lg-1 order-2">
<div class="col-xxl-9 col-lg-8 order-lg-1 order-2">
<div class="panel panel-bordered">
<div class="panel-heading p-20">
<h1 class="panel-title cyan-600">
@@ -53,18 +53,12 @@
</table>
</div>
</div>
<div class="panel-footer">
<div class="row">
<div class="col-md-12">
<nav class="Page navigation float-right">
{{ $tickets->links() }}
</nav>
</div>
</div>
<div class="panel-footer d-flex justify-content-end">
{{ $tickets->links() }}
</div>
</div>
</div>
<div class="col-lg-4 order-lg-2 order-1">
<div class="col-xxl-3 col-lg-4 order-lg-2 order-1">
<div class="panel panel-bordered">
<div class="panel-heading p-20">
<h3 class="panel-title cyan-600">

View File

@@ -193,17 +193,11 @@
</table>
</div>
</div>
<div class="panel-footer">
<div class="row">
<div class="col-sm-4">
{!! trans('admin.logs.counts', ['num' => $entries->total()]) !!}
</div>
<div class="col-sm-8">
<nav class="Page navigation float-right">
{{ $entries->links() }}
</nav>
</div>
<div class="panel-footer d-flex flex-column flex-lg-row justify-content-between align-items-center">
<div class="mb-3 mb-lg-0">
{!! trans('admin.logs.counts', ['num' => $entries->total()]) !!}
</div>
{{ $entries->links() }}
</div>
</div>
</div>