feat: unify referral promotion tabs and compact earnings UI

This commit is contained in:
2026-08-16 20:40:21 +08:00
parent 8799063c6c
commit ff730ab593
7 changed files with 144 additions and 52 deletions
+3 -4
View File
@@ -376,10 +376,9 @@ trait PayHelpers {
if (empty($aff['enabled'])) {
return $empty;
}
$referrer_id = 0;
if (class_exists('\AKSRT\Credits\Invite') && method_exists(\AKSRT\Credits\Invite::get_instance(), 'get_referrer')) {
$referrer_id = (int) \AKSRT\Credits\Invite::get_instance()->get_referrer($user_id);
}
$referrer_id = class_exists('\AKSRT\Payment\ReferralAttribution')
? \AKSRT\Payment\ReferralAttribution::get_instance()->resolve($user_id)
: 0;
if ($referrer_id <= 0) {
return $empty;
}
+2 -2
View File
@@ -74,10 +74,10 @@ class Invite {
],
]);
}
/** Capture ?ref=XYZ, with legacy ?invite=XYZ support. */
/** Capture the unified ?ref=XYZ referral parameter. */
public function capture_invite_cookie(): void {
if (is_admin()) return;
$raw_code = $_GET['ref'] ?? $_GET['invite'] ?? '';
$raw_code = $_GET['ref'] ?? '';
if ($raw_code === '') return;
// 邀请注册功能关闭时不处理
if (class_exists('\AKSRT\Settings\Settings') && !\AKSRT\Settings\Settings::invite_registration_enabled()) return;
+9 -1
View File
@@ -90,7 +90,15 @@ final class CommissionLedger {
public function overview(int $user_id): array {
global $wpdb; $table=$this->table('commission_ledger');
$row=$wpdb->get_row($wpdb->prepare("SELECT COALESCE(SUM(original_amount+adjustment_total),0) total, COALESCE(SUM(CASE WHEN status='pending' THEN original_amount+adjustment_total ELSE 0 END),0) pending, COALESCE(SUM(CASE WHEN status='settled' THEN original_amount+adjustment_total ELSE 0 END),0) settled FROM {$table} WHERE promoter_id=%d",$user_id),ARRAY_A) ?: [];
return ['total'=>round((float)($row['total']??0),2),'pending'=>round((float)($row['pending']??0),2),'settled'=>round((float)($row['settled']??0),2),'wallet'=>class_exists('\\AKSRT\\Credits\\Balance')?\AKSRT\Credits\Balance::balance($user_id):0.0,'debt'=>round((float)get_user_meta($user_id,self::DEBT_META,true),2)];
$withdrawn = 0.0;
$withdrawal_table = $this->table('withdrawal');
if ($withdrawal_table !== '') {
$withdrawn = (float) $wpdb->get_var($wpdb->prepare(
"SELECT COALESCE(SUM(CASE WHEN status='completed' THEN CASE WHEN gross_amount > 0 THEN gross_amount ELSE amount END ELSE 0 END),0) FROM {$withdrawal_table} WHERE user_id=%d",
$user_id
));
}
return ['total'=>round((float)($row['total']??0),2),'pending'=>round((float)($row['pending']??0),2),'settled'=>round((float)($row['settled']??0),2),'wallet'=>class_exists('\\AKSRT\\Credits\\Balance')?\AKSRT\Credits\Balance::balance($user_id):0.0,'withdrawn'=>round($withdrawn,2),'debt'=>round((float)get_user_meta($user_id,self::DEBT_META,true),2)];
}
public function list_entries(int $user_id, array $args=[]): array {
global $wpdb; $table=$this->table('commission_ledger'); $limit=max(1,min(100,(int)($args['per_page']??20))); $page=max(1,(int)($args['page']??1)); $offset=($page-1)*$limit; $where='promoter_id=%d'; $params=[$user_id]; $status=sanitize_key((string)($args['status']??'')); if(in_array($status,['pending','settled','cancelled'],true)){ $where.=' AND status=%s'; $params[]=$status; } $total=(int)$wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM {$table} WHERE {$where}",$params)); $rows=$wpdb->get_results($wpdb->prepare("SELECT * FROM {$table} WHERE {$where} ORDER BY id DESC LIMIT %d OFFSET %d",array_merge($params,[$limit,$offset])),ARRAY_A); return ['items'=>$rows?:[],'total'=>$total,'page'=>$page,'per_page'=>$limit,'max_pages'=>max(1,(int)ceil($total/$limit))];
+41
View File
@@ -140,6 +140,47 @@ final class ReferralAttribution {
return ['promoters' => $promoters, 'effective_payers' => $payers];
}
/**
* Return users bound through the forward-only ref relation.
*
* @return array{items:array<int,array<string,mixed>>,total:int,page:int,per_page:int,max_pages:int}
*/
public function list_referred_users(int $promoter_id, int $page = 1, int $per_page = 10): array {
global $wpdb;
$table = \AKSRT\Core\DBMigrator::table('affiliate_relation');
$page = max(1, $page);
$per_page = max(1, min(50, $per_page));
if ($promoter_id <= 0 || $table === '') {
return ['items' => [], 'total' => 0, 'page' => $page, 'per_page' => $per_page, 'max_pages' => 1];
}
$total = (int) $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM {$table} WHERE promoter_id=%d AND status='bound' AND invitee_id > 0",
$promoter_id
));
$rows = $wpdb->get_results($wpdb->prepare(
"SELECT invitee_id, referral_code, bound_at, status FROM {$table} WHERE promoter_id=%d AND status='bound' AND invitee_id > 0 ORDER BY id DESC LIMIT %d OFFSET %d",
$promoter_id,
$per_page,
($page - 1) * $per_page
), ARRAY_A);
$items = [];
foreach ((array) $rows as $row) {
$invitee_id = (int) ($row['invitee_id'] ?? 0);
$user = $invitee_id > 0 ? get_userdata($invitee_id) : null;
if (!$user instanceof \WP_User) {
continue;
}
$items[] = [
'user_id' => $invitee_id,
'name' => $user->display_name,
'avatar' => get_avatar_url($invitee_id, ['size' => 64]),
'bound_at' => (string) ($row['bound_at'] ?? ''),
'status' => (string) ($row['status'] ?? 'bound'),
];
}
return ['items' => $items, 'total' => $total, 'page' => $page, 'per_page' => $per_page, 'max_pages' => max(1, (int) ceil($total / $per_page))];
}
public function register_routes(): void {
register_rest_route('aksrt/v1', '/promotion/me', [
'methods' => \WP_REST_Server::READABLE,