Files
wordpress-theme-aksrt/inc/classes/class-aksrt-user-balance-admin.php
T
kate522 c3eee3fa7e feat(admin): cash wallet adjust on user profile
Mirror credits admin with list column, profile form, and balance ledger
for manual wallet adjustments.
2026-07-16 16:29:15 +08:00

163 lines
5.9 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
/**
* Admin cash wallet adjust on WP user screens.
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
class AKSRT_User_Balance_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 {
if (!is_admin()) {
return;
}
add_filter('manage_users_columns', [$this, 'add_column']);
add_filter('manage_users_custom_column', [$this, 'render_column'], 10, 3);
add_filter('manage_users_sortable_columns', [$this, 'sortable']);
add_action('pre_get_users', [$this, 'sort_users']);
add_action('show_user_profile', [$this, 'render_section']);
add_action('edit_user_profile', [$this, 'render_section']);
add_action('personal_options_update', [$this, 'handle_update']);
add_action('edit_user_profile_update', [$this, 'handle_update']);
}
private function can_manage(): bool {
return current_user_can('manage_options');
}
public function add_column(array $columns): array {
if (!class_exists('AKSRT_Balance') || !AKSRT_Balance::enabled()) {
return $columns;
}
$columns['aksrt_wallet_balance'] = __('现金余额', 'aksrt');
return $columns;
}
public function render_column(string $output, string $column_name, int $user_id): string {
if ($column_name !== 'aksrt_wallet_balance') {
return $output;
}
if (!class_exists('AKSRT_Balance')) {
return '—';
}
return '<strong>' . esc_html(AKSRT_Balance::format(AKSRT_Balance::balance($user_id))) . '</strong>';
}
public function sortable(array $columns): array {
$columns['aksrt_wallet_balance'] = 'aksrt_wallet_balance';
return $columns;
}
public function sort_users($query): void {
if (!is_admin() || $query->get('orderby') !== 'aksrt_wallet_balance') {
return;
}
$query->set('meta_key', 'aksrt_balance');
$query->set('orderby', 'meta_value_num');
}
public function render_section(WP_User $user): void {
if (!class_exists('AKSRT_Balance') || !AKSRT_Balance::enabled()) {
return;
}
$balance = AKSRT_Balance::balance((int) $user->ID);
$can = $this->can_manage();
$log = AKSRT_Balance::get_log(['user_id' => (int) $user->ID, 'page' => 1, 'per_page' => 8]);
?>
<a id="aksrt-user-wallet"></a>
<h2><?php esc_html_e('现金钱包(AKSRT)', 'aksrt'); ?></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(AKSRT_Balance::format($balance)); ?></strong> <?php esc_html_e('元', 'aksrt'); ?></td>
</tr>
<?php if ($can) : ?>
<tr>
<th><?php esc_html_e('调整余额', 'aksrt'); ?></th>
<td>
<?php wp_nonce_field('aksrt_user_balance_adjust_' . (int) $user->ID, '_aksrt_balance_nonce'); ?>
<label for="aksrt_balance_delta"><?php esc_html_e('变动金额(正数=增加,负数=扣减)', 'aksrt'); ?></label><br>
<input type="number" step="0.01" name="aksrt_balance_delta" id="aksrt_balance_delta" value="" class="regular-text" />
<p>
<label for="aksrt_balance_reason"><?php esc_html_e('备注', 'aksrt'); ?></label><br>
<input type="text" name="aksrt_balance_reason" id="aksrt_balance_reason" class="regular-text" />
</p>
<p class="description"><?php esc_html_e('保存用户资料时生效,并写入余额流水。', 'aksrt'); ?></p>
</td>
</tr>
<?php endif; ?>
<tr>
<th><?php esc_html_e('近期流水', 'aksrt'); ?></th>
<td>
<?php if (!empty($log['items'])) : ?>
<table class="widefat striped" style="max-width:640px;">
<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></tr></thead>
<tbody>
<?php foreach ($log['items'] as $row) : ?>
<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(($row['delta'] > 0 ? '+' : '') . AKSRT_Balance::format((float) $row['delta'])); ?></td>
<td><?php echo esc_html(AKSRT_Balance::format((float) ($row['balance_after'] ?? 0))); ?></td>
<td><?php echo esc_html(AKSRT_Balance::reason_label((string) ($row['reason'] ?? ''))); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php else : ?>
<p><?php esc_html_e('暂无流水', 'aksrt'); ?></p>
<?php endif; ?>
</td>
</tr>
</table>
<?php
}
public function handle_update(int $user_id): void {
if (!$this->can_manage() || !class_exists('AKSRT_Balance') || !AKSRT_Balance::enabled()) {
return;
}
if (empty($_POST['_aksrt_balance_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash((string) $_POST['_aksrt_balance_nonce'])), 'aksrt_user_balance_adjust_' . $user_id)) {
return;
}
if (!isset($_POST['aksrt_balance_delta']) || $_POST['aksrt_balance_delta'] === '') {
return;
}
$delta = round((float) wp_unslash($_POST['aksrt_balance_delta']), 2);
if (abs($delta) < 0.0001) {
return;
}
$reason = isset($_POST['aksrt_balance_reason'])
? sanitize_text_field(wp_unslash((string) $_POST['aksrt_balance_reason']))
: __('管理员调整', 'aksrt');
if ($delta > 0) {
$result = AKSRT_Balance::add($user_id, $delta, 'admin', ['type' => 'user', 'id' => get_current_user_id()], $reason);
} else {
$result = AKSRT_Balance::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' => __('现金余额已更新', 'aksrt'),
]], 30);
}
}