From 970b377b9a225bdf6ae5047f03120a353f12a347 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 20 Sep 2026 15:32:27 +0800 Subject: [PATCH] perf(admin): toggle the ticket process form instead of reloading the page Expand and cancel were full admin navigations (action/id query round trip), which is why they felt slow. Pre-render each pending ticket's process form as a hidden colspan=6 row and swap list row <-> form via a small delegated jQuery handler: expand hides the row (info stays single-sourced), collapse brings it back, only one form is open at a time, and the no-JS action=process links keep working as a fallback. --- src/Admin/Native/UsersMenusTickets.php | 83 ++++++++++++++----- .../report-ban-contract.test.cjs | 17 ++-- 2 files changed, 72 insertions(+), 28 deletions(-) diff --git a/src/Admin/Native/UsersMenusTickets.php b/src/Admin/Native/UsersMenusTickets.php index 8545d8b8..4b21c963 100644 --- a/src/Admin/Native/UsersMenusTickets.php +++ b/src/Admin/Native/UsersMenusTickets.php @@ -218,23 +218,62 @@ trait UsersMenusTickets { } foreach ($tickets as $row) { - $is_processing = $process_action === 'process' - && $process_id === (string) $row['kind'] . '-' . (string) $row['id']; - if ($is_processing) { - // 被处理工单:行信息由处理表单承载,不再重复渲染列表行—— - // 此前 row + 表单把同一工单信息展示两次,且表单裸嵌 - // 属无效 HTML,被浏览器 foster-parent 后那次多余的行信息 - // 错位到“确认提交”下方。合法包裹为 colspan=6 单元格。 - echo ''; - $this->render_ticket_process_form($row, $action_url); - echo ''; - } else { - $this->render_ticket_row($row, $page_url); + $process_key = (string) $row['kind'] . '-' . (string) $row['id']; + $expanded = $process_action === 'process' && $process_id === $process_key && $row['status'] === 'pending'; + $this->render_ticket_row($row, $page_url, $expanded); + + if ($row['status'] !== 'pending') { + continue; } + + // 展开与收起走 JS 切换(无整页刷新,即点即达):展开时隐藏列表行、 + // 显示处理表单(信息只出现一次);取消时换回。无 JS 环境由立即处理 + // 链接(action=process)整页兜底,直链进入时表单默认展开。 + $hidden_attr = $expanded ? '' : ' style="display:none;"'; + echo ''; + $this->render_ticket_process_form($row, $action_url); + echo ''; } echo ''; + // 行内展开/收起的轻量交互(管理员环境必有 jQuery)。 + echo ''; + $this->ticket_pagenavi($total, self::TICKETS_PER_PAGE); } @@ -259,11 +298,12 @@ trait UsersMenusTickets { echo '
'; } - private function render_ticket_row(array $row, string $page_url): void { - $kind = $row['kind']; - $status = $row['status']; - $user_id = (int) $row['user_id']; - $url = add_query_arg(['action' => 'process', 'id' => $kind . '-' . $row['id']], $page_url); + private function render_ticket_row(array $row, string $page_url, bool $hidden = false): void { + $kind = $row['kind']; + $status = $row['status']; + $user_id = (int) $row['user_id']; + $process_key = $kind . '-' . (string) $row['id']; + $url = add_query_arg(['action' => 'process', 'id' => $process_key], $page_url); // 状态列(对齐参考主题:待处理→立即处理按钮 / 已批准 / 处理完成 / 已拒绝 / 正在处理) $is_processing = isset($_GET['action']) && sanitize_key((string) wp_unslash($_GET['action'])) === 'process' @@ -271,7 +311,8 @@ trait UsersMenusTickets { if ($is_processing) { $status_html = '' . esc_html__('正在处理', 'aksrt') . ''; } elseif ($status === 'pending') { - $status_html = '' . esc_html__('立即处理', 'aksrt') . ''; + // JS 切换展开(无整页刷新);无 JS 时 href 整页兜底。 + $status_html = '' . esc_html__('立即处理', 'aksrt') . ''; } elseif ($status === 'resolved') { $status_html = $kind === 'appeal' ? '' . esc_html__('已批准', 'aksrt') . '' @@ -300,7 +341,7 @@ trait UsersMenusTickets { $desc_html = $kind === 'report' ? $this->ticket_report_desc_html($row['payload']) : $this->ticket_appeal_desc_html($row['payload'], (int) $row['id']); - echo ''; + echo ''; echo '' . $status_html . ''; echo '' . $type_html . ''; echo '' . $user_html . ''; @@ -489,8 +530,8 @@ trait UsersMenusTickets { echo '

'; echo ' '; - // 取消:回到未展开状态(去掉 action/id 参数的当前列表,保留筛选)。 - echo '' . esc_html__('取消', 'aksrt') . ''; + // 取消:收起表单、换回列表行(JS 切换;无 JS 时整页回列表兜底)。 + echo '' . esc_html__('取消', 'aksrt') . ''; echo '

'; echo ''; } diff --git a/tests/widget-system/report-ban-contract.test.cjs b/tests/widget-system/report-ban-contract.test.cjs index 24f131aa..57d6fc76 100644 --- a/tests/widget-system/report-ban-contract.test.cjs +++ b/tests/widget-system/report-ban-contract.test.cjs @@ -179,14 +179,17 @@ test('native ban page mirrors the reference theme layout', () => { assert.match(tickets, /name="action" value="' \. esc_attr\(\$kind === 'report' \? 'aksrt_users_update_report' : 'aksrt_users_process_appeal'\)/) assert.match(usersMenus, /admin_post_aksrt_users_update_report/) assert.match(usersMenus, /admin_post_aksrt_users_process_appeal/) - // 内联处理视图(参考主题方向):被处理工单以 colspan=6 合法单元格展开 - // 表单,且不再渲染其列表行——此前 row + 表单重复展示同一工单信息, - // 表单裸嵌 tbody 被 foster-parent 后多余行信息错位到“确认提交”下方。 - assert.match(tickets, /';\s*\$this->render_ticket_process_form/) - assert.match(tickets, /if \(\$is_processing\) \{[\s\S]*?render_ticket_process_form\(\$row, \$action_url\)[\s\S]*?\} else \{\s*\$this->render_ticket_row/) - // 展开的处理表单提供“取消”按钮(确认提交右侧),可收起回到列表。 + // 内联处理视图(参考主题方向):表单以合法的 colspan=6 单元格随待处理行 + // 预渲染;展开/取消走 JS 行↔表单互换(无整页刷新),信息只出现一次, + // 不再裸嵌 tbody 被 foster-parent 错位。 + assert.match(tickets, /';\s*\$this->render_ticket_process_form/) + assert.match(tickets, /data-aksrt-ticket-toggle="/) + assert.match(tickets, /data-aksrt-ticket-cancel="/) + assert.match(tickets, /data-aksrt-ticket-row="/) + assert.match(tickets, /e\.preventDefault\(\);/) + // 展开的处理表单提供“取消”按钮(确认提交右侧)。 assert.match(tickets, /class="button button-primary process-submit"/) - assert.match(tickets, /' \. esc_html__\('取消', 'aksrt'\)/) + assert.match(tickets, /' \. esc_html__\('取消', 'aksrt'\)/) // 分页对齐参考主题 zibpay_admin_pagenavi(每页 20 条) assert.match(tickets, /TICKETS_PER_PAGE = 20/)