From 9fffe7b590f6cbcedaa0481d4c59da5248e6e4c3 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 17 Sep 2026 10:14:19 +0800 Subject: [PATCH] =?UTF-8?q?fix(payment):=20=E5=8D=A1=E5=AF=86=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E9=A1=B5=E6=A0=87=E9=A2=98=E6=8C=89=E9=92=AE=E5=8D=95?= =?UTF-8?q?=E7=82=B9=E8=BE=93=E5=87=BA=E5=B9=B6=E4=BF=AE=E6=AD=A3=E6=8E=92?= =?UTF-8?q?=E5=BA=8F=E7=AE=AD=E5=A4=B4=E4=B8=8B=E6=B2=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 标题右侧按钮原在页面头部与列表渲染函数各输出一次(实际渲染 3 个 page-title-action,「添加卡密」重复出现),改为只在页面头部的 tab switch 中 拼一次;render_list() 收为 render_list(string $s),只渲染过滤链接与表格, 搜索词在页面头部单次解析后传入,搜索提示仍按参考主题跟在按钮之后。 - .orderby-but 恢复参考主题写法(position: relative,不设 display)。 箭头是绝对定位元素且不写 top/left,位置取自容器的静态位置;容器一旦变成零 高度 inline-block,基线会退化为自身下边缘并与文字基线对齐,整组箭头下沉一 个字高。同时补回参考主题的 padding-right: 1em,并加注释锁定该约束。 - 清理死代码:行循环中 custom 分支的 $type_html 赋值总被下方类型链覆盖,已删除。 - 新增 tests/admin/charge-cards-page-contract.test.cjs(4 例)作为回归护栏, 并按 .gitignore 既有白名单惯例放开该文件。 --- .gitignore | 3 + src/Admin/Native/PayChargeCards.php | 57 +++++++------- .../admin/charge-cards-page-contract.test.cjs | 76 +++++++++++++++++++ 3 files changed, 110 insertions(+), 26 deletions(-) create mode 100644 tests/admin/charge-cards-page-contract.test.cjs diff --git a/.gitignore b/.gitignore index 0acd1d6d..c458d63a 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,9 @@ !/tests/widget-system/circular-button-icon-margin-contract.test.cjs !/tests/widget-system/single-cover-height-contract.test.cjs !/tests/widget-system/frontend-lifecycle-contract.test.cjs +!/tests/admin/ +/tests/admin/* +!/tests/admin/charge-cards-page-contract.test.cjs !/tests/front-submit/ /tests/front-submit/* !/tests/front-submit/video-cover-contract.test.cjs diff --git a/src/Admin/Native/PayChargeCards.php b/src/Admin/Native/PayChargeCards.php index 03630fea..49655b21 100644 --- a/src/Admin/Native/PayChargeCards.php +++ b/src/Admin/Native/PayChargeCards.php @@ -51,8 +51,9 @@ class PayChargeCards { } $tab = isset($_GET['tab']) ? sanitize_key((string) wp_unslash($_GET['tab'])) : ''; + $s = isset($_REQUEST['s']) ? sanitize_text_field((string) wp_unslash($_REQUEST['s'])) : ''; $page_title = __('卡密管理', 'aksrt'); - $head_but = '' . esc_html__('添加卡密', 'aksrt') . ''; + $head_but = ''; // 页面级动作(参考主题在渲染前处理 add / delete)。 $action = isset($_REQUEST['action']) ? sanitize_key((string) wp_unslash($_REQUEST['action'])) : ''; @@ -62,6 +63,7 @@ class PayChargeCards { $this->handle_delete(); } + // 标题右侧按钮是页面头部的一部分,只在此处输出一次(列表页同样如此,由 render_list 负责列表本体)。 switch ($tab) { case 'add': $page_title = __('添加卡密', 'aksrt'); @@ -72,6 +74,14 @@ class PayChargeCards { $page_title = __('导出卡密', 'aksrt'); $head_but = '' . esc_html__('返回列表', 'aksrt') . ''; break; + + default: + $head_but = '' . esc_html__('添加卡密', 'aksrt') . ''; + $head_but .= '' . esc_html__('导出卡密', 'aksrt') . ''; + if ($s !== '') { + $head_but .= '
' . sprintf(esc_html__('搜索 “%s” 的内容', 'aksrt'), esc_html($s)) . '
'; + } + break; } echo '
'; @@ -84,7 +94,7 @@ class PayChargeCards { } elseif ($tab === 'export') { $this->render_export_form(); } else { - $this->render_list(); + $this->render_list($s); } echo '
'; @@ -94,17 +104,19 @@ class PayChargeCards { * 列表 * ------------------------------------------------------------------ */ - private function render_list(): void { + /** + * @param string $s 搜索词(由页面头部统一解析后传入,用于提示、过滤链接与查询)。 + */ + private function render_list(string $s): void { $svc = \AKSRT\Payment\ChargeCard::get_instance(); - $s = isset($_REQUEST['s']) ? sanitize_text_field((string) wp_unslash($_REQUEST['s'])) : ''; - $status = isset($_GET['status']) ? sanitize_key((string) wp_unslash($_GET['status'])) : ''; - $type = isset($_GET['type']) ? sanitize_key((string) wp_unslash($_GET['type'])) : ''; - $other = isset($_GET['other']) ? sanitize_text_field((string) wp_unslash($_GET['other'])) : ''; - $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'] ?? 30))); + $status = isset($_GET['status']) ? sanitize_key((string) wp_unslash($_GET['status'])) : ''; + $type = isset($_GET['type']) ? sanitize_key((string) wp_unslash($_GET['type'])) : ''; + $other = isset($_GET['other']) ? sanitize_text_field((string) wp_unslash($_GET['other'])) : ''; + $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'] ?? 30))); // 参考主题:status=0 表示未使用;本主题规范状态为 active。 if ($status === '0' || $status === 'active') { @@ -116,15 +128,7 @@ class PayChargeCards { $type = ''; } - // 标题右侧按钮与过滤链接。 - $head_but = ''; - if ($s !== '') { - $head_but .= '
' . sprintf(esc_html__('搜索 “%s” 的内容', 'aksrt'), esc_html($s)) . '
'; - } else { - $head_but .= '' . esc_html__('添加卡密', 'aksrt') . ''; - $head_but .= '' . esc_html__('导出卡密', 'aksrt') . ''; - } - + // 过滤链接(标题右侧按钮与搜索提示由页面头部统一输出)。 $sub_but = [ ['name' => __('全部', 'aksrt'), 'href' => $this->page_url], ]; @@ -148,7 +152,6 @@ class PayChargeCards { '; - echo $head_but; // phpcs:ignore WordPress.Security.EscapeOutput -- 已转义。 echo '
' . $search . '
'; $result = $svc->get_list([ @@ -203,10 +206,9 @@ class PayChargeCards { $meta = is_array($decoded) ? $decoded : []; } + // 自定义卡密不展示状态;其余类型按状态着色(类型链接统一在下方链表中生成)。 $status_html = ''; - if ($msg['type'] === 'custom') { - $type_html = '' . esc_html__('自定义卡密', 'aksrt') . ''; - } else { + if ($msg['type'] !== 'custom') { $status_html = '' . esc_html__('未使用', 'aksrt') . ''; if ($msg['status'] === 'used') { $status_html = '' . esc_html__('已使用', 'aksrt') . ''; @@ -1029,8 +1031,11 @@ class PayChargeCards {