feat(admin): fully align the ban page with the reference theme
- submenu page title becomes 处理举报及禁封申诉 (menu title 举报&禁封申诉) - replicate the reference pagenavi: first/prev/numbered/next/last links with displaying-num (每页 20 共N) and paging-input (第X页共Y页) - report process form is now status-only like the reference theme: 被举报用户/举报信息/被举报用户禁封信息/处理说明 blocks, with a 点击此处 link to the restrictions tab (prefilled user_id) instead of an enforcement select - replicate reference row details (举报用户/举报内容, 正在处理 state, 此用户已解封 auto-close for stale appeals, 当前用户已解封 notice) and the table-box/preview-item style block - drop now-unused ReportCenter::get_report_row
This commit is contained in:
@@ -82,7 +82,7 @@ class UsersMenus {
|
||||
);
|
||||
add_submenu_page(
|
||||
'users.php',
|
||||
__('举报&禁封申诉', 'aksrt'),
|
||||
__('处理举报及禁封申诉', 'aksrt'),
|
||||
__('举报&禁封申诉', 'aksrt'),
|
||||
self::CAPABILITY,
|
||||
'aksrt_user_ban',
|
||||
@@ -324,7 +324,7 @@ class UsersMenus {
|
||||
echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '" style="margin-bottom:20px;display:flex;gap:8px;flex-wrap:wrap;align-items:end;">';
|
||||
echo '<input type="hidden" name="action" value="aksrt_users_add_restriction" />';
|
||||
wp_nonce_field('aksrt_users_add_restriction');
|
||||
echo '<p><label>' . esc_html__('用户 ID', 'aksrt') . '<br><input type="number" name="user_id" min="1" required /></label></p>';
|
||||
echo '<p><label>' . esc_html__('用户 ID', 'aksrt') . '<br><input type="number" name="user_id" min="1" required value="' . esc_attr((string) (isset($_GET['user_id']) ? max(0, (int) $_GET['user_id']) : 0)) . '" /></label></p>';
|
||||
echo '<p><label>' . esc_html__('类型', 'aksrt') . '<br><select name="type">';
|
||||
foreach (['warn' => __('警告', 'aksrt'), 'mute' => __('禁言', 'aksrt'), 'suspend' => __('停权', 'aksrt'), 'ban' => __('封禁', 'aksrt')] as $key => $label) {
|
||||
printf('<option value="%s">%s</option>', esc_attr($key), esc_html($label));
|
||||
@@ -377,28 +377,11 @@ class UsersMenus {
|
||||
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'])) : '';
|
||||
$action_taken = isset($_POST['action_taken']) ? sanitize_key((string) wp_unslash($_POST['action_taken'])) : 'none';
|
||||
$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 = false;
|
||||
if ($id > 0 && class_exists('\AKSRT\Messages\ReportCenter')) {
|
||||
$svc = \AKSRT\Messages\ReportCenter::get_instance();
|
||||
$ok = $svc->update_status($id, $new_status, $note);
|
||||
if ($ok && $action_taken !== '' && $action_taken !== 'none') {
|
||||
$row = $svc->get_report_row($id);
|
||||
if ($row) {
|
||||
$svc->apply_action(
|
||||
sanitize_key((string) $row['target_type']),
|
||||
(int) $row['target_id'],
|
||||
$action_taken,
|
||||
(string) ($row['reason'] ?? '')
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
$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']);
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +119,8 @@ trait UsersMenusTickets {
|
||||
$orderby = in_array($orderby, ['time', 'status', 'type'], true) ? $orderby : 'time';
|
||||
$order = (isset($_GET['order']) && strtoupper((string) $_GET['order']) === 'ASC') ? 'ASC' : 'DESC';
|
||||
|
||||
$action_url = admin_url('users.php?page=aksrt_user_ban');
|
||||
$action_url = admin_url('users.php?page=aksrt_user_ban');
|
||||
$process_action = isset($_GET['action']) ? sanitize_key((string) wp_unslash($_GET['action'])) : '';
|
||||
$page_url = add_query_arg(array_filter([
|
||||
'tab' => 'tickets',
|
||||
'type' => $type,
|
||||
@@ -128,6 +129,13 @@ trait UsersMenusTickets {
|
||||
'send_user' => $send_user,
|
||||
], static function ($v) { return $v !== '' && $v !== 0; }), $action_url);
|
||||
|
||||
// 对齐参考主题页面样式块
|
||||
echo '<style>
|
||||
.table-box>table{min-width:740px;}
|
||||
.preview-item{position:relative;display:inline-block;width:160px;height:160px;border-radius:4px;background:#fff;margin:5px;vertical-align:top;}
|
||||
.preview-item img{object-fit:contain;width:100%;height:100%;}
|
||||
</style>';
|
||||
|
||||
$rows = $this->collect_ticket_rows($type, $status, $s, $send_user, $orderby, $order);
|
||||
$total = count($rows);
|
||||
$pages = max(1, (int) ceil($total / self::TICKETS_PER_PAGE));
|
||||
@@ -175,6 +183,10 @@ trait UsersMenusTickets {
|
||||
echo '<div class="mb10">"' . esc_html($s) . '" ' . esc_html__('的搜索结果', 'aksrt') . '</div>';
|
||||
}
|
||||
|
||||
if ($process_action === 'process') {
|
||||
echo '<a href="' . esc_url(remove_query_arg(['action', 'id'], $page_url)) . '">' . esc_html__('查看全部', 'aksrt') . '</a>';
|
||||
}
|
||||
|
||||
echo '<div class="table-box" style="overflow-y:auto;width:100%;">';
|
||||
echo '<table class="widefat fixed striped posts" style="min-width:1000px;">';
|
||||
echo '<thead><tr>';
|
||||
@@ -205,8 +217,7 @@ trait UsersMenusTickets {
|
||||
echo '<tr><td colspan="6" align="center"><strong>' . esc_html__('暂无申请记录', 'aksrt') . '</strong></td></tr>';
|
||||
}
|
||||
|
||||
$process_action = isset($_GET['action']) ? sanitize_key((string) wp_unslash($_GET['action'])) : '';
|
||||
$process_id = isset($_GET['id']) ? (string) wp_unslash($_GET['id']) : '';
|
||||
$process_id = isset($_GET['id']) ? (string) wp_unslash($_GET['id']) : '';
|
||||
|
||||
foreach ($tickets as $row) {
|
||||
$this->render_ticket_row($row, $page_url);
|
||||
@@ -217,7 +228,28 @@ trait UsersMenusTickets {
|
||||
|
||||
echo '</tbody></table></div>';
|
||||
|
||||
$this->pagination($pages, $paged);
|
||||
$this->ticket_pagenavi($total, self::TICKETS_PER_PAGE);
|
||||
}
|
||||
|
||||
/** 分页(对齐参考主题 zibpay_admin_pagenavi:« ‹ 第X页共Y页 › » + 每页显示数) */
|
||||
private function ticket_pagenavi(int $total_count, int $per_page): void {
|
||||
$current_page = isset($_GET['paged']) ? max(1, (int) $_GET['paged']) : 1;
|
||||
$total_pages = max(1, (int) ceil($total_count / max(1, $per_page)));
|
||||
|
||||
$first_page_url = add_query_arg('paged', 1);
|
||||
$last_page_url = add_query_arg('paged', $total_pages);
|
||||
$prev_page_url = $current_page > 1 ? add_query_arg('paged', $current_page - 1) : '#';
|
||||
$next_page_url = $current_page < $total_pages ? add_query_arg('paged', $current_page + 1) : '#';
|
||||
|
||||
echo '<div class="tablenav bottom"><div class="tablenav-pages">';
|
||||
echo '<span class="displaying-num">' . esc_html(sprintf(__('每页 %1$s 共%2$s', 'aksrt'), $per_page, $total_count)) . '</span>';
|
||||
echo '<span class="pagination-links">';
|
||||
echo '<a class="first-page button' . ($current_page <= 1 ? ' disabled' : '') . '" title="' . esc_attr__('前往第一页', 'aksrt') . '" href="' . esc_url($first_page_url) . '">«</a>';
|
||||
echo '<a class="prev-page button' . ($current_page <= 1 ? ' disabled' : '') . '" title="' . esc_attr__('前往上一页', 'aksrt') . '" href="' . esc_url($prev_page_url) . '">‹</a>';
|
||||
echo '<span class="paging-input">' . esc_html(sprintf(__('第 %1$s 页,共 ', 'aksrt'), $current_page)) . '<span class="total-pages">' . esc_html((string) $total_pages) . '</span>' . esc_html__(' 页', 'aksrt') . '</span>';
|
||||
echo '<a class="next-page button' . ($current_page >= $total_pages ? ' disabled' : '') . '" title="' . esc_attr__('前往下一页', 'aksrt') . '" href="' . esc_url($next_page_url) . '">›</a>';
|
||||
echo '<a class="last-page button' . ($current_page >= $total_pages ? ' disabled' : '') . '" title="' . esc_attr__('前往最后一页', 'aksrt') . '" href="' . esc_url($last_page_url) . '">»</a>';
|
||||
echo '</span></div><br class="clear"></div>';
|
||||
}
|
||||
|
||||
private function render_ticket_row(array $row, string $page_url): void {
|
||||
@@ -226,8 +258,12 @@ trait UsersMenusTickets {
|
||||
$user_id = (int) $row['user_id'];
|
||||
$url = add_query_arg(['action' => 'process', 'id' => $kind . '-' . $row['id']], $page_url);
|
||||
|
||||
// 状态列(对齐参考主题:待处理→立即处理按钮 / 已批准 / 处理完成 / 已拒绝)
|
||||
if ($status === 'pending') {
|
||||
// 状态列(对齐参考主题:待处理→立即处理按钮 / 已批准 / 处理完成 / 已拒绝 / 正在处理)
|
||||
$is_processing = isset($_GET['action']) && sanitize_key((string) wp_unslash($_GET['action'])) === 'process'
|
||||
&& isset($_GET['id']) && (string) wp_unslash($_GET['id']) === $kind . '-' . (string) $row['id'];
|
||||
if ($is_processing) {
|
||||
$status_html = '<span style="color:#fb4444;">' . esc_html__('正在处理', 'aksrt') . '</span>';
|
||||
} elseif ($status === 'pending') {
|
||||
$status_html = '<a class="button" href="' . esc_url($url) . '">' . esc_html__('立即处理', 'aksrt') . '</a>';
|
||||
} elseif ($status === 'resolved') {
|
||||
$status_html = $kind === 'appeal'
|
||||
@@ -267,13 +303,17 @@ trait UsersMenusTickets {
|
||||
echo '</tr>';
|
||||
}
|
||||
|
||||
/** 举报行详情(对齐参考主题:举报目标红字 + 原因 + 分类) */
|
||||
/** 举报行详情(对齐参考主题:举报用户/举报内容红字 + 原因) */
|
||||
private function ticket_report_desc_html(array $r): string {
|
||||
$target_type = sanitize_key((string) ($r['target_type'] ?? ''));
|
||||
$target_id = (int) ($r['target_id'] ?? 0);
|
||||
$link = $this->ticket_target_link($target_type, $target_id);
|
||||
|
||||
$html = '<div style="color:#fb4444;">' . esc_html(sprintf(__('举报目标:%s', 'aksrt'), $link !== '' ? $link : $target_type . ' #' . $target_id)) . '</div>';
|
||||
if ($target_type === 'user') {
|
||||
$html = '<div style="color:#fb4444;">' . esc_html__('举报用户:', 'aksrt') . ($link !== '' ? $link : esc_html('#' . $target_id)) . '</div>';
|
||||
} else {
|
||||
$html = '<div style="color:#fb4444;">' . esc_html__('举报内容:', 'aksrt') . ($link !== '' ? $link : esc_html($target_type . ' #' . $target_id)) . '</div>';
|
||||
}
|
||||
$html .= '<div>' . esc_html(sprintf(__('举报原因:%s', 'aksrt'), (string) ($r['reason'] ?? ''))) . '</div>';
|
||||
if (!empty($r['category'])) {
|
||||
$html .= '<div>' . esc_html(sprintf(__('分类:%s', 'aksrt'), (string) $r['category'])) . '</div>';
|
||||
@@ -283,7 +323,7 @@ trait UsersMenusTickets {
|
||||
|
||||
/** 申诉行详情(对齐参考主题:禁封状态/原因/起止时间,或已解封) */
|
||||
private function ticket_appeal_desc_html(array $payload, int $user_id): string {
|
||||
$ban_html = $this->ticket_ban_info_html($user_id);
|
||||
$ban_html = $this->ticket_ban_info_html($user_id, 'appeal_row');
|
||||
$html = $ban_html;
|
||||
if (!empty($payload['reason'])) {
|
||||
$html .= '<div>' . esc_html(sprintf(__('申诉说明:%s', 'aksrt'), (string) $payload['reason'])) . '</div>';
|
||||
@@ -291,13 +331,17 @@ trait UsersMenusTickets {
|
||||
return $html;
|
||||
}
|
||||
|
||||
/** 用户当前限制状态摘要(对齐参考主题禁封信息展示) */
|
||||
private function ticket_ban_info_html(int $user_id): string {
|
||||
/**
|
||||
* 用户当前限制状态摘要(对齐参考主题禁封信息展示)。
|
||||
*
|
||||
* @param string $context appeal_row(申诉列表行,已解封时自动结案)| form(处理表单)
|
||||
*/
|
||||
private function ticket_ban_info_html(int $user_id, string $context = 'form'): string {
|
||||
if ($user_id <= 0 || !class_exists('\AKSRT\User\Restriction')) {
|
||||
return '';
|
||||
}
|
||||
$svc = \AKSRT\User\Restriction::get_instance();
|
||||
$ban = $svc->get_active_ban($user_id);
|
||||
$svc = \AKSRT\User\Restriction::get_instance();
|
||||
$ban = $svc->get_active_ban($user_id);
|
||||
|
||||
if ($ban) {
|
||||
$end = !empty($ban['expires_at']) ? (string) $ban['expires_at'] : __('永久', 'aksrt');
|
||||
@@ -315,6 +359,17 @@ trait UsersMenusTickets {
|
||||
return '<div style="color:#fd6a11;">' . esc_html(sprintf(__('限制状态:%s', 'aksrt'), __('禁言中', 'aksrt'))) . '</div>';
|
||||
}
|
||||
|
||||
// 对齐参考主题:申诉列表行中用户已无禁封 → 显示已解封并自动结案
|
||||
if ($context === 'appeal_row' && class_exists('\AKSRT\User\BanAppeal') && \AKSRT\User\BanAppeal::get_status($user_id) === 'pending') {
|
||||
update_user_meta($user_id, \AKSRT\User\BanAppeal::META_STATUS, 'approved');
|
||||
return '<div style="color:#fd6a11;">' . esc_html__('此用户已解封', 'aksrt') . '</div>';
|
||||
}
|
||||
|
||||
// 对齐参考主题:申诉处理表单中用户已解封的提示
|
||||
if ($context === 'appeal_form') {
|
||||
return '<div style="color:#16a60a;">' . esc_html__('当前用户已解封', 'aksrt') . '</div>';
|
||||
}
|
||||
|
||||
return '<div style="color:#16a60a;">' . esc_html__('用户状态正常', 'aksrt') . '</div>';
|
||||
}
|
||||
|
||||
@@ -352,9 +407,10 @@ trait UsersMenusTickets {
|
||||
$target_id = (int) ($r['target_id'] ?? 0);
|
||||
$link = $this->ticket_target_link($target_type, $target_id);
|
||||
|
||||
echo '<tr><th>' . esc_html__('被举报目标', 'aksrt') . '</th><td>';
|
||||
echo '<tr><th>' . esc_html__('被举报用户', 'aksrt') . '</th><td>';
|
||||
echo $link !== '' ? $link : esc_html($target_type . ' #' . $target_id);
|
||||
echo '<input type="hidden" name="report_id" value="' . esc_attr((string) $row['id']) . '" />';
|
||||
echo '<input type="hidden" name="new_status" value="resolved" />';
|
||||
echo '</td></tr>';
|
||||
|
||||
echo '<tr><th>' . esc_html__('举报信息', 'aksrt') . '</th><td>';
|
||||
@@ -366,44 +422,19 @@ trait UsersMenusTickets {
|
||||
echo '</td></tr>';
|
||||
|
||||
if ($target_type === 'user') {
|
||||
echo '<tr><th>' . esc_html__('被举报用户限制信息', 'aksrt') . '</th><td>';
|
||||
echo $this->ticket_ban_info_html($target_id);
|
||||
echo '<p class="description">' . esc_html__('如举报事实清楚,可对用户执行处罚动作,处理结果会反馈给举报人。', 'aksrt') . '</p>';
|
||||
echo '<tr><th>' . esc_html__('被举报用户禁封信息', 'aksrt') . '</th><td>';
|
||||
if (class_exists('\AKSRT\User\Restriction') && \AKSRT\User\Restriction::get_instance()->is_restricted($target_id)) {
|
||||
echo $this->ticket_ban_info_html($target_id);
|
||||
} else {
|
||||
$ban_url = admin_url('users.php?page=aksrt_user_ban&tab=restrictions&user_id=' . $target_id);
|
||||
echo '<div style="color:#16a60a;">' . esc_html__('用户状态正常', 'aksrt') . '</div>';
|
||||
echo '<p class="description">' . esc_html__('请查阅相关资料以及举证,如举报事实清楚,可以', 'aksrt');
|
||||
echo ' <a target="_blank" href="' . esc_url($ban_url) . '">' . esc_html__('点击此处', 'aksrt') . '</a> ';
|
||||
echo esc_html__('对用户做禁封处理,并将处理结果填写至下方', 'aksrt') . '</p>';
|
||||
}
|
||||
echo '</td></tr>';
|
||||
|
||||
echo '<tr><th>' . esc_html__('处罚动作', 'aksrt') . '</th><td><select name="action_taken">';
|
||||
foreach ([
|
||||
'none' => __('仅更新状态', 'aksrt'),
|
||||
'warn' => __('发送警告', 'aksrt'),
|
||||
'mute' => __('禁言', 'aksrt'),
|
||||
'suspend' => __('停权', 'aksrt'),
|
||||
'ban' => __('封禁账号', 'aksrt'),
|
||||
'clear' => __('解除限制', 'aksrt'),
|
||||
] as $value => $label) {
|
||||
printf('<option value="%s">%s</option>', esc_attr($value), esc_html($label));
|
||||
}
|
||||
echo '</select></td></tr>';
|
||||
} else {
|
||||
echo '<tr><th>' . esc_html__('内容处理', 'aksrt') . '</th><td><select name="action_taken">';
|
||||
foreach ([
|
||||
'none' => __('仅更新状态', 'aksrt'),
|
||||
'content_removed' => __('转为待审内容', 'aksrt'),
|
||||
] as $value => $label) {
|
||||
printf('<option value="%s">%s</option>', esc_attr($value), esc_html($label));
|
||||
}
|
||||
echo '</select></td></tr>';
|
||||
}
|
||||
|
||||
echo '<tr><th>' . esc_html__('处理结果', 'aksrt') . '</th><td><select name="new_status">';
|
||||
foreach ([
|
||||
'resolved' => __('处理完成', 'aksrt'),
|
||||
'dismissed' => __('已驳回', 'aksrt'),
|
||||
'reviewing' => __('处理中', 'aksrt'),
|
||||
] as $value => $label) {
|
||||
printf('<option value="%s"%s>%s</option>', esc_attr($value), $value === 'resolved' ? ' selected="selected"' : '', esc_html($label));
|
||||
}
|
||||
echo '</select></td></tr>';
|
||||
|
||||
echo '<tr><th>' . esc_html__('处理说明', 'aksrt') . '</th><td>';
|
||||
echo '<textarea style="width:95%;max-width:500px;" rows="2" cols="40" name="note" placeholder="' . esc_attr__('请输入本次处理的方式及说明', 'aksrt') . '"></textarea>';
|
||||
echo '<p class="description">' . esc_html__('此处内容会反馈给举报人', 'aksrt') . '</p>';
|
||||
@@ -424,7 +455,7 @@ trait UsersMenusTickets {
|
||||
echo '<input type="hidden" name="user_id" value="' . esc_attr((string) $uid) . '" />';
|
||||
echo '</td></tr>';
|
||||
|
||||
echo '<tr><th>' . esc_html__('禁封信息', 'aksrt') . '</th><td>' . $this->ticket_ban_info_html($uid) . '</td></tr>';
|
||||
echo '<tr><th>' . esc_html__('禁封信息', 'aksrt') . '</th><td>' . $this->ticket_ban_info_html($uid, 'appeal_form') . '</td></tr>';
|
||||
|
||||
echo '<tr><th>' . esc_html__('申诉信息', 'aksrt') . '</th><td>';
|
||||
$payload = $row['payload'];
|
||||
|
||||
@@ -159,20 +159,6 @@ class ReportCenter {
|
||||
return $result !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单条举报原始行(ARRAY_A),不存在返回 null。
|
||||
*/
|
||||
public function get_report_row(int $report_id): ?array {
|
||||
$table = $this->table();
|
||||
if ($table === '' || $report_id <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
$row = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$table} WHERE id = %d", $report_id), ARRAY_A);
|
||||
return $row ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对举报目标执行处罚动作(REST 与原生后台共用入口)。
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user