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