Files
wordpress-theme-aksrt/inc/classes/class-aksrt-user-credits-admin.php
T
kate522 8d31e65ccd feat(admin,forum): download logs, hidecontent, VIP tiers, users commerce
Add aksrt_download_logs workbench, zibll hidecontent alias + topic
partial-hide path, VIP1/VIP2 price matrix for topics, and users list
commerce snapshot column with deep links.
2026-07-15 11:13:48 +08:00

324 lines
14 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* AKSRT User Credits Admin
*
* 把"用户积分管理"迁移到 WordPress 原生"用户"菜单:
* - users.php:增加积分余额列(可排序)+ 行操作
* - user-edit.php / profile.php:增加积分管理区块(管理员可调增减)+ 近期流水
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
class AKSRT_User_Credits_Admin {
private static $instance = null;
private function __construct() {}
public static function get_instance(): self {
if (null === self::$instance) self::$instance = new self();
return self::$instance;
}
public function init(): void {
add_filter('manage_users_columns', [$this, 'add_balance_column']);
add_filter('manage_users_custom_column', [$this, 'render_balance_column'], 10, 3);
add_filter('manage_users_sortable_columns', [$this, 'make_balance_sortable']);
add_action('pre_get_users', [$this, 'sort_users_by_credits']);
add_filter('user_row_actions', [$this, 'add_row_actions'], 30, 2);
add_action('show_user_profile', [$this, 'render_user_credits_section']);
add_action('edit_user_profile', [$this, 'render_user_credits_section']);
add_action('personal_options_update', [$this, 'handle_user_credits_update']);
add_action('edit_user_profile_update', [$this, 'handle_user_credits_update']);
}
private function can_manage_credits(): bool {
return current_user_can('manage_options');
}
// ========== 用户列表:积分余额列 ==========
public function add_balance_column(array $columns): array {
$currency_name = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_currency_name() : __('积分', 'aksrt');
$columns['aksrt_credits_balance'] = sprintf(__('%s余额', 'aksrt'), $currency_name);
$columns['aksrt_user_commerce'] = __('资产/分成', 'aksrt');
return $columns;
}
public function render_balance_column(string $output, string $column_name, int $user_id): string {
if ($column_name === 'aksrt_user_commerce') {
return $this->render_commerce_column($user_id);
}
if ($column_name !== 'aksrt_credits_balance') {
return $output;
}
if (!class_exists('AKSRT_Credits')) {
return '—';
}
$balance = AKSRT_Credits::balance($user_id);
return '<strong>' . esc_html((string) $balance) . '</strong>';
}
/**
* Compact commerce snapshot: VIP, revenue, rebate, download logs link.
*/
private function render_commerce_column(int $user_id): string {
$bits = [];
if (function_exists('aksrt_get_user_vip_level')) {
$lv = (int) aksrt_get_user_vip_level($user_id);
if ($lv > 0) {
$bits[] = '<span class="aksrt-vip-badge">VIP' . esc_html((string) $lv) . '</span>';
}
}
if (class_exists('AKSRT_Revenue')) {
$stats = AKSRT_Revenue::get_instance()->get_stats($user_id);
$pending = (float) ($stats['pending'] ?? 0);
$total = (float) ($stats['total'] ?? 0);
if ($total > 0 || $pending > 0) {
$bits[] = sprintf(
/* translators: 1 total 2 pending */
esc_html__('分成 ¥%1$s(待结 ¥%2$s)', 'aksrt'),
number_format($total, 2),
number_format($pending, 2)
);
$bits[] = '<a href="' . esc_url(admin_url('admin.php?page=aksrt_income')) . '">' . esc_html__('明细', 'aksrt') . '</a>';
}
}
if (class_exists('AKSRT_Rebate')) {
$list = AKSRT_Rebate::get_instance()->get_list(['user_id' => $user_id, 'limit' => 1]);
$total_r = (int) ($list['total'] ?? 0);
if ($total_r > 0) {
$sum = 0.0;
// Lightweight sum via stats if available; else show count.
if (method_exists(AKSRT_Rebate::get_instance(), 'get_stats')) {
// global stats only — show link with count
$bits[] = sprintf(esc_html__('返佣 %d 笔', 'aksrt'), $total_r);
} else {
$bits[] = sprintf(esc_html__('返佣 %d 笔', 'aksrt'), $total_r);
}
$bits[] = '<a href="' . esc_url(admin_url('admin.php?page=aksrt_rebate')) . '">' . esc_html__('返佣', 'aksrt') . '</a>';
}
}
$bits[] = '<a href="' . esc_url(admin_url('admin.php?page=aksrt_download_logs&user_id=' . $user_id)) . '">' . esc_html__('下载记录', 'aksrt') . '</a>';
$bits[] = '<a href="' . esc_url(admin_url('admin.php?page=aksrt_orders&s=' . $user_id)) . '">' . esc_html__('订单', 'aksrt') . '</a>';
if (!$bits) {
return '—';
}
return '<div style="font-size:12px;line-height:1.5;">' . implode('<br>', $bits) . '</div>';
}
public function make_balance_sortable(array $columns): array {
$columns['aksrt_credits_balance'] = 'aksrt_credits_balance';
return $columns;
}
public function sort_users_by_credits($query): void {
if (!is_admin()) {
return;
}
if ($query->get('orderby') !== 'aksrt_credits_balance') {
return;
}
$query->set('meta_key', 'aksrt_credits');
$query->set('orderby', 'meta_value_num');
}
// ========== 用户列表:行操作 ==========
public function add_row_actions(array $actions, WP_User $user): array {
if (!$this->can_manage_credits()) {
return $actions;
}
$edit_url = get_edit_user_link($user->ID);
if ($edit_url) {
$currency_name = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_currency_name() : __('积分', 'aksrt');
$actions['aksrt_edit_credits'] = sprintf(
'<a href="%s#aksrt-user-credits">%s</a>',
esc_url($edit_url),
esc_html(sprintf(__('调整%s', 'aksrt'), $currency_name))
);
}
$actions['aksrt_user_dl_logs'] = sprintf(
'<a href="%s">%s</a>',
esc_url(admin_url('admin.php?page=aksrt_download_logs&user_id=' . (int) $user->ID)),
esc_html__('下载记录', 'aksrt')
);
return $actions;
}
// ========== 用户编辑页:积分管理区块 ==========
public function render_user_credits_section(WP_User $user): void {
if (!class_exists('AKSRT_Credits')) {
return;
}
$balance = AKSRT_Credits::balance((int) $user->ID);
$can_manage = $this->can_manage_credits();
$currency_name = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_currency_name() : __('积分', 'aksrt');
?>
<a id="aksrt-user-credits"></a>
<h2><?php echo esc_html(sprintf(__('%s管理(AKSRT)', 'aksrt'), $currency_name)); ?></h2>
<table class="form-table" role="presentation">
<tr>
<th><?php esc_html_e('当前余额', 'aksrt'); ?></th>
<td>
<strong style="font-size:18px;"><?php echo esc_html((string) $balance); ?></strong>
<span style="color:#666;margin-left:6px;"><?php echo esc_html($currency_name); ?></span>
</td>
</tr>
<?php if ($can_manage) : ?>
<tr>
<th><?php echo esc_html(sprintf(__('调整%s', 'aksrt'), $currency_name)); ?></th>
<td>
<?php wp_nonce_field('aksrt_user_credits_adjust_' . (int) $user->ID, '_aksrt_credits_nonce'); ?>
<fieldset>
<label for="aksrt_credits_delta" style="display:block;margin-bottom:6px;">
<?php esc_html_e('变动数量(正数=增加,负数=扣减)', 'aksrt'); ?>
</label>
<input
type="number"
id="aksrt_credits_delta"
name="aksrt_credits_delta"
class="regular-text"
min="-100000"
max="100000"
step="1"
value="0"
>
<p class="description" style="margin-bottom:12px;">
<?php esc_html_e('填写 0 不会执行任何变更。', 'aksrt'); ?>
</p>
<label for="aksrt_credits_reason" style="display:block;margin-bottom:6px;">
<?php esc_html_e('调整原因', 'aksrt'); ?>
</label>
<input
type="text"
id="aksrt_credits_reason"
name="aksrt_credits_reason"
class="regular-text"
maxlength="100"
placeholder="<?php echo esc_attr__('例如:手工补偿 / 运营赠送 / 退款修正', 'aksrt'); ?>"
>
<p class="description">
<?php esc_html_e('勾选后点击页面底部"更新用户"保存即可生效。', 'aksrt'); ?>
</p>
</fieldset>
</td>
</tr>
<?php endif; ?>
</table>
<?php
// ========== 近期积分流水 ==========
$log = AKSRT_Credits::get_log(['user_id' => (int) $user->ID, 'page' => 1, 'per_page' => 20]);
$items = $log['items'] ?? [];
$reason_labels = [
'register' => __('注册赠送', 'aksrt'),
'signin' => __('每日签到', 'aksrt'),
'comment' => __('评论奖励', 'aksrt'),
'invite' => __('邀请奖励', 'aksrt'),
'invitee' => __('被邀请奖励', 'aksrt'),
'download' => __('下载消费', 'aksrt'),
'admin' => __('管理员调整', 'aksrt'),
];
?>
<h3 style="margin-top:24px;"><?php echo esc_html(sprintf(__('近期%s流水', 'aksrt'), $currency_name)); ?></h3>
<?php if (!empty($items)) : ?>
<table class="widefat striped" style="max-width:800px;">
<thead>
<tr>
<th><?php esc_html_e('时间', 'aksrt'); ?></th>
<th><?php esc_html_e('类型', 'aksrt'); ?></th>
<th><?php esc_html_e('备注', 'aksrt'); ?></th>
<th><?php esc_html_e('变动', 'aksrt'); ?></th>
<th><?php esc_html_e('余额', 'aksrt'); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($items as $row) :
$delta = (int) $row['delta'];
$reason_key = (string) ($row['reason'] ?? '');
$label = $reason_labels[$reason_key] ?? $reason_key;
?>
<tr>
<td><?php echo esc_html(get_date_from_gmt((string) $row['created_at'], 'Y-m-d H:i')); ?></td>
<td><?php echo esc_html($label); ?></td>
<td><?php echo esc_html((string) ($row['remark'] ?? '')); ?></td>
<td style="color:<?php echo $delta >= 0 ? '#16a34a' : '#ef4444'; ?>; font-weight:600;">
<?php echo esc_html(($delta > 0 ? '+' : '') . $delta); ?>
</td>
<td><?php echo esc_html((string) (int) $row['balance_after']); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php else : ?>
<p style="color:#888;"><?php echo esc_html(sprintf(__('暂无%s流水记录。', 'aksrt'), $currency_name)); ?></p>
<?php endif;
}
// ========== 处理积分调整 ==========
public function handle_user_credits_update(int $user_id): void {
if (!$this->can_manage_credits() || !class_exists('AKSRT_Credits')) {
return;
}
if (!current_user_can('edit_user', $user_id)) {
return;
}
if (!isset($_POST['_aksrt_credits_nonce'])) {
return;
}
$nonce = sanitize_text_field((string) $_POST['_aksrt_credits_nonce']);
if (!wp_verify_nonce($nonce, 'aksrt_user_credits_adjust_' . $user_id)) {
return;
}
$delta = isset($_POST['aksrt_credits_delta']) ? (int) $_POST['aksrt_credits_delta'] : 0;
$reason = isset($_POST['aksrt_credits_reason']) ? sanitize_text_field((string) wp_unslash($_POST['aksrt_credits_reason'])) : '';
if ($delta === 0) {
return;
}
$currency_name = class_exists('AKSRT_Settings') ? AKSRT_Settings::get_currency_name() : __('积分', 'aksrt');
if ($reason === '') {
set_transient('aksrt_admin_notice_' . get_current_user_id(), [[
'type' => 'error',
'msg' => sprintf(__('调整%s时请填写原因。', 'aksrt'), $currency_name),
]], 30);
return;
}
if ($delta > 0) {
$result = AKSRT_Credits::add($user_id, $delta, 'admin', ['type' => 'user', 'id' => get_current_user_id()], $reason);
} else {
$result = AKSRT_Credits::deduct($user_id, abs($delta), 'admin', ['type' => 'user', 'id' => get_current_user_id()], $reason);
}
if (is_wp_error($result)) {
set_transient('aksrt_admin_notice_' . get_current_user_id(), [[
'type' => 'error',
'msg' => $result->get_error_message(),
]], 30);
return;
}
set_transient('aksrt_admin_notice_' . get_current_user_id(), [[
'type' => 'success',
'msg' => sprintf(__('%s调整成功,当前余额:%d', 'aksrt'), $currency_name, (int) $result),
]], 30);
}
}