Files
wordpress-theme-aksrt/inc/classes/class-aksrt-charge-card.php
T

210 lines
6.2 KiB
PHP

<?php
/**
* AKSRT Charge Card — 充值卡系统
*
* 管理充值卡的创建、使用和查询。
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
class AKSRT_Charge_Card {
private static $instance = null;
const STATUS_ACTIVE = 'active';
const STATUS_USED = 'used';
const STATUS_EXPIRED = 'expired';
const STATUS_DISABLED = 'disabled';
public static function get_instance(): self {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function table(): string {
return AKSRT_DB_Migrator::table('charge_card');
}
/**
* 创建充值卡
*/
public function create(array $data): int {
global $wpdb;
$code = sanitize_text_field((string) ($data['code'] ?? ''));
$amount = (float) ($data['amount'] ?? 0);
$expires_at = sanitize_text_field((string) ($data['expires_at'] ?? ''));
$note = sanitize_textarea_field((string) ($data['note'] ?? ''));
if ($code === '' || $amount <= 0) {
return 0;
}
// 检查 code 唯一性
$exists = $wpdb->get_var($wpdb->prepare(
"SELECT id FROM {$this->table()} WHERE code = %s",
$code
));
if ($exists) return 0;
$result = $wpdb->insert($this->table(), [
'code' => $code,
'amount' => $amount,
'balance' => $amount,
'status' => self::STATUS_ACTIVE,
'expires_at' => $expires_at !== '' ? $expires_at : null,
'created_at' => current_time('mysql'),
'note' => $note,
]);
return $result ? (int) $wpdb->insert_id : 0;
}
/**
* 批量生成充值卡
*/
public function batch_create(float $amount, int $count, int $length = 16, string $prefix = ''): array {
$codes = [];
for ($i = 0; $i < $count; $i++) {
$code = $prefix . strtoupper(wp_generate_password($length, false));
$id = $this->create([
'code' => $code,
'amount' => $amount,
]);
if ($id > 0) {
$codes[] = $code;
}
}
return $codes;
}
/**
* 使用充值卡
*/
public function redeem(string $code, int $user_id): array {
global $wpdb;
$code = sanitize_text_field($code);
$card = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM {$this->table()} WHERE code = %s",
$code
), ARRAY_A);
if (!$card) {
return ['success' => false, 'message' => '充值卡不存在'];
}
if ($card['status'] !== self::STATUS_ACTIVE) {
return ['success' => false, 'message' => '充值卡已使用或已失效'];
}
if ($card['expires_at'] && strtotime($card['expires_at']) < time()) {
// 标记过期
$wpdb->update($this->table(), ['status' => self::STATUS_EXPIRED], ['id' => (int) $card['id']]);
return ['success' => false, 'message' => '充值卡已过期'];
}
$amount = (float) $card['balance'];
// 更新卡状态
$wpdb->update($this->table(), [
'status' => self::STATUS_USED,
'used_by' => $user_id,
'used_at' => current_time('mysql'),
'balance' => 0,
], ['id' => (int) $card['id']]);
// 增加用户余额
if (class_exists('AKSRT_Credits')) {
AKSRT_Credits::add($user_id, (int) $amount, 'charge_card', [
'ref_type' => 'charge_card',
'ref_id' => (int) $card['id'],
]);
}
return [
'success' => true,
'message' => sprintf('充值成功,已到账 %s 元', number_format($amount, 2)),
'amount' => $amount,
];
}
/**
* 获取充值卡列表
*/
public function get_list(array $args = []): array {
global $wpdb;
$limit = max(1, min(100, (int) ($args['limit'] ?? 20)));
$offset = max(0, (int) ($args['offset'] ?? 0));
$status = sanitize_key((string) ($args['status'] ?? ''));
$where = [];
$params = [];
if ($status !== '') {
$where[] = 'status = %s';
$params[] = $status;
}
$where_sql = $where ? 'WHERE ' . implode(' AND ', $where) : '';
$count_sql = "SELECT COUNT(*) FROM {$this->table()} {$where_sql}";
$total = $params ? (int) $wpdb->get_var($wpdb->prepare($count_sql, $params)) : (int) $wpdb->get_var($count_sql);
$sql = "SELECT * FROM {$this->table()} {$where_sql} ORDER BY created_at DESC LIMIT %d OFFSET %d";
$params[] = $limit;
$params[] = $offset;
$items = $wpdb->get_results($wpdb->prepare($sql, $params), ARRAY_A);
return [
'items' => $items ?: [],
'total' => $total,
'page' => floor($offset / $limit) + 1,
'max_pages' => ceil($total / $limit),
];
}
/**
* 禁用充值卡
*/
public function disable(int $id): bool {
global $wpdb;
return (bool) $wpdb->update($this->table(), [
'status' => self::STATUS_DISABLED,
], ['id' => $id]);
}
/**
* 获取统计
*/
public function get_stats(): array {
global $wpdb;
$table = $this->table();
$row = $wpdb->get_row(
"SELECT
COUNT(*) as total,
SUM(CASE WHEN status = 'active' THEN 1 ELSE 0 END) as active,
SUM(CASE WHEN status = 'used' THEN 1 ELSE 0 END) as used,
SUM(amount) as total_amount,
SUM(CASE WHEN status = 'used' THEN amount ELSE 0 END) as used_amount
FROM {$table}",
ARRAY_A
);
return [
'total' => (int) ($row['total'] ?? 0),
'active' => (int) ($row['active'] ?? 0),
'used' => (int) ($row['used'] ?? 0),
'total_amount' => (float) ($row['total_amount'] ?? 0),
'used_amount' => (float) ($row['used_amount'] ?? 0),
];
}
}