feat(admin): review reports and ban appeals in dialogs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
kate522andClaude Fable 5 committed 2026-10-30 23:06:04 +08:00
1 parent 32ac2112b0
commit 59ddf677b6
13 files changed
+2122 -704

No files matched your search

+5 -96
View File
@@ -12,7 +12,7 @@ class UsersMenus {
use UsersMenusVerify;
use UsersMenusVip;
use UsersMenusInviteCode;
use UsersMenusTickets;
use UsersMenusBan;
use UsersMenusTicketsCenter;
use UsersMenusMessages;
@@ -47,6 +47,7 @@ class UsersMenus {
add_action('admin_enqueue_scripts', [$this, 'enqueue_message_assets']);
add_action('admin_enqueue_scripts', [$this, 'enqueue_invite_assets']);
add_action('admin_enqueue_scripts', [$this, 'enqueue_verify_assets']);
add_action('admin_enqueue_scripts', [$this, 'enqueue_ban_assets']);
add_action('admin_enqueue_scripts', [$this, 'enqueue_vip_assets']);
}
@@ -202,6 +203,9 @@ class UsersMenus {
if ($code === 'verify_failed' && isset($_GET['aksrt_verify_error'])) {
$message = sanitize_text_field((string) wp_unslash($_GET['aksrt_verify_error']));
}
if (in_array($code, ['report_failed', 'appeal_failed'], true) && isset($_GET['aksrt_ban_error'])) {
$message = sanitize_text_field((string) wp_unslash($_GET['aksrt_ban_error']));
}
if ($code === 'vip_failed' && isset($_GET['aksrt_vip_error'])) {
$message = sanitize_text_field((string) wp_unslash($_GET['aksrt_vip_error']));
}
@@ -221,101 +225,6 @@ class UsersMenus {
exit;
}
/* ------------------------------------------------------------------
* Ban / reports
* ----------------------------------------------------------------*/
public function render_ban_page(): void {
$this->ensure_cap();
NativeUi::page_open('aksrt-native-ban');
NativeUi::header(
__('用户禁封申诉及用户举报管理', 'aksrt'),
__('处理用户举报与禁封申诉工单。禁封 / 解封操作在前台封禁弹窗完成。', 'aksrt'),
'dashicons-shield'
);
$this->flash();
// 与参考主题一致:后台仅承载「申诉&举报」工单处理;禁封/解封操作
// 全部在前台完成(用户主页封面 / 评论区 / 文章作者栏三点菜单 →
// 封禁弹窗,REST /user-ban/modal + /user-ban/set)。
// render_tickets_tab() 自带筛选控件 + 表格 + 分页,直接交给 .aksrt-native
// 作用域下的共享样式(.subsubsub / .widefat / .button / .tablenav)接管。
$this->render_tickets_tab();
NativeUi::page_close();
}
public function handle_update_report(): void {
if (!current_user_can(self::CAPABILITY)) {
wp_die(esc_html__('权限不足', 'aksrt'));
}
$id = isset($_POST['report_id']) ? (int) $_POST['report_id'] : 0;
$new_status = isset($_POST['new_status']) ? sanitize_key((string) wp_unslash($_POST['new_status'])) : '';
$note = isset($_POST['note']) ? sanitize_textarea_field((string) wp_unslash($_POST['note'])) : '';
check_admin_referer('aksrt_users_update_report_' . $id);
$ok = $id > 0 && class_exists('\AKSRT\Messages\ReportCenter') && \AKSRT\Messages\ReportCenter::get_instance()->update_status($id, $new_status, $note);
$this->redirect('aksrt_user_ban', $ok ? 'report_updated' : 'report_failed', ['tab' => 'tickets']);
}
public function handle_process_appeal(): void {
if (!current_user_can(self::CAPABILITY)) {
wp_die(esc_html__('权限不足', 'aksrt'));
}
$user_id = isset($_POST['user_id']) ? (int) $_POST['user_id'] : 0;
$decision = isset($_POST['decision']) ? sanitize_key((string) wp_unslash($_POST['decision'])) : '';
$note = isset($_POST['note']) ? sanitize_textarea_field((string) wp_unslash($_POST['note'])) : '';
check_admin_referer('aksrt_users_process_appeal_' . $user_id);
if ($user_id <= 0 || !in_array($decision, ['approve', 'reject'], true) || !class_exists('\AKSRT\User\BanAppeal')) {
$this->redirect('aksrt_user_ban', 'appeal_failed', ['tab' => 'tickets', 'type' => 'appeal']);
}
$status = $decision === 'approve' ? 'approved' : 'rejected';
update_user_meta($user_id, \AKSRT\User\BanAppeal::META_STATUS, $status);
$payload = \AKSRT\User\BanAppeal::get_payload($user_id);
$payload['admin_note'] = $note;
$payload['handled_at'] = current_time('Y-m-d H:i');
$payload['handled_by'] = get_current_user_id();
$payload['decision'] = $status;
update_user_meta($user_id, \AKSRT\User\BanAppeal::META_PAYLOAD, $payload);
$history = get_user_meta($user_id, \AKSRT\User\BanAppeal::META_HISTORY, true);
$history = is_array($history) ? $history : [];
$history[] = $payload;
update_user_meta($user_id, \AKSRT\User\BanAppeal::META_HISTORY, array_slice($history, -30));
if ($decision === 'approve' && class_exists('\AKSRT\User\Restriction')) {
\AKSRT\User\Restriction::get_instance()->lift_user_restriction($user_id);
}
if (class_exists('\AKSRT\Messages\Message')) {
$msg = $decision === 'approve'
? __('你的禁封申诉已通过,限制已解除。', 'aksrt')
: __('你的禁封申诉未通过,可修改后重新提交。', 'aksrt');
if ($note !== '') {
$msg .= ' ' . sprintf(__('备注:%s', 'aksrt'), $note);
}
\AKSRT\Messages\Message::get_instance()->send(
$user_id,
'ban_appeal',
$msg,
[
'title' => $decision === 'approve' ? __('申诉通过', 'aksrt') : __('申诉驳回', 'aksrt'),
]
);
}
do_action('aksrt_ban_appeal_processed', $user_id, $decision, $note);
$this->redirect(
'aksrt_user_ban',
$decision === 'approve' ? 'appeal_approved' : 'appeal_rejected',
['tab' => 'tickets', 'type' => 'appeal']
);
}
private function pagination(int $pages, int $page_num): void {
if ($pages <= 1) {
return;