feat(ban): align ban prompts with the reference theme modals and block page
对照参考主题(Zibll)修正四项偏差,申诉链路从页面整体迁移至弹窗:
- feat(ban): 新增三个 1:1 复刻弹窗(REST /user-ban/{info,appeal,log}-modal):
查看禁封状态(多彩头 c-gray + 信息行 + 申诉按钮)、禁封申诉(edit-header
gavel/c-blue + 信息框 + 资料项 data[key] 输入 + 审核中态 + 禁止申诉态)、
禁封记录(多彩头 c-yellow + 计数 + 逐条卡片);user-ban.js 增加
data-aksrt-ban-info/appeal/log 委托与 admin-ajax 申诉提交
- feat(ban): 禁封/解封弹窗的「当前用户已有N次禁封记录」静态文案改为可点击
黄链(N>1),打开禁封记录弹窗;解封视图信息行改复用统一数据源
- refactor(ban): 治理展示态收敛至 Restriction::state_badges()(封号=c-red
违规已封号 / 小黑屋=c-yellow 小黑屋禁封中 / 禁言=c-gray 禁言中,颜色与
字段统一管理)+ get_ban_info()(状态/起止时间/原因/说明/申诉权限,
三弹窗与禁封页共用)
- feat(ban): 登录行为对齐参考主题——移除登录期拦截(enforce_login_ban)
与 complete_login 禁封闸门,封号用户可正常登录;新增 template_redirect
前台禁封页(1:1 zib_user_ban_restrict_login/zib_die_page:红盒提示 +
信息行 + 申诉权限 + 退出登录/申诉按钮,模板 templates/parts/user/ban-block.php)
- feat(profile): 公开主页禁封状态从资料卡下方提示框改为占据身份行元信息位
的 badg 徽章(参考主题 author_header_identity 语义);用户中心元信息改为
but 按钮(徽章+箭头)打开查看禁封状态弹窗;评论拒绝态链接同源
- refactor: 移除申诉页面模板(page-ban-appeal.php)及其资产/注册/入队、
get_profile_notice/profile_notice 链、state_labels/state_notices/
login_ban_message、UserRuntime 的 public_notice/ban_notice_text 死配置、
report_settings 死键、无消费方的 aksrt_ban_appeal_status 端点
- feat(ban): BanAppeal::ajax_submit 兼容弹窗 data[key] 表单结构
(逐项清洗入库,申诉说明取 data['申诉说明'],旧平铺字段保持兼容)
- chore: 重新构建 public.css/public.min.css(三个新弹窗几何与头部样式)
- test: 契约测试重写(徽章元信息位、三弹窗与记录链接、禁封页、允许登录 +
前台拦截、死代码移除断言),全量 362 项通过
This commit is contained in:
@@ -20,9 +20,9 @@ const uninstall = read('uninstall.php')
|
||||
const userBanHelper = read('inc/helpers/user-ban.php')
|
||||
const userBanJs = read('assets/js/user-ban.js')
|
||||
const authorHero = read('templates/parts/user/author-hero.php')
|
||||
const banBlock = read('templates/parts/user/ban-block.php')
|
||||
const ucHeader = read('inc/helpers/user-center-renderers/profile-header.php')
|
||||
const commentsHelper = read('inc/helpers/aksrt-comments.php')
|
||||
const appealPage = read('templates/pages/page-ban-appeal.php')
|
||||
const identityHelper = read('inc/helpers/aksrt-identity.php')
|
||||
const avatarHelper = read('inc/helpers/aksrt-avatar.php')
|
||||
const singleComponents = read('inc/helpers/aksrt-single-components.php')
|
||||
@@ -38,6 +38,9 @@ const oauthFlow = read('src/Auth/OAuth.php')
|
||||
const oauthProxy = read('src/Auth/OAuthProxyClient.php')
|
||||
const authJs = read('assets/js/auth.js')
|
||||
const userCenterJs = read('assets/js/routes/user-center.js')
|
||||
const modalRuntimeCss = read('assets/css/frontend/modal-runtime.css')
|
||||
const templatesMap = read('src/Core/Templates.php')
|
||||
const scriptsPart1b = read('src/Core/ScriptsPart1b.php')
|
||||
|
||||
test('report REST surface is canonical: submit + users/reports only', () => {
|
||||
assert.match(userController, /'\/report\/submit'/)
|
||||
@@ -148,62 +151,84 @@ test('ban appeal approval actually lifts restrictions', () => {
|
||||
assert.ok(!usersMenus.includes('lift_ban'))
|
||||
})
|
||||
|
||||
test('profile governance notice reads from the restriction table', () => {
|
||||
assert.match(home, /->get_display_state\(\$user_id\)/)
|
||||
assert.match(home, /Restriction::state_labels\(\)\[\$state\]/)
|
||||
assert.match(home, /\\AKSRT\\User\\Restriction::get_instance\(\)/)
|
||||
assert.ok(!home.includes('aksrt_user_ban_state'))
|
||||
// 提示框内容契约:state|label|text,label 对齐参考主题公开主页禁封徽章文案。
|
||||
assert.match(home, /'state'\s*=> \$state/)
|
||||
assert.match(home, /'label'\s*=>/)
|
||||
// 提示尾句分级:封号=全面限制(无法登录),不得沿用“部分互动能力已关闭”。
|
||||
assert.match(home, /\$text = trim\(\(string\) \(\$settings\['report'\]\['ban_notice_text'\] \?\? ''\)\)/)
|
||||
assert.match(home, /state_notices\(\)/)
|
||||
assert.ok(!userRuntime.includes('当前账号处于限制状态,部分互动能力已关闭'), 'generic partial-restriction copy must not be the banned-state default')
|
||||
// 模板必须消费真实契约键:tone/message 双键曾导致资料卡下方提示框渲染为空。
|
||||
assert.match(authorHero, /\$notice\['state'\]/)
|
||||
assert.match(authorHero, /\$notice\['text'\]/)
|
||||
assert.match(authorHero, /\$notice\['label'\]/)
|
||||
assert.ok(!authorHero.includes("$notice['message']"), 'template must not read the removed message key')
|
||||
assert.ok(!authorHero.includes("$notice['tone']"), 'template must not read the removed tone key')
|
||||
test('ban identity badge occupies the public profile meta row', () => {
|
||||
// 公开主页:禁封状态占据身份行元信息位(参考主题 author_header_identity),
|
||||
// 不再是资料卡下方提示框(notice 链已移除)。
|
||||
assert.match(userBanHelper, /function aksrt_get_user_ban_identity_badge/)
|
||||
assert.match(authorHero, /aksrt_get_user_ban_identity_badge\(\$user_id\)/)
|
||||
assert.match(authorHero, /aksrt-author-hero__identity/)
|
||||
assert.ok(!authorHero.includes('aksrt-author-hero__notice'), 'profile notice box must stay removed')
|
||||
assert.ok(!authorHero.includes('profile_notice'), 'dashboard must not carry profile_notice anymore')
|
||||
assert.ok(!home.includes('get_profile_notice'), 'Home::get_profile_notice must stay removed')
|
||||
assert.ok(!mainCss.includes('aksrt-author-hero__notice'), 'notice box CSS must stay removed')
|
||||
// 徽章字段(文案/颜色/图标)由 Restriction::state_badges() 统一管理。
|
||||
assert.match(userBanHelper, /state_badges\(\)/)
|
||||
// 死配置清理:公开提示开关与提示文案键不再进入运行时。
|
||||
assert.ok(!userRuntime.includes('public_notice'), 'dead public_notice setting must stay removed')
|
||||
assert.ok(!userRuntime.includes('ban_notice_text'), 'dead ban_notice_text setting must stay removed')
|
||||
// 用户中心元信息入口:but 按钮(徽章 + 箭头)→ 查看禁封状态弹窗。
|
||||
assert.match(userBanHelper, /function aksrt_get_user_ban_info_link/)
|
||||
assert.match(userBanHelper, /data-aksrt-ban-info=/)
|
||||
assert.match(ucHeader, /aksrt_get_user_ban_info_link/)
|
||||
})
|
||||
|
||||
test('governance display state is a single source shared by every prompt surface', () => {
|
||||
// 展示态与文案集中在 Restriction(资料卡/用户中心/评论拒绝态/昵称徽章共用)。
|
||||
// 展示态与徽章字段集中在 Restriction(身份行/用户中心/评论拒绝态/昵称徽章共用)。
|
||||
for (const state of ['STATE_BANNED', 'STATE_RESTRICTED', 'STATE_MUTED']) {
|
||||
assert.match(restriction, new RegExp(`const ${state}\\s+=`), `missing display state: ${state}`)
|
||||
}
|
||||
assert.match(restriction, /public function get_display_state\(int \$user_id\): string/)
|
||||
assert.match(restriction, /public static function state_labels\(\): array/)
|
||||
assert.match(restriction, /public static function state_notices\(\): array/)
|
||||
for (const label of ["__('违规已封号', 'aksrt')", "__('小黑屋禁封中', 'aksrt')", "__('禁言中', 'aksrt')"]) {
|
||||
assert.ok(restriction.includes(label), `missing state label: ${label}`)
|
||||
}
|
||||
// 提示尾句分级:封号=全面限制,小黑屋=部分限制,禁言=评论域限制。
|
||||
for (const notice of [
|
||||
"__('禁封期间无法登录,账号功能全面停用。', 'aksrt')",
|
||||
"__('发布、评论等操作已受限制。', 'aksrt')",
|
||||
"__('暂时无法发表评论。', 'aksrt')",
|
||||
]) {
|
||||
assert.ok(restriction.includes(notice), `missing state notice: ${notice}`)
|
||||
}
|
||||
assert.match(restriction, /public static function state_badges\(\): array/)
|
||||
// 颜色统一管理:封号=红、小黑屋=黄、禁言=灰。
|
||||
assert.match(restriction, /'label' => __\('违规已封号', 'aksrt'\),\s*'tone' => 'c-red'/)
|
||||
assert.match(restriction, /'label' => __\('小黑屋禁封中', 'aksrt'\),\s*'tone' => 'c-yellow'/)
|
||||
assert.match(restriction, /'label' => __\('禁言中', 'aksrt'\),\s*'tone' => 'c-gray'/)
|
||||
// 禁封信息行单一数据源(查看禁封状态弹窗/申诉弹窗/禁封页/管理端弹窗共用)。
|
||||
assert.match(restriction, /public function get_ban_info\(int \$user_id\): array/)
|
||||
assert.match(restriction, /'status'\s*=>/)
|
||||
assert.match(restriction, /'no_appeal_desc'/)
|
||||
assert.match(restriction, /is_banned\(\$user_id\)[\s\S]*?is_suspended\(\$user_id\)[\s\S]*?is_restricted\(\$user_id, self::TYPE_MUTE\)/)
|
||||
// 请求级缓存:评论列表逐条渲染昵称徽章不得反复查库。
|
||||
assert.match(userBanHelper, /static \$cache = \[\]/)
|
||||
})
|
||||
|
||||
test('ban prompt surface mirrors the reference theme entry points', () => {
|
||||
// 用户中心页头(参考主题 user_page_header_desc / zib_get_user_ban_info_link)。
|
||||
assert.match(userBanHelper, /function aksrt_get_user_ban_notice_html/)
|
||||
assert.match(userBanHelper, /function aksrt_get_ban_appeal_page_url/)
|
||||
assert.match(ucHeader, /aksrt_get_user_ban_notice_html/)
|
||||
// 用户中心提示排版与相邻元信息一致:复用 uc-header__meta-item 结构,
|
||||
// 不用 badg-sm(0.8em 破坏字号一致性),箭头置于提示内部。
|
||||
const noticeFn = userBanHelper.slice(userBanHelper.indexOf('function aksrt_get_user_ban_notice_html'))
|
||||
const noticeBody = noticeFn.slice(0, noticeFn.indexOf('\n}'))
|
||||
assert.match(noticeBody, /\$class = 'uc-header__meta-item aksrt-user-ban-notice';/)
|
||||
assert.ok(!noticeBody.includes('badg-sm'), 'user center notice must not use badg-sm (shrinks font vs meta row)')
|
||||
assert.match(noticeBody, /fa-angle-right/)
|
||||
test('ban prompt surface mirrors the reference theme modals and block page', () => {
|
||||
// 查看禁封状态弹窗(1:1 zib_get_ban_info_modal:多彩头 + 信息行 + 申诉按钮)。
|
||||
assert.match(userBanHelper, /function aksrt_get_user_ban_info_modal/)
|
||||
assert.match(userBanHelper, /aksrt-user-ban-info-modal/)
|
||||
assert.match(userBanHelper, /您已解封,请刷新页面/)
|
||||
assert.match(userBanHelper, /您当前已无法进行申诉/)
|
||||
// 禁封申诉弹窗(1:1 zib_get_user_ban_appeal_modal:edit-header + 信息框 +
|
||||
// 资料项 inputs + 审核中态 + 禁止申诉态;仅本人)。
|
||||
assert.match(userBanHelper, /function aksrt_get_user_ban_appeal_modal/)
|
||||
assert.match(userBanHelper, /aksrt-user-ban-appeal-modal/)
|
||||
assert.match(userBanHelper, /function aksrt_get_user_ban_appeal_link/)
|
||||
assert.match(userBanHelper, /data-aksrt-ban-appeal=/)
|
||||
assert.match(userBanHelper, /抱歉!您当前已无法进行申诉/)
|
||||
assert.match(userBanHelper, /您的申诉正在审核中,请耐心等待/)
|
||||
assert.match(userBanHelper, /name="data\[/)
|
||||
assert.match(userBanHelper, /详细的说明更容易通过审核喔/)
|
||||
// 申诉表单 data[key] 结构与后端兼容。
|
||||
assert.match(banAppeal, /is_array\(\$_POST\['data'\]\)/)
|
||||
assert.match(banAppeal, /申诉说明/)
|
||||
// 禁封记录弹窗 + 记录链接(1:1 zib_get_ban_log_modal / zib_get_user_ban_log_link)。
|
||||
assert.match(userBanHelper, /function aksrt_get_user_ban_log_modal/)
|
||||
assert.match(userBanHelper, /function aksrt_get_user_ban_log_link/)
|
||||
assert.match(userBanHelper, /data-aksrt-ban-log=/)
|
||||
assert.match(userBanHelper, /当前用户已有%d次禁封记录,请谨慎操作/)
|
||||
assert.match(userBanHelper, /该用户共有%d次禁封记录/)
|
||||
// 登录后禁封状态页(1:1 zib_user_ban_restrict_login / zib_die_page)。
|
||||
assert.match(userBanHelper, /function aksrt_render_user_ban_block_page/)
|
||||
assert.match(banBlock, /抱歉,您的账号当前处于禁封状态,暂时无法登录/)
|
||||
assert.match(banBlock, /退出登录/)
|
||||
assert.match(banBlock, /aksrt_get_user_ban_appeal_link/)
|
||||
for (const row of ['用户名', '状态', '开始时间', '结束时间', '原因', '说明', '申诉权限']) {
|
||||
assert.ok(banBlock.includes(`__('${row}', 'aksrt')`), `ban block page missing row: ${row}`)
|
||||
}
|
||||
// Restriction 以 template_redirect 收口(不禁登录)。
|
||||
assert.match(restriction, /add_action\('template_redirect', \[\$this, 'restrict_frontend_access'\], 1\)/)
|
||||
assert.match(restriction, /public function restrict_frontend_access\(\): void/)
|
||||
assert.ok(!restriction.includes('enforce_login_ban'), 'login-time ban block must stay removed')
|
||||
// 评论拒绝态(参考主题 zib_get_user_ban_nocan_info)。
|
||||
assert.match(userBanHelper, /function aksrt_get_user_ban_nocan_html/)
|
||||
assert.match(commentsHelper, /aksrt_get_user_ban_nocan_html/)
|
||||
@@ -213,22 +238,27 @@ test('ban prompt surface mirrors the reference theme entry points', () => {
|
||||
assert.match(userBanHelper, /function aksrt_get_user_ban_avatar_badge/)
|
||||
assert.match(identityHelper, /aksrt_get_user_ban_name_badge\(\$user_id\)/)
|
||||
assert.match(avatarHelper, /aksrt_get_user_ban_avatar_badge\(\$user_id\)/)
|
||||
// 禁封申诉页完整状态信息(参考主题 zib_get_ban_info_modal)。
|
||||
assert.match(appealPage, /get_active_suspend\(\$user_id\)/)
|
||||
for (const row of ['状态', '开始时间', '结束时间', '原因', '说明']) {
|
||||
assert.match(appealPage, new RegExp(`__\\('${row}', 'aksrt'\\)`), `appeal page missing status row: ${row}`)
|
||||
// 三个弹窗 REST 路由(modal-mini 几何 / 每次刷新)。
|
||||
for (const route of ['/user-ban/info-modal', '/user-ban/appeal-modal', '/user-ban/log-modal']) {
|
||||
assert.ok(userController.includes(`'${route}'`), `missing REST route: ${route}`)
|
||||
}
|
||||
// 前端委托与 admin-ajax 提交。
|
||||
for (const attr of ['data-aksrt-ban-info', 'data-aksrt-ban-appeal', 'data-aksrt-ban-log']) {
|
||||
assert.ok(userBanJs.includes(attr), `missing JS delegation: ${attr}`)
|
||||
}
|
||||
assert.match(userBanJs, /aksrt_ban_appeal_submit/)
|
||||
assert.match(userBanJs, /new FormData\(form\)/)
|
||||
// modal-mini 几何(400px)与头部样式覆盖三个新弹窗类。
|
||||
for (const cls of ['aksrt-user-ban-info-modal', 'aksrt-user-ban-appeal-modal', 'aksrt-user-ban-log-modal']) {
|
||||
assert.ok(modalRuntimeCss.includes(cls), `missing modal geometry for ${cls}`)
|
||||
}
|
||||
assert.match(appealPage, /esc_html_e\('申诉权限', 'aksrt'\)/)
|
||||
assert.match(appealPage, /禁封中\(禁止登录\)/)
|
||||
assert.match(appealPage, /本次禁封您将不能发起申诉/)
|
||||
// 禁封/小黑屋均可申诉(参考主题 zib_user_is_ban 双类型语义)。
|
||||
assert.match(banAppeal, /STATE_BANNED, \\AKSRT\\User\\Restriction::STATE_RESTRICTED/)
|
||||
// 禁封站内信附申诉入口(参考主题 zib_updata_user_ban_msg 申诉指引)。
|
||||
assert.match(restrictionOps, /aksrt_get_ban_appeal_page_url/)
|
||||
// 头像角标样式:源文件与入队的 min 产物同步。
|
||||
for (const css of [mainCss, mainMinCss]) {
|
||||
assert.ok(css.includes('aksrt-avatar-ban-badge'), 'ban avatar badge CSS must exist in both main.css and main.min.css')
|
||||
}
|
||||
// 申诉页面模板与专属资产已移除(死代码清理)。
|
||||
assert.ok(!templatesMap.includes('page-ban-appeal'), 'ban appeal page template registration must stay removed')
|
||||
assert.ok(!scriptsPart1b.includes('page-ban-appeal'), 'ban appeal page assets must stay removed')
|
||||
})
|
||||
|
||||
test('report entry hides targets already banned or suspended', () => {
|
||||
@@ -239,35 +269,28 @@ test('report entry hides targets already banned or suspended', () => {
|
||||
assert.match(authorHero, /aksrt_is_user_ban_restricted\(\$user_id\)/)
|
||||
})
|
||||
|
||||
test('banned users get the ban reason on every login path, not a credentials error', () => {
|
||||
// 登录禁封文案单一来源(全面限制语义 + 期限 + 原因)。
|
||||
assert.match(restriction, /public function login_ban_message\(int \$user_id\): string/)
|
||||
assert.match(restriction, /__\('您的账号已被封禁,禁封期间无法登录。', 'aksrt'\)/)
|
||||
assert.match(restriction, /new \\WP_Error\('user_banned', \$this->login_ban_message/)
|
||||
// Toast 透传:REST 层不得把失败原因硬编码为“账号或密码错误”。
|
||||
test('banned users may log in and meet the frontend block page', () => {
|
||||
// 对齐参考主题:封号用户可正常登录(不禁登录),登录后前台任何页面展示禁封页。
|
||||
assert.ok(!restriction.includes("add_filter('authenticate'"), 'login-time ban block must stay removed')
|
||||
assert.ok(!authService.includes('user_banned'), 'dead user_banned error branch must stay removed')
|
||||
assert.ok(!authService.includes('get_error_code'), 'friendly_login_error must not carry the dead code param')
|
||||
assert.ok(!oauthAccountService.includes('is_banned'), 'complete_login must not gate login')
|
||||
const completeLoginFn = oauthAccountService.slice(oauthAccountService.indexOf('function complete_login'))
|
||||
const completeLoginBody = completeLoginFn.slice(0, completeLoginFn.indexOf('\n}'))
|
||||
assert.ok(!completeLoginBody.includes('WP_Error'), 'complete_login must stay void')
|
||||
assert.ok(!phoneOps.includes('login_ban_message'), 'SMS path must not carry the removed ban gate')
|
||||
assert.ok(!weixinGzh.includes('account_banned'), 'weixin gzh must not carry the removed ban error code')
|
||||
assert.ok(!oauthFlow.includes('account_banned'), 'oauth flow must not carry the removed ban error code')
|
||||
assert.ok(!oauthProxy.includes('account_banned'), 'oauth proxy must not carry the removed ban error code')
|
||||
for (const js of [authJs, userCenterJs]) {
|
||||
assert.ok(!js.includes('account_banned'), 'removed account_banned JS message must stay gone')
|
||||
}
|
||||
// Toast 透传(一般性修复,保留):REST 层不得把失败原因硬编码为凭证错误。
|
||||
assert.match(phoneOps, /\$result\['error'\]/)
|
||||
assert.ok(
|
||||
phoneOps.includes("$login_error !== '' ? $login_error : __('账号或密码错误', 'aksrt')"),
|
||||
'auth_login must pass through the real failure reason'
|
||||
)
|
||||
assert.match(authService, /friendly_login_error\(\$user->get_error_message\(\), \(string\) \$user->get_error_code\(\)\)/)
|
||||
assert.match(authService, /'user_banned' === \$error_code/)
|
||||
// 短信验证码(免密)登录禁封闸口:封号用户不得经此路径登录。
|
||||
assert.match(phoneOps, /is_banned\(\(int\) \$user->ID\)/)
|
||||
assert.match(phoneOps, /login_ban_message\(\(int\) \$user->ID\)/)
|
||||
// 非密码登录统一收口:complete_login 返回 WP_Error,调用方必须中止。
|
||||
assert.match(oauthAccountService, /public static function complete_login\(\\WP_User \$user, bool \$remember = true\): \?\\WP_Error/)
|
||||
assert.match(oauthAccountService, /is_banned\(\(int\) \$user->ID\)/)
|
||||
assert.match(weixinGzh, /\$login_error = OAuthAccountService::complete_login/)
|
||||
assert.match(weixinGzh, /error_response\(\$login_error->get_error_message\(\), 403\)/)
|
||||
assert.match(oauthFlow, /\$login_error = OAuthAccountService::complete_login/)
|
||||
assert.match(oauthFlow, /redirect_error\('account_banned'/)
|
||||
assert.match(oauthProxy, /\$login_error = OAuthAccountService::complete_login/)
|
||||
assert.match(oauthProxy, /redirect_error\('account_banned'/)
|
||||
// 前端 OAuth 错误映射同步补充 account_banned。
|
||||
for (const js of [authJs, userCenterJs]) {
|
||||
assert.match(js, /account_banned: '您的账号已被封禁,禁封期间无法登录'/)
|
||||
}
|
||||
})
|
||||
|
||||
test('admin report notification links to the real page', () => {
|
||||
@@ -402,9 +425,13 @@ test('comments expose a report entry for other users when reporting is enabled',
|
||||
test('frontend ban modal mirrors the reference theme zib_get_set_user_ban_modal 1:1', () => {
|
||||
// 禁封方式/禁封时间/预置原因徽章/其它原因/禁封说明/删除全部内容/禁止用户申诉,
|
||||
// 以及已禁封用户的状态信息与解封留言表单(弹窗经 REST /user-ban/modal 输出)。
|
||||
for (const label of ['拉入小黑屋', '禁封用户', '禁封方式', '禁封时间', '选择禁封原因', '其它原因', '禁封说明', '删除全部内容', '禁止用户申诉', '请填写禁止申诉说明', '解封用户', '移出小黑屋', '禁封中(禁止登录)', '小黑屋', '给用户的留言', '开始时间', '结束时间', '原因', '说明', '禁封记录', '确认禁封']) {
|
||||
for (const label of ['拉入小黑屋', '禁封用户', '禁封方式', '禁封时间', '选择禁封原因', '其它原因', '禁封说明', '删除全部内容', '禁止用户申诉', '请填写禁止申诉说明', '解封用户', '移出小黑屋', '给用户的留言', '开始时间', '结束时间', '原因', '说明', '禁封记录', '确认禁封']) {
|
||||
assert.ok(userBanHelper.includes(label), `ban modal missing reference label: ${label}`)
|
||||
}
|
||||
// 状态文案由 Restriction::get_ban_info() 单一数据源产出(各提示面共用)。
|
||||
for (const label of ['禁封中(禁止登录)', '小黑屋禁封中']) {
|
||||
assert.ok(restriction.includes(label), `ban status label missing from Restriction: ${label}`)
|
||||
}
|
||||
// 时长选项 1/7/14/30/100/永久(默认 7 天);类型映射:小黑屋→suspend,禁封→ban。
|
||||
assert.match(userBanHelper, /1 => __\('1天', 'aksrt'\)/)
|
||||
assert.match(userBanHelper, /7 => __\('7天', 'aksrt'\)/)
|
||||
|
||||
Reference in New Issue
Block a user