fix(admin): 支付中心分页条改回四按钮式

AdminListPagination 的输出标记从 WP 原生 paginate_links() 换回「卡密管理」
原版的四按钮式:`« ‹ 第 X 页,共 Y 页 › »` +「每页 X 共Y」计数,没有数字页码
链接。七个页面调用点不变,外观统一为卡密管理那一套。

- 删除 $total_pages <= 1 早退:只要总数 > 0 就渲染分页条,单页时四枚按钮全
  disabled —— 与原版 render_pagenavi 行为一致
- 基准 URL 与页码夹取沿用现有实现(显式拼装、夹到 [1, total_pages]),
  这两处缺陷修复不动
- 标题属性由 esc_attr_e() 改为 esc_attr__():输出相同,且同文件与 dev harness
  都只用后者
- 新增私有静态 print_assets(),由 render() 调用并以 $assets_printed 保证每页
  只输出一次;内容只有 .tablenav-pages a.disabled { pointer-events: none; }
  及其注释。这些原生后台页面不加载主题 CSS,故随标记内联

清理 harness 中已无人调用的 number_format_i18n() 与 paginate_links() stub。

验证:tests/admin/ 76 项通过;tests/widget-system/ 458/459(仅剩与本次无关的
lazyload-contract 既有失败);用 git show HEAD~1 取出原 render_pagenavi() 与
新助手在 8 组输入(含单页、总数为 0、per_page 为 0、页码越界)下比对,规范化
空白后输出逐字节一致;harness 渲染售后面板确认四按钮标记与内联样式就位。
This commit is contained in:
2026-10-09 11:49:16 +08:00
parent 536ac67f3c
commit afd08885fc
4 changed files with 104 additions and 48 deletions
+66 -29
View File
@@ -2,13 +2,22 @@
/**
* @package AKSRT
*
* 后台列表页分页条(WP 原生 paginate_links)。
* 后台列表页分页条 —— 1:1 复刻「卡密管理」页的 zibpay_admin_pagenavi 结构。
*
* 支付中心各页面(订单明细 / 售后服务 / 付费文章 / 优惠码 / 创作分成 / 提现审核 / 卡密管理)
* 原先各写一份几乎相同的 paginate_links 调用,且基准 URL 都写成
* add_query_arg('paged', '%#%') —— 只有两个参数时 WordPress 会退到
* $_SERVER['REQUEST_URI'],链接绑在当前请求上,随请求形态漂移,列条件也容易丢。
* 这里统一到一处:显式以「page 参数 + 当前筛选参数」为基准拼装,页码先夹到有效范围。
* 原先各写一份几乎相同的翻页代码。这里统一到一处,标记沿用卡密管理那一套:
* `« ‹ 第 X 页,共 Y 页 › »` 四枚按钮 + 「每页 X 共Y」计数,没有数字页码链接。
*
* 与参考实现的两处差异,均为缺陷修复:
* 1) 基准 URL 显式以「page 参数 + 当前筛选参数」拼装。历史写法里 add_query_arg('paged', N)
* 只有两个参数时会落到 $_SERVER['REQUEST_URI'],链接绑在当前请求上,随请求形态
* 漂移,列条件也容易丢。
* 2) 页码先夹到 [1, total_pages],禁用状态由夹取后的页码推导。历史写法在此处会留下
* 「第 2 页 / 共 1 页」这类越界状态,四个分支一个都不命中,上一页/下一页同时停在
* '#':按钮既不禁用也点不动。
*
* 单页也渲染分页条(只要总数 > 0):与参考实现一致,运营能直接看到「每页 20 共 5」
* 这样的口径,四枚按钮全 disabled 也明确了「没有更多页」。
*/
namespace AKSRT\Admin\Native;
@@ -20,12 +29,14 @@ class AdminListPagination {
/** 每页条数默认值。所有列表页一致,且不提供「每页显示」控件。 */
public const DEFAULT_PER_PAGE = 20;
/** @var bool 内联样式只输出一次 */
private static $assets_printed = false;
/**
* 渲染分页条。
*
* 页码夹取到 [1, total_pages] 再决定渲染与否:历史写法在此处会留下「第 2 页 / 共 1 页」
* 这类越界状态。真正的数据回退(数据也要跟着落到最后一页)由各页面在查询前完成,
* 这里只负责把显示状态收敛到自洽。
* 真正的数据回退(数据也要跟着落到最后一页)由各页面在查询前完成,这里只把页码
* 夹到有效范围,保证显示状态自洽。
*
* @param string $page_slug 当前 admin.php 的 page 参数。
* @param int $total_count 当前筛选条件下的记录总数。
@@ -44,31 +55,57 @@ class AdminListPagination {
return;
}
self::print_assets();
$total_pages = max(1, (int) ceil($total_count / $per_page));
$current_page = min(max(1, $current_page), $total_pages);
if ($total_pages <= 1) {
// 显式基准 URL:不再让 add_query_arg() 只有两个参数时退回 $_SERVER['REQUEST_URI']。
$base = add_query_arg(array_merge(['page' => $page_slug], $query_args), admin_url('admin.php'));
$page_url = static function (int $page) use ($base): string {
return add_query_arg('paged', $page, $base);
};
$on_first = $current_page <= 1;
$on_last = $current_page >= $total_pages;
$first_page_url = $on_first ? '#' : $page_url(1);
$prev_page_url = $on_first ? '#' : $page_url($current_page - 1);
$next_page_url = $on_last ? '#' : $page_url($current_page + 1);
$last_page_url = $on_last ? '#' : $page_url($total_pages);
?>
<div class="tablenav bottom">
<div class="tablenav-pages">
<span class="displaying-num"><?php printf(esc_html__('每页 %1$s 共%2$s', 'aksrt'), esc_html((string) $per_page), esc_html((string) $total_count)); ?></span>
<span class="pagination-links">
<a class="first-page button<?php echo $on_first ? ' disabled' : ''; ?>" title="<?php echo esc_attr__('前往第一页', 'aksrt'); ?>" href="<?php echo esc_url($first_page_url); ?>">«</a>
<a class="prev-page button<?php echo $on_first ? ' disabled' : ''; ?>" title="<?php echo esc_attr__('前往上一页', 'aksrt'); ?>" href="<?php echo esc_url($prev_page_url); ?>">‹</a>
<span class="paging-input"><?php printf(esc_html__('第 %1$s 页,共 %2$s 页', 'aksrt'), esc_html((string) $current_page), '<span class="total-pages">' . esc_html((string) $total_pages) . '</span>'); ?></span>
<a class="next-page button<?php echo $on_last ? ' disabled' : ''; ?>" title="<?php echo esc_attr__('前往下一页', 'aksrt'); ?>" href="<?php echo esc_url($next_page_url); ?>">›</a>
<a class="last-page button<?php echo $on_last ? ' disabled' : ''; ?>" title="<?php echo esc_attr__('前往最后一页', 'aksrt'); ?>" href="<?php echo esc_url($last_page_url); ?>">»</a>
</span>
</div>
</div>
<?php
}
/**
* 行内样式。
*
* 这些原生后台页面不加载主题 CSS(admin-main.css 只在 edit.php 文章列表入队),
* 所以分页条依赖的规则随标记一起内联输出。
*/
private static function print_assets(): void {
if (self::$assets_printed) {
return;
}
// 显式基准 URL:不再让 add_query_arg() 只有两个参数时退回 $_SERVER['REQUEST_URI']。
$base = add_query_arg(array_merge(['page' => $page_slug], $query_args), admin_url('admin.php'));
$base = add_query_arg('paged', '%#%', $base);
echo '<div class="tablenav"><div class="tablenav-pages">';
echo '<span class="displaying-num">' . esc_html(sprintf(
/* translators: %s: 记录总数 */
__('共 %s 项', 'aksrt'),
number_format_i18n($total_count)
)) . '</span>';
echo paginate_links([
'base' => $base,
'format' => '',
'current' => $current_page,
'total' => $total_pages,
'prev_text' => '&laquo;',
'next_text' => '&raquo;',
]); // phpcs:ignore WordPress.Security.EscapeOutput -- paginate_links 自行转义。
echo '</div></div>';
self::$assets_printed = true;
?>
<style>
/* 禁用的翻页按钮已经无法跳转,但 <a href="#"> 仍会把页面滚回顶部;
这里直接让它们不可点击,避免「点了没反应还跳回页首」的错觉。 */
.tablenav-pages a.disabled { pointer-events: none; }
</style>
<?php
}
}