From a1eb545bef7daefbdfdc3a2b4cbd881eee489790 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 20 Sep 2026 16:22:47 +0800 Subject: [PATCH] fix: mute records get an unban entry on the restrictions tab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The record list rendered an action only for global ban/suspend rows, so mute (禁言) rows showed an empty 操作 column with no way to lift them. - record list: active mute rows now render a 解除禁言 button - unban view: falls back to the active mute record when no ban/suspend exists, with 解除禁言/禁言中 titles (ban > suspend > mute precedence preserved); lifting still goes through lift_user_restriction (mute included by default) - contract tests: cover the mute action link and the unban-view fallback --- src/Admin/Native/UsersMenus.php | 31 ++++++++++++++++--- .../report-ban-contract.test.cjs | 7 ++++- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/Admin/Native/UsersMenus.php b/src/Admin/Native/UsersMenus.php index 5f8d2be5..87ddbfee 100644 --- a/src/Admin/Native/UsersMenus.php +++ b/src/Admin/Native/UsersMenus.php @@ -346,7 +346,8 @@ class UsersMenus { // 当前生效中的全局禁封(ban 优先于 suspend,对齐参考主题单一状态语义) $current = null; if ($target_id > 0) { - foreach ($svc->get_user_restrictions($target_id, true) as $r) { + $restrictions = $svc->get_user_restrictions($target_id, true); + foreach ($restrictions as $r) { if (($r['scope'] ?? '') !== 'global' || !in_array($r['type'], ['ban', 'suspend'], true)) { continue; } @@ -354,6 +355,15 @@ class UsersMenus { $current = $r; } } + // 禁言解除视图:记录列表“解除禁言”进入(无更重的 ban/suspend 时生效)。 + if ($unban && $current === null) { + foreach ($restrictions as $r) { + if (($r['type'] ?? '') === 'mute') { + $current = $r; + break; + } + } + } } echo '
'; @@ -362,8 +372,19 @@ class UsersMenus { echo '

' . esc_html__('请先通过“用户 ID”定位要禁封或解封的用户(也可从工单列表的“点击此处”进入)。', 'aksrt') . '

'; } elseif ($current !== null) { // —— 已禁封视图(参考主题解封弹窗同构):状态信息 + 解封留言表单 —— - $unban_title = $current['type'] === 'ban' ? __('解封用户', 'aksrt') : __('移出小黑屋', 'aksrt'); - $status_text = $current['type'] === 'ban' ? __('禁封中(禁止登录)', 'aksrt') : __('小黑屋禁封中', 'aksrt'); + $unban_titles = [ + 'ban' => __('解封用户', 'aksrt'), + 'suspend' => __('移出小黑屋', 'aksrt'), + 'mute' => __('解除禁言', 'aksrt'), + ]; + $status_texts = [ + 'ban' => __('禁封中(禁止登录)', 'aksrt'), + 'suspend' => __('小黑屋禁封中', 'aksrt'), + 'mute' => __('禁言中', 'aksrt'), + ]; + $cur_type = (string) ($current['type'] ?? 'ban'); + $unban_title = $unban_titles[$cur_type] ?? $unban_titles['ban']; + $status_text = $status_texts[$cur_type] ?? $status_texts['ban']; $end_time = !empty($current['expires_at']) ? (string) $current['expires_at'] : __('永久', 'aksrt'); echo '

' . esc_html($unban_title) . '

'; echo '
' . esc_html__('用户', 'aksrt') . '
' . esc_html($target->display_name) . '
'; @@ -479,8 +500,10 @@ class UsersMenus { echo '' . esc_html(!empty($r['expires_at']) ? (string) $r['expires_at'] : __('永久', 'aksrt')) . ''; echo '' . nl2br(esc_html((string) ($r['reason'] ?? ''))) . ''; echo ''; - if ($is_global && !$expired) { + if (!$expired && $is_global) { echo '' . esc_html(($type === 'ban' ? __('解封', 'aksrt') : __('移出小黑屋', 'aksrt'))) . ''; + } elseif (!$expired && $type === 'mute') { + echo '' . esc_html__('解除禁言', 'aksrt') . ''; } echo ''; } diff --git a/tests/widget-system/report-ban-contract.test.cjs b/tests/widget-system/report-ban-contract.test.cjs index 005856ad..5eeccf17 100644 --- a/tests/widget-system/report-ban-contract.test.cjs +++ b/tests/widget-system/report-ban-contract.test.cjs @@ -254,9 +254,14 @@ test('comments expose a report entry for other users when reporting is enabled', test('restrictions tab mirrors the reference ban modal 1:1', () => { // 禁封方式/禁封时间/预置原因徽章/禁封说明/删除全部内容/禁止用户申诉, // 以及已禁封用户的状态信息与解封留言表单(zib_get_set_user_ban_modal 同构)。 - for (const label of ['拉入小黑屋', '禁封用户', '禁封方式', '禁封时间', '选择禁封原因', '其它原因', '禁封说明', '删除全部内容', '禁止用户申诉', '请填写禁止申诉说明', '解封用户', '移出小黑屋', '小黑屋禁封中', '禁封中(禁止登录)', '给用户的留言', '开始时间', '结束时间']) { + for (const label of ['拉入小黑屋', '禁封用户', '禁封方式', '禁封时间', '选择禁封原因', '其它原因', '禁封说明', '删除全部内容', '禁止用户申诉', '请填写禁止申诉说明', '解封用户', '移出小黑屋', '解除禁言', '小黑屋禁封中', '禁封中(禁止登录)', '禁言中', '给用户的留言', '开始时间', '结束时间']) { assert.ok(usersMenus.includes(label), `restrictions tab missing reference label: ${label}`) } + // 禁言(mute)记录在操作列提供“解除禁言”入口,且解除视图能选中 mute 记录 + // (此前操作列对 mute 为空、顶部视图只认 ban/suspend,禁言无法从后台解除)。 + assert.match(usersMenus, /\$type === 'mute'/) + assert.match(usersMenus, /'mute'\s*=>\s*__\('解除禁言', 'aksrt'\)/) + assert.match(usersMenus, /\$unban && \$current === null/) // 时长选项 1/7/14/30/100/永久(默认 7 天);类型映射:小黑屋→suspend,禁封→ban。 assert.match(usersMenus, /1 => __\('1天', 'aksrt'\)/) assert.match(usersMenus, /7 => __\('7天', 'aksrt'\)/)