Files
wordpress-theme-aksrt/src/Admin/Native/UsersMenus.php
T
2026-10-30 23:06:04 +08:00

244 lines
10 KiB
PHP

<?php
/**
* @package AKSRT
*/
namespace AKSRT\Admin\Native;
defined('ABSPATH') || exit;
class UsersMenus {
use UsersMenusVerify;
use UsersMenusVip;
use UsersMenusInviteCode;
use UsersMenusBan;
use UsersMenusTicketsCenter;
use UsersMenusMessages;
public const CAPABILITY = 'manage_options';
private static $instance = null;
public static function get_instance(): self {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
public function init(): void {
if (!is_admin()) {
return;
}
NativeUi::boot();
add_action('admin_menu', [$this, 'register_menus']);
add_action('admin_notices', [$this, 'pending_notices']);
add_action('admin_post_aksrt_users_send_message', [$this, 'handle_send_message']);
add_action('admin_post_aksrt_users_bulk_messages', [$this, 'handle_bulk_messages']);
add_action('admin_post_aksrt_users_review_verify', [$this, 'handle_review_verify']);
add_action('admin_post_aksrt_users_delete_verify', [$this, 'handle_delete_verify']);
add_action('admin_post_aksrt_users_update_report', [$this, 'handle_update_report']);
add_action('admin_post_aksrt_users_process_appeal', [$this, 'handle_process_appeal']);
add_action('admin_post_aksrt_users_mutate_vip', [$this, 'handle_mutate_vip']);
add_action('admin_post_aksrt_ticket_update', [$this, 'handle_ticket_update']);
add_action('admin_enqueue_scripts', [$this, 'enqueue_ticket_assets']);
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']);
}
public function register_menus(): void {
add_submenu_page(
'users.php',
__('邀请码管理', 'aksrt'),
__('邀请码管理', 'aksrt'),
'edit_users',
'aksrt_invite_codes',
[$this, 'render_invite_codes_page']
);
if (!current_user_can(self::CAPABILITY)) {
return;
}
add_submenu_page(
'users.php',
__('消息管理', 'aksrt'),
__('消息管理', 'aksrt'),
self::CAPABILITY,
'aksrt_messages',
[$this, 'render_messages_page']
);
add_submenu_page(
'users.php',
__('用户会员', 'aksrt'),
__('用户会员', 'aksrt'),
self::CAPABILITY,
'aksrt_user_vip',
[$this, 'render_vip_page']
);
add_submenu_page(
'users.php',
__('身份认证', 'aksrt'),
__('身份认证', 'aksrt'),
self::CAPABILITY,
'aksrt_user_auth',
[$this, 'render_verify_page']
);
add_submenu_page(
'users.php',
__('处理举报及禁封申诉', 'aksrt'),
__('举报&禁封申诉', 'aksrt'),
self::CAPABILITY,
'aksrt_user_ban',
[$this, 'render_ban_page']
);
add_submenu_page(
'users.php',
__('工单管理', 'aksrt'),
__('工单管理', 'aksrt'),
self::CAPABILITY,
'aksrt_tickets',
[$this, 'render_tickets_page']
);
}
public function pending_notices(): void {
if (!current_user_can(self::CAPABILITY)) {
return;
}
$page = isset($_GET['page']) ? sanitize_key((string) wp_unslash($_GET['page'])) : '';
if ($page !== 'aksrt_user_auth') {
$pending_verify = $this->count_verify_status('pending');
if ($pending_verify > 0) {
$url = admin_url('users.php?page=aksrt_user_auth&status=pending');
echo '<div class="notice notice-info is-dismissible"><h3>' . esc_html__('用户身份认证申请待处理', 'aksrt') . '</h3>';
echo '<p>' . esc_html(sprintf(
/* translators: %d count */
__('您有 %d 个用户身份认证申请待处理', 'aksrt'),
$pending_verify
)) . '</p>';
echo '<p><a class="button button-primary" href="' . esc_url($url) . '">' . esc_html__('立即处理', 'aksrt') . '</a></p></div>';
}
}
if ($page !== 'aksrt_user_ban' && class_exists('\AKSRT\Messages\ReportCenter')) {
$pending_reports = (int) \AKSRT\Messages\ReportCenter::get_instance()->get_pending_count();
if ($pending_reports > 0) {
$url = admin_url('users.php?page=aksrt_user_ban&status=pending');
echo '<div class="notice notice-info is-dismissible"><h3>' . esc_html__('举报待处理', 'aksrt') . '</h3>';
echo '<p>' . esc_html(sprintf(
/* translators: %d count */
__('您有 %d 条举报待处理', 'aksrt'),
$pending_reports
)) . '</p>';
echo '<p><a class="button button-primary" href="' . esc_url($url) . '">' . esc_html__('立即处理', 'aksrt') . '</a></p></div>';
}
}
if ($page !== 'aksrt_user_ban' && class_exists('\AKSRT\User\BanAppeal')) {
$pending_appeals = count(get_users([
'meta_key' => \AKSRT\User\BanAppeal::META_STATUS,
'meta_value' => 'pending',
'number' => 50,
'fields' => 'ID',
]));
if ($pending_appeals > 0) {
$url = admin_url('users.php?page=aksrt_user_ban&type=appeal&status=pending');
echo '<div class="notice notice-warning is-dismissible"><h3>' . esc_html__('禁封申诉待处理', 'aksrt') . '</h3>';
echo '<p>' . esc_html(sprintf(__('您有 %d 条禁封申诉待处理', 'aksrt'), $pending_appeals)) . '</p>';
echo '<p><a class="button button-primary" href="' . esc_url($url) . '">' . esc_html__('立即处理', 'aksrt') . '</a></p></div>';
}
}
if ($page !== 'aksrt_tickets' && class_exists('\AKSRT\Ticket\TicketSettings') && \AKSRT\Ticket\TicketSettings::enabled()) {
$pending_tickets = $this->count_pending_tickets();
if ($pending_tickets > 0) {
$url = admin_url('users.php?page=aksrt_tickets&status=' . \AKSRT\Ticket\TicketStatusService::KEY_PENDING);
echo '<div class="notice notice-info is-dismissible"><h3>' . esc_html__('工单待接单', 'aksrt') . '</h3>';
echo '<p>' . esc_html(sprintf(
/* translators: %d count */
__('您有 %d 个工单待接单', 'aksrt'),
$pending_tickets
)) . '</p>';
echo '<p><a class="button button-primary" href="' . esc_url($url) . '">' . esc_html__('立即处理', 'aksrt') . '</a></p></div>';
}
}
}
private function ensure_cap(): void {
if (!current_user_can(self::CAPABILITY)) {
wp_die(esc_html__('您没有权限访问此页面。', 'aksrt'));
}
}
private function flash(): void {
if (empty($_GET['aksrt_users_msg'])) {
return;
}
$code = sanitize_key((string) wp_unslash($_GET['aksrt_users_msg']));
$map = [
'verify_updated' => __('认证状态已更新。', 'aksrt'),
'verify_deleted' => __('认证记录已删除。', 'aksrt'),
'verify_failed' => __('认证审核失败。', 'aksrt'),
'report_updated' => __('举报状态已更新。', 'aksrt'),
'report_failed' => __('举报更新失败。', 'aksrt'),
'appeal_approved' => __('申诉已通过,限制已解除。', 'aksrt'),
'appeal_rejected' => __('申诉已驳回。', 'aksrt'),
'appeal_failed' => __('申诉处理失败。', 'aksrt'),
'vip_updated' => __('会员状态已更新。', 'aksrt'),
'vip_partial' => __('部分用户的会员状态已更新。', 'aksrt'),
'vip_failed' => __('会员操作失败。', 'aksrt'),
];
if (!isset($map[$code])) {
return;
}
$class = str_contains($code, 'failed') ? 'notice-error' : 'notice-success';
$message = $map[$code];
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']));
}
if (in_array($code, ['vip_updated', 'vip_partial'], true)) {
$message .= ' ' . sprintf(
__('成功:%1$d;失败:%2$d;跳过:%3$d。', 'aksrt'),
absint($_GET['aksrt_vip_ok'] ?? 0),
absint($_GET['aksrt_vip_failed_count'] ?? 0),
absint($_GET['aksrt_vip_skipped'] ?? 0)
);
}
echo '<div class="notice ' . esc_attr($class) . ' is-dismissible"><p>' . esc_html($message) . '</p></div>';
}
private function redirect(string $page, string $msg, array $extra = []): void {
wp_safe_redirect(add_query_arg(array_merge(['page' => $page, 'aksrt_users_msg' => $msg], $extra), admin_url('users.php')));
exit;
}
private function pagination(int $pages, int $page_num): void {
if ($pages <= 1) {
return;
}
echo '<div class="tablenav"><div class="tablenav-pages">';
echo paginate_links([
'base' => add_query_arg('paged', '%#%'),
'format' => '',
'prev_text' => '&laquo;',
'next_text' => '&raquo;',
'total' => $pages,
'current' => $page_num,
]);
echo '</div></div>';
}
}