feat(admin): cash wallet adjust on user profile
Mirror credits admin with list column, profile form, and balance ledger for manual wallet adjustments.
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user