feat(admin): 支付中心列表页统一为 WP 原生分页

七个支付中心列表页(订单明细 / 售后服务 / 付费文章 / 优惠码 / 创作分成 /
提现审核 / 卡密管理)的分页收敛到共享助手 AdminListPagination,改用 WP 原生
paginate_links() 渲染。

- 基准 URL 显式以 page 参数 + 当前筛选参数拼装,不再让两个参数的
  add_query_arg('paged', ...) 退回 $_SERVER['REQUEST_URI']:链接不再随当前
  请求形态漂移,列条件也不再丢失
- 售后服务从写死的 limit => 100 改为 limit/offset 分页,总数接上原本零调用的
  AfterSaleService::count();after_sale_status 先按状态常量归一,保证 count()
  与 admin_list() 口径一致,分页条不说谎
- 每页 20 条,统一来自 AdminListPagination::DEFAULT_PER_PAGE
- 每页在查询前夹取页码,越界时回退到最后一页并重查,杜绝「空表且没有分页条」
  的死胡同;页码夹取与早退也一并收敛到助手
- 提现审核的翻页链接排除 retry_id / retry_key 两个一次性动作参数
- 订单明细的标签页与翻页链接共用同一份筛选参数,不再各写一份

清理死代码:五个页面里近乎复制的 render_pagination()(其中订单明细与提现审核
两份从未被调用)、两页重复的内联 paginate_links 块、卡密管理的 render_pagenavi()
及其 docblock、PayChargeCards::DEFAULT_PER_PAGE 常量,以及只服务自定义禁用
按钮的 .tablenav-pages a.disabled 规则。

验证:tests/admin/ 76 项通过(新增 pay-pages-pagination.test.cjs,重写
charge-cards-pagination.test.cjs);用 git show HEAD 取出原文件对比,订单明细
与售后服务两页在新旧实现下渲染输出逐字节相同。
This commit is contained in:
2026-10-08 22:22:08 +08:00
parent 83c164a427
commit 7b83893cf6
10 changed files with 516 additions and 242 deletions
+4 -55
View File
@@ -21,9 +21,6 @@ class PayChargeCards {
public const NONCE = 'aksrt_card_pass_page';
public const EXPORT_AJAX_ACTION = 'aksrt_card_pass_export';
/** 每页条数默认值;列表页可由 ice_perpage 覆盖(无界面控件,仅供 URL / 程序化调用)。 */
public const DEFAULT_PER_PAGE = 20;
private static $instance = null;
/** @var string 当前页面 URL */
@@ -119,7 +116,8 @@ class PayChargeCards {
$orderby = isset($_GET['orderby']) ? sanitize_key((string) wp_unslash($_GET['orderby'])) : 'modified_time';
$order = isset($_GET['desc']) ? (strtoupper((string) wp_unslash($_GET['desc'])) === 'ASC' ? 'ASC' : 'DESC') : 'DESC';
$paged = max(1, (int) ($_GET['paged'] ?? 1));
$per_page = max(1, min(100, (int) ($_REQUEST['ice_perpage'] ?? self::DEFAULT_PER_PAGE)));
// 每页条数默认值取自共享助手;ice_perpage 仅作为 URL 参数被尊重,无界面控件。
$per_page = max(1, min(100, (int) ($_REQUEST['ice_perpage'] ?? AdminListPagination::DEFAULT_PER_PAGE)));
// 参考主题:status=0 表示未使用;本主题规范状态为 active。
if ($status === '0' || $status === 'active') {
@@ -297,7 +295,7 @@ class PayChargeCards {
echo '</form>';
echo '<div class="clear"></div>';
$this->render_pagenavi($count_all, $per_page, $query_args);
AdminListPagination::render(self::PAGE_SLUG, $count_all, $paged, $per_page, $query_args);
}
/* ------------------------------------------------------------------
@@ -1059,67 +1057,18 @@ class PayChargeCards {
if ($order === 'ASC') {
$args['desc'] = 'ASC';
}
if ($per_page !== self::DEFAULT_PER_PAGE) {
if ($per_page !== AdminListPagination::DEFAULT_PER_PAGE) {
$args['ice_perpage'] = (string) $per_page;
}
return $args;
}
/**
* 分页(参考主题 zibpay_admin_pagenavi 同款结构与禁用逻辑)。
*
* 与参考实现的两处差异,均为缺陷修复:
* 1) 页码先夹到 [1, total_pages]。历史写法在此处会出现「第 2 页 / 共 1 页」这类越界状态,
* 四个分支一个都不命中,上一页/下一页同时停在 '#',按钮既不禁用也点不动。
* 2) 链接基于显式基准 URL(page_url + 当前筛选条件),不再依赖 REQUEST_URI。
*
* @param array<string,string> $query_args 当前筛选参数(不含 paged)。
*/
private function render_pagenavi(int $total_count, int $number_per_page, array $query_args = []): void {
if ($total_count <= 0 || $number_per_page <= 0) {
return;
}
$total_pages = max(1, (int) ceil($total_count / $number_per_page));
$current_page = min(max(1, (int) ($_GET['paged'] ?? 1)), $total_pages);
$base = $query_args ? add_query_arg($query_args, $this->page_url) : $this->page_url;
$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) $number_per_page), esc_html((string) $total_count)); ?></span>
<span class="pagination-links">
<a class="first-page button<?php echo $on_first ? ' disabled' : ''; ?>" title="<?php esc_attr_e('前往第一页', 'aksrt'); ?>" href="<?php echo esc_url($first_page_url); ?>">«</a>
<a class="prev-page button<?php echo $on_first ? ' disabled' : ''; ?>" title="<?php esc_attr_e('前往上一页', '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 esc_attr_e('前往下一页', 'aksrt'); ?>" href="<?php echo esc_url($next_page_url); ?>">›</a>
<a class="last-page button<?php echo $on_last ? ' disabled' : ''; ?>" title="<?php esc_attr_e('前往最后一页', 'aksrt'); ?>" href="<?php echo esc_url($last_page_url); ?>">»</a>
</span>
</div>
</div>
<?php
}
/** 行内样式与脚本:依赖显隐 + 点击复制。 */
private function print_assets(): void {
?>
<style>
.order-header { display: flex; align-items: flex-start; justify-content: space-between; flex-wrap: wrap; margin-top: 8px; }
.order-header .subsubsub { margin: 6px 0; }
/* 禁用的翻页按钮已经无法跳转,但 <a href="#"> 仍会把页面滚回顶部;
这里直接让它们不可点击,避免「点了没反应还跳回页首」的错觉。 */
.tablenav-pages a.disabled { pointer-events: none; }
/* 排序箭头对齐:宿主做成零尺寸 inline-block —— 空 inline-block 的基线即其下边缘,
会与文字基线对齐,于是箭头可用 bottom 精确锚定到「基线以上 N em」。
箭头盒中心等于 bottom 值(translateY(50%) 抵消自身高度,与盒子高度无关):