diff --git a/assets/admin/src/constants/sections/users.js b/assets/admin/src/constants/sections/users.js index 83776da1..6ba9626f 100644 --- a/assets/admin/src/constants/sections/users.js +++ b/assets/admin/src/constants/sections/users.js @@ -3,7 +3,8 @@ import { renderFaIcon, schemaPage, customPage } from './helpers' /** * Users SPA keeps config-shaped pages. * Message / referral-code queues live under users.php native menus; - * 封禁/举报 gets a sidebar entry that lands on the native ban page. + * 禁封/举报 is a config page (schema section "report"); ticket queues + * (举报&禁封申诉) stay on the native WP users.php page. */ export const usersSection = { key: 'users', @@ -129,19 +130,15 @@ export const usersSection = { canonicalDomain: 'users', section: 'wechat-template', }), - customPage({ + schemaPage({ key: 'users-ban', name: 'UsersBan', - label: '封禁/举报', + label: '禁封/举报', route: '/users/ban', - component: 'NativeOpsRedirect', - status: 'available', - title: '封禁/举报', - desc: '举报工单、禁封限制与申诉审核,统一在 WordPress 用户菜单处理。', - iconClass: 'fa fas fa-gavel', + title: '禁封/举报', + desc: '禁封功能、举报功能、预置原因、申诉资料与举报说明配置;举报与申诉工单在 WordPress 用户菜单处理。', canonicalDomain: 'users', - section: 'ban', - nativeAdminPath: 'users.php?page=aksrt_user_ban', + section: 'report', }), ], } diff --git a/assets/admin/src/pages/users/UsersBan.vue b/assets/admin/src/pages/users/UsersBan.vue deleted file mode 100644 index 45e729a1..00000000 --- a/assets/admin/src/pages/users/UsersBan.vue +++ /dev/null @@ -1,228 +0,0 @@ - - - diff --git a/assets/admin/src/pages/users/UsersMessages.vue b/assets/admin/src/pages/users/UsersMessages.vue deleted file mode 100644 index 6b25a2b2..00000000 --- a/assets/admin/src/pages/users/UsersMessages.vue +++ /dev/null @@ -1,304 +0,0 @@ - - - - - diff --git a/assets/admin/src/pages/users/UsersReport.vue b/assets/admin/src/pages/users/UsersReport.vue deleted file mode 100644 index 89e01d1d..00000000 --- a/assets/admin/src/pages/users/UsersReport.vue +++ /dev/null @@ -1,357 +0,0 @@ - - - - - diff --git a/assets/admin/src/pages/users/components/ReportDetailDrawer.vue b/assets/admin/src/pages/users/components/ReportDetailDrawer.vue deleted file mode 100644 index 89232c3c..00000000 --- a/assets/admin/src/pages/users/components/ReportDetailDrawer.vue +++ /dev/null @@ -1,242 +0,0 @@ - - - - - diff --git a/assets/admin/src/router/index.js b/assets/admin/src/router/index.js index 1d827da7..02153ba7 100644 --- a/assets/admin/src/router/index.js +++ b/assets/admin/src/router/index.js @@ -40,10 +40,6 @@ function createRouteMeta(page) { meta.section = page.section } - if (page.nativeAdminPath) { - meta.nativeAdminPath = page.nativeAdminPath - } - if (page.component === 'DeferredPage') { meta.deferred = true meta.deferredProps = { diff --git a/assets/admin/src/schema/sections/users/report.js b/assets/admin/src/schema/sections/users/report.js index 8b0e3c9b..75e2a98c 100644 --- a/assets/admin/src/schema/sections/users/report.js +++ b/assets/admin/src/schema/sections/users/report.js @@ -1,57 +1,71 @@ +// 字段集合、顺序、文案、默认值 1:1 对齐参考主题"用户&互动/禁封/举报" export const reportSchema = { key: 'users.report', title: '禁封/举报', - icon: 'fa fas fa-flag', - description: '配置举报入口、公开限制提示和后续治理分类,为封禁/举报流程预留稳定结构。', + icon: 'fa fas fa-ban', + description: '禁封功能、举报入口、预置原因、申诉资料与举报说明配置。', defaults: { - user_report_enabled: false, - user_report_public_entry: true, - user_report_public_notice: true, - user_report_ban_notice_text: '当前账号处于限制状态,部分互动能力已关闭。', - user_report_categories: 'spam|垃圾信息\nabuse|人身攻击\ncopyright|版权投诉', - ban_preset_reason: 'spam|垃圾信息\nabuse|人身攻击\nviolation|违规操作', - ban_appeal_desc: '', - ban_appeal_keys: '', + user_ban_s: true, + user_report_s: true, + ban_preset_reason: [ + { t: '发布色情、违法内容' }, + { t: '存在欺诈骗钱行为' }, + { t: '骚扰他人' }, + { t: '涉嫌侵权' }, + { t: '发布垃圾广告信息' }, + ], + ban_appeal_desc: '
为了良好的交流环境,申诉请阅读以下事项
\n
  • 首次违规将拉入小黑屋7天
  • \n
  • 3次违规后将直接禁封账号
  • \n
  • 违规情节严重将无法提交申诉
  • \n
  • 申诉提交后约2-3个工作日进行审核
  • \n
  • 如有其它疑问请与客服联系
  • ', + ban_appeal_keys: [ + { t: '真实姓名' }, + { t: '邮箱' }, + { t: '手机号' }, + ], user_report_img_s: true, - user_report_desc: '', + user_report_desc: '
    举报说明:
    \n
  • 请确保举报的内容属实
  • \n
  • 我们将会在收到举报后2个工作日内进行处理
  • \n
  • 举报属实我们将根据社区管理条例对该用户进行封号处理
  • \n
  • 如有其它疑问请与客服联系
  • ', }, groups: [ { - key: 'entry', - title: '前台入口', - icon: 'fa fas fa-sign-in-alt', - fields: [ - { key: 'user_report_enabled', label: '启用举报/禁封结构', type: 'switch', default: false }, - { key: 'user_report_public_entry', label: '公开主页展示举报入口', type: 'switch', default: true, dependsOn: { key: 'user_report_enabled', value: true } }, - { key: 'user_report_public_notice', label: '公开显示限制提示', type: 'switch', default: true, dependsOn: { key: 'user_report_enabled', value: true } }, - { key: 'user_report_ban_notice_text', label: '限制提示文案', type: 'input', default: '当前账号处于限制状态,部分互动能力已关闭。', dependsOn: { key: 'user_report_public_notice', value: true } }, - ], - }, - { - key: 'taxonomy', - title: '举报分类', - icon: 'fa fas fa-list', - fields: [ - { key: 'user_report_categories', label: '举报分类', type: 'textarea', default: 'spam|垃圾信息\nabuse|人身攻击\ncopyright|版权投诉', help: '每行一个分类:slug|显示名称', dependsOn: { key: 'user_report_enabled', value: true } }, - ], - }, - { - key: 'ban', - title: '禁封设置', + key: 'main', + title: '', icon: 'fa fas fa-ban', fields: [ - { key: 'ban_preset_reason', label: '预设封禁原因', type: 'textarea', default: 'spam|垃圾信息\nabuse|人身攻击\nviolation|违规操作', help: '每行一条:slug|显示名称', dependsOn: { key: 'user_report_enabled', value: true } }, - { key: 'ban_appeal_desc', label: '申诉说明', type: 'textarea', default: '', dependsOn: { key: 'user_report_enabled', value: true } }, - { key: 'ban_appeal_keys', label: '申诉关键词', type: 'input', default: '', help: '逗号分隔', dependsOn: { key: 'user_report_enabled', value: true } }, - ], - }, - { - key: 'image', - title: '图片举报', - icon: 'fa fas fa-image', - fields: [ - { key: 'user_report_img_s', label: '启用图片举报', type: 'switch', default: true, dependsOn: { key: 'user_report_enabled', value: true } }, - { key: 'user_report_desc', label: '举报说明', type: 'textarea', default: '', dependsOn: { key: 'user_report_img_s', value: true } }, + { key: 'user_ban_s', label: '禁封功能', type: 'switch', default: true, help: '启用后可以设置用户禁封,即小黑屋和封号的功能' }, + { key: 'user_report_s', label: '举报功能', type: 'switch', default: true, help: '前台显示举报按钮,用户可以举报其它不良信息', dependsOn: { key: 'user_ban_s', value: true } }, + { + key: 'ban_preset_reason', + label: '预置原因', + type: 'group', + button_title: '添加原因', + help: '举报/禁封的时候可选择的原因', + default: [ + { t: '发布色情、违法内容' }, + { t: '存在欺诈骗钱行为' }, + { t: '骚扰他人' }, + { t: '涉嫌侵权' }, + { t: '发布垃圾广告信息' }, + ], + fields: [ + { key: 't', label: '原因', type: 'input', default: '' }, + ], + }, + { key: 'ban_appeal_desc', label: '申诉说明', type: 'textarea', rows: 5, help: '用户申诉时候显示的内容(支持HTML代码,请注意代码规范)', default: '
    为了良好的交流环境,申诉请阅读以下事项
    \n
  • 首次违规将拉入小黑屋7天
  • \n
  • 3次违规后将直接禁封账号
  • \n
  • 违规情节严重将无法提交申诉
  • \n
  • 申诉提交后约2-3个工作日进行审核
  • \n
  • 如有其它疑问请与客服联系
  • ' }, + { + key: 'ban_appeal_keys', + label: '申诉所需资料', + type: 'group', + button_title: '添加申诉资料', + help: '用户提交申诉时候需要提供的资料;此处的信息收集,仅用于记录和申诉审核', + default: [ + { t: '真实姓名' }, + { t: '邮箱' }, + { t: '手机号' }, + ], + fields: [ + { key: 't', label: '资料项', type: 'input', default: '' }, + ], + }, + { key: 'user_report_img_s', label: '举报可上传图片', type: 'switch', default: true, help: '举报时允许上传图片进行举证(最多上传3张)', dependsOn: { key: 'user_report_s', value: true } }, + { key: 'user_report_desc', label: '举报说明', type: 'textarea', rows: 5, help: '举报时候显示的内容(支持HTML代码,请注意代码规范)', dependsOn: { key: 'user_report_s', value: true }, default: '
    举报说明:
    \n
  • 请确保举报的内容属实
  • \n
  • 我们将会在收到举报后2个工作日内进行处理
  • \n
  • 举报属实我们将根据社区管理条例对该用户进行封号处理
  • \n
  • 如有其它疑问请与客服联系
  • ' }, ], }, ], diff --git a/src/Admin/Schema/SchemaUsers.php b/src/Admin/Schema/SchemaUsers.php index ebb55c5e..461a7089 100644 --- a/src/Admin/Schema/SchemaUsers.php +++ b/src/Admin/Schema/SchemaUsers.php @@ -612,26 +612,48 @@ class SchemaUsers { 'report' => [ 'key' => 'report', 'title' => '禁封/举报', - 'version' => '1.0.0', + 'version' => '1.1.0', 'option_key' => 'aksrt_settings', 'groups' => [ - ['key' => 'entry', 'title' => '前台入口', 'fields' => [ - ['key' => 'user_report_enabled', 'label' => '启用举报/禁封结构', 'type' => 'switch', 'default' => false], - ['key' => 'user_report_public_entry', 'label' => '公开主页展示举报入口', 'type' => 'switch', 'default' => true, 'dependsOn' => ['key' => 'user_report_enabled', 'value' => true]], - ['key' => 'user_report_public_notice', 'label' => '公开显示限制提示', 'type' => 'switch', 'default' => true, 'dependsOn' => ['key' => 'user_report_enabled', 'value' => true]], - ['key' => 'user_report_ban_notice_text', 'label' => '限制提示文案', 'type' => 'input', 'default' => '当前账号处于限制状态,部分互动能力已关闭。', 'dependsOn' => ['key' => 'user_report_enabled', 'value' => true]], - ]], - ['key' => 'taxonomy', 'title' => '举报分类', 'fields' => [ - ['key' => 'user_report_categories', 'label' => '举报分类', 'type' => 'textarea', 'default' => "spam|垃圾信息\nabuse|人身攻击\ncopyright|版权投诉"], - ]], - ['key' => 'ban', 'title' => '禁封设置', 'fields' => [ - ['key' => 'ban_preset_reason', 'label' => '预设封禁原因', 'type' => 'textarea', 'default' => "spam|垃圾信息\nabuse|人身攻击\nviolation|违规操作", 'dependsOn' => ['key' => 'user_report_enabled', 'value' => true]], - ['key' => 'ban_appeal_desc', 'label' => '申诉说明', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'user_report_enabled', 'value' => true]], - ['key' => 'ban_appeal_keys', 'label' => '申诉关键词', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'user_report_enabled', 'value' => true]], - ]], - ['key' => 'image', 'title' => '图片举报', 'fields' => [ - ['key' => 'user_report_img_s', 'label' => '启用图片举报', 'type' => 'switch', 'default' => true, 'dependsOn' => ['key' => 'user_report_enabled', 'value' => true]], - ['key' => 'user_report_desc', 'label' => '举报说明', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'user_report_enabled', 'value' => true]], + // 字段集合、顺序、文案、默认值 1:1 对齐参考主题"用户&互动/禁封举报" + ['key' => 'main', 'title' => '', 'fields' => [ + ['key' => 'user_ban_s', 'label' => '禁封功能', 'type' => 'switch', 'default' => true, 'help' => '启用后可以设置用户禁封,即小黑屋和封号的功能'], + ['key' => 'user_report_s', 'label' => '举报功能', 'type' => 'switch', 'default' => true, 'help' => '前台显示举报按钮,用户可以举报其它不良信息', 'dependsOn' => ['key' => 'user_ban_s', 'value' => true]], + [ + 'key' => 'ban_preset_reason', + 'label' => '预置原因', + 'type' => 'group', + 'button_title' => '添加原因', + 'help' => '举报/禁封的时候可选择的原因', + 'default' => [ + ['t' => '发布色情、违法内容'], + ['t' => '存在欺诈骗钱行为'], + ['t' => '骚扰他人'], + ['t' => '涉嫌侵权'], + ['t' => '发布垃圾广告信息'], + ], + 'fields' => [ + ['key' => 't', 'label' => '原因', 'type' => 'input', 'default' => ''], + ], + ], + ['key' => 'ban_appeal_desc', 'label' => '申诉说明', 'type' => 'textarea', 'rows' => 5, 'help' => '用户申诉时候显示的内容(支持HTML代码,请注意代码规范)', 'default' => "
    为了良好的交流环境,申诉请阅读以下事项
    \n
  • 首次违规将拉入小黑屋7天
  • \n
  • 3次违规后将直接禁封账号
  • \n
  • 违规情节严重将无法提交申诉
  • \n
  • 申诉提交后约2-3个工作日进行审核
  • \n
  • 如有其它疑问请与客服联系
  • "], + [ + 'key' => 'ban_appeal_keys', + 'label' => '申诉所需资料', + 'type' => 'group', + 'button_title' => '添加申诉资料', + 'help' => '用户提交申诉时候需要提供的资料;此处的信息收集,仅用于记录和申诉审核', + 'default' => [ + ['t' => '真实姓名'], + ['t' => '邮箱'], + ['t' => '手机号'], + ], + 'fields' => [ + ['key' => 't', 'label' => '资料项', 'type' => 'input', 'default' => ''], + ], + ], + ['key' => 'user_report_img_s', 'label' => '举报可上传图片', 'type' => 'switch', 'default' => true, 'help' => '举报时允许上传图片进行举证(最多上传3张)', 'dependsOn' => ['key' => 'user_report_s', 'value' => true]], + ['key' => 'user_report_desc', 'label' => '举报说明', 'type' => 'textarea', 'rows' => 5, 'help' => '举报时候显示的内容(支持HTML代码,请注意代码规范)', 'dependsOn' => ['key' => 'user_report_s', 'value' => true], 'default' => "
    举报说明:
    \n
  • 请确保举报的内容属实
  • \n
  • 我们将会在收到举报后2个工作日内进行处理
  • \n
  • 举报属实我们将根据社区管理条例对该用户进行封号处理
  • \n
  • 如有其它疑问请与客服联系
  • "], ]], ], ], diff --git a/src/Settings/UserRuntime.php b/src/Settings/UserRuntime.php index 65684d89..d2f893a4 100644 --- a/src/Settings/UserRuntime.php +++ b/src/Settings/UserRuntime.php @@ -173,7 +173,7 @@ class UserRuntime { }, $medal['items_by_slug'])), ], 'report' => [ - 'enabled' => !empty($settings['user_report_enabled']), + 'enabled' => (bool) ($settings['user_report_s'] ?? $settings['user_report_enabled'] ?? false), 'public_entry' => !isset($settings['user_report_public_entry']) || !empty($settings['user_report_public_entry']), 'public_notice' => !isset($settings['user_report_public_notice']) || !empty($settings['user_report_public_notice']), 'ban_notice_text' => $ban_notice_text !== '' ? $ban_notice_text : __('当前账号处于限制状态,部分互动能力已关闭。', 'aksrt'), @@ -200,21 +200,44 @@ class UserRuntime { */ public static function ban_settings(): array { $settings = Settings::get_all(); - $reasons_raw = (string) ($settings['ban_preset_reason'] ?? "spam|垃圾信息\nabuse|人身攻击\nviolation|违规操作"); + + // 预置原因:group 数组 [{t:...}](对齐参考主题)或旧版每行一条文本 + $reasons_raw = $settings['ban_preset_reason'] ?? null; $reasons = []; - foreach (preg_split('/\r\n|\r|\n/', $reasons_raw) as $line) { - $line = trim($line); - if ($line === '') { - continue; + if (is_array($reasons_raw)) { + foreach ($reasons_raw as $row) { + $text = trim((string) ($row['t'] ?? '')); + if ($text !== '') { + $reasons[] = ['slug' => sanitize_key($text), 'name' => sanitize_text_field($text)]; + } + } + } else { + foreach (preg_split('/\r\n|\r|\n/', (string) $reasons_raw) as $line) { + $line = trim((string) $line); + if ($line === '') { + continue; + } + $parts = explode('|', $line, 2); + $reasons[] = [ + 'slug' => sanitize_key($parts[0]), + 'name' => sanitize_text_field($parts[1] ?? $parts[0]), + ]; } - $parts = explode('|', $line, 2); - $reasons[] = [ - 'slug' => sanitize_key($parts[0]), - 'name' => sanitize_text_field($parts[1] ?? $parts[0]), - ]; } - $appeal_keys_raw = (string) ($settings['ban_appeal_keys'] ?? ''); - $appeal_keys = array_filter(array_map('trim', explode(',', $appeal_keys_raw))); + + // 申诉资料:group 数组 [{t:...}] 或旧版逗号分隔文本 + $keys_raw = $settings['ban_appeal_keys'] ?? null; + $appeal_keys = []; + if (is_array($keys_raw)) { + foreach ($keys_raw as $row) { + $text = trim((string) ($row['t'] ?? '')); + if ($text !== '') { + $appeal_keys[] = sanitize_text_field($text); + } + } + } else { + $appeal_keys = array_filter(array_map('trim', explode(',', (string) $keys_raw))); + } return [ 'reasons' => $reasons, @@ -229,9 +252,9 @@ class UserRuntime { public static function report_settings(): array { $settings = Settings::get_all(); return [ - 'enabled' => !empty($settings['user_report_enabled']), - 'public_entry' => !empty($settings['user_report_public_entry']), - 'public_notice' => !empty($settings['user_report_public_notice']), + 'enabled' => (bool) ($settings['user_report_s'] ?? $settings['user_report_enabled'] ?? false), + 'public_entry' => !isset($settings['user_report_public_entry']) || !empty($settings['user_report_public_entry']), + 'public_notice' => !isset($settings['user_report_public_notice']) || !empty($settings['user_report_public_notice']), 'ban_notice_text' => sanitize_text_field((string) ($settings['user_report_ban_notice_text'] ?? '')), 'img_enabled' => !empty($settings['user_report_img_s']), 'desc' => wp_kses_post((string) ($settings['user_report_desc'] ?? '')), diff --git a/src/User/BanAppeal.php b/src/User/BanAppeal.php index f231842e..ec147bc3 100644 --- a/src/User/BanAppeal.php +++ b/src/User/BanAppeal.php @@ -34,10 +34,17 @@ class BanAppeal { */ public static function settings(): array { $all = class_exists('\AKSRT\Settings\Settings') ? (array) \AKSRT\Settings\Settings::get_all() : []; - $keys_raw = (string) ($all['ban_appeal_keys'] ?? ''); - $keys = array_values(array_filter(array_map('trim', preg_split('/[,,\n]/', $keys_raw) ?: []))); + // 申诉资料:group 数组 [{t:...}](对齐参考主题)或旧版逗号分隔文本 + $keys_raw = $all['ban_appeal_keys'] ?? null; + if (is_array($keys_raw)) { + $keys = array_values(array_filter(array_map(static function ($row): string { + return trim((string) ($row['t'] ?? '')); + }, $keys_raw))); + } else { + $keys = array_values(array_filter(array_map('trim', preg_split('/[,,\n]/', (string) $keys_raw) ?: []))); + } return [ - 'enabled' => !isset($all['user_report_enabled']) || !empty($all['user_report_enabled']), + 'enabled' => (bool) ($all['user_report_s'] ?? (isset($all['user_report_enabled']) ? $all['user_report_enabled'] : true)), 'desc' => (string) ($all['ban_appeal_desc'] ?? ''), 'keys' => $keys, ]; diff --git a/tests/widget-system/message-center-contract.test.cjs b/tests/widget-system/message-center-contract.test.cjs index a50ffe91..5332daf4 100644 --- a/tests/widget-system/message-center-contract.test.cjs +++ b/tests/widget-system/message-center-contract.test.cjs @@ -103,8 +103,7 @@ test('asset notifications are absent and interaction notification hooks are pres const notifications = read('inc/modules/user-notifications.php'); const settings = read('src/Settings/Integration.php'); const adminSettings = read('assets/admin/src/pages/content/NotificationCenterSettings.vue'); - const messageAdmin = read('assets/admin/src/pages/users/UsersMessages.vue'); - const combined = [notifications, settings, adminSettings, messageAdmin].join('\n'); + const combined = [notifications, settings, adminSettings].join('\n'); for (const retired of [ 'asset_points_increase', diff --git a/tests/widget-system/report-ban-contract.test.cjs b/tests/widget-system/report-ban-contract.test.cjs index 86699930..4ff47f95 100644 --- a/tests/widget-system/report-ban-contract.test.cjs +++ b/tests/widget-system/report-ban-contract.test.cjs @@ -15,7 +15,6 @@ const usersMenus = read('src/Admin/Native/UsersMenus.php') const mailNotifications = read('src/Settings/MailNotifications.php') const home = read('src/User/Home.php') const commentItem = read('inc/helpers/comments/item.php') -const usersBan = read('assets/admin/src/pages/users/UsersBan.vue') const functions = read('functions.php') const uninstall = read('uninstall.php') @@ -71,15 +70,44 @@ test('restriction class supports lifting and kicks sessions on ban', () => { test('ban admin REST endpoints stay in sync with the SPA client', () => { assert.match(userController, /'\/users\/\(\?P\\d\+\)\/restrictions'/) assert.match(userController, /'\/users\/\(\?P\\d\+\)\/restrict'/) - assert.match(usersBan, /\/users\/\$\{addForm\.user_id\}\/restrict`/) - assert.ok(!usersBan.includes('/restrictions`, {'), 'SPA must not POST to the unregistered /restrictions endpoint') - assert.match(usersBan, /expires_at: durationToExpiresAt\(addForm\.duration\)/) - for (const t of ["value: 'warn'", "value: 'mute'", "value: 'suspend'", "value: 'ban'"]) { - assert.ok(usersBan.includes(t), `SPA restriction type missing: ${t}`) + // The self-built SPA ban-manager page is removed: ban enforcement lives on + // the native reference-theme page, and the SPA hosts the settings schema. + assert.ok(!fs.existsSync(path.join(root, 'assets/admin/src/pages/users/UsersBan.vue')), 'self-built SPA ban page must stay deleted') + assert.ok(!fs.existsSync(path.join(root, 'assets/admin/src/pages/users/UsersReport.vue')), 'self-built SPA report queue must stay deleted') +}) + +test('ban/report settings page mirrors the reference theme schema', () => { + const schemaPhp = read('src/Admin/Schema/SchemaUsers.php') + const schemaJs = read('assets/admin/src/schema/sections/users/report.js') + const sections = read('assets/admin/src/constants/sections/users.js') + + // SPA 侧边栏“用户互动 → 禁封/举报”挂载为 schema 设置页(非跳转页) + assert.match(sections, /schemaPage\(\{\s*\n\s*key: 'users-ban',/) + assert.match(sections, /label: '禁封\/举报'/) + assert.match(sections, /section: 'report'/) + assert.ok(!sections.includes("component: 'NativeOpsRedirect'"), 'ban page must not be a redirect stub') + + // 字段键 1:1 对齐参考主题:禁封/举报开关、预置原因、申诉说明、申诉资料、图片举报、举报说明 + for (const key of ['user_ban_s', 'user_report_s', 'ban_preset_reason', 'ban_appeal_desc', 'ban_appeal_keys', 'user_report_img_s', 'user_report_desc']) { + assert.ok(schemaPhp.includes(`'${key}'`), `PHP schema missing reference key: ${key}`) + assert.ok(schemaJs.includes(key), `SPA schema missing reference key: ${key}`) } - for (const dead of ["value: 'muted'", "value: 'restricted'", "value: 'banned'"]) { - assert.ok(!usersBan.includes(dead), `invalid SPA restriction type: ${dead}`) + // 参考主题文案与 group 结构 + for (const label of ['禁封功能', '举报功能', '预置原因', '申诉说明', '申诉所需资料', '举报可上传图片', '举报说明']) { + assert.ok(schemaJs.includes(`label: '${label}'`), `SPA schema missing reference label: ${label}`) } + assert.match(schemaJs, /type: 'group'/) + assert.match(schemaJs, /添加原因/) + assert.match(schemaJs, /添加申诉资料/) + + // 运行时读取兼容 group 数组 [{t}] 并保留旧格式回退 + const runtime = read('src/Settings/UserRuntime.php') + assert.match(runtime, /ban_settings\(\): array/) + assert.match(runtime, /report_settings\(\): array/) + assert.match(runtime, /user_report_s/) + const appeal = read('src/User/BanAppeal.php') + assert.match(appeal, /ban_appeal_keys/) + assert.match(appeal, /ban_appeal_desc/) }) test('ban appeal approval actually lifts restrictions', () => {