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/)
|