doge 7 часов назад
Родитель
Сommit
8edf35a7c7
1 измененных файлов с 80 добавлено и 64 удалено
  1. 80 64
      app/Services/NewUserSummaryService.php

+ 80 - 64
app/Services/NewUserSummaryService.php

@@ -5,22 +5,21 @@ namespace App\Services;
 use Illuminate\Support\Facades\DB;
 
 /**
- * 新用户汇总:区间集合查询,按天输出(无按天 PHP 循环打库)
+ * 新用户汇总:区间集合查询,按天输出
  *
  * 口径:
  * - H5/APP:register_domain 是否为包名风格(com.xxx.yyy)
  * - 活跃会员:当日新注册且当日下注 >= 50
  * - 有效会员:当日新注册且当日存款 >= 50
  * - 公司盈利:当日新用户当日 投注额 - 派奖
+ *
+ * 使用显式表前缀 raw SQL,避免 joinSub 别名前缀 / whereIn 多列 等问题。
  */
 class NewUserSummaryService
 {
     public const ACTIVE_BET_THRESHOLD = 50;
     public const VALID_DEPOSIT_THRESHOLD = 50;
 
-    /** MySQL:包名风格域名视为 APP */
-    private const IS_APP_SQL = "(register_domain REGEXP '^(com|org|net|io|cn)\\\\.[a-zA-Z0-9_]+(\\\\.[a-zA-Z0-9_]+)+$')";
-
     /**
      * @return array{start_time:string,end_time:string,rules:array,data:list<array>}
      */
@@ -28,84 +27,101 @@ class NewUserSummaryService
     {
         $rangeStart = $startDate . ' 00:00:00';
         $rangeEnd = $endDate . ' 23:59:59';
-        $isApp = self::IS_APP_SQL;
+        $p = DB::getTablePrefix();
+        $users = $p . 'users';
+        $logs = $p . 'balance_logs';
 
-        // 当日新注册用户(供后续 join)
-        $newUsers = DB::table('users')
-            ->selectRaw("
-                DATE(created_at) as reg_date,
-                COALESCE(NULLIF(member_id, ''), user_id) as member_key,
-                CASE WHEN {$isApp} THEN 1 ELSE 0 END as is_app
-            ")
-            ->whereBetween('created_at', [$rangeStart, $rangeEnd]);
+        // 包名风格 = APP
+        $isApp = "(u.register_domain REGEXP '^(com|org|net|io|cn)\\\\.[a-zA-Z0-9_]+(\\\\.[a-zA-Z0-9_]+)+$')";
 
         // 1) 注册按天
-        $registerByDay = DB::table('users')
-            ->selectRaw("
-                DATE(created_at) as d,
-                SUM(CASE WHEN {$isApp} THEN 1 ELSE 0 END) as app_register,
-                SUM(CASE WHEN {$isApp} THEN 0 ELSE 1 END) as h5_register
-            ")
-            ->whereBetween('created_at', [$rangeStart, $rangeEnd])
-            ->groupByRaw('DATE(created_at)')
-            ->get()
-            ->keyBy(fn ($r) => (string)$r->d);
-
-        // 2) 首存:新用户首次正充值落在注册日
-        $firstDepositSub = DB::table('balance_logs')
-            ->selectRaw('member_id, MIN(created_at) as first_at')
-            ->where('amount', '>', 0)
-            ->where(function ($q) {
-                $q->whereIn('change_type', ['充值', '人工充值', '三方充值'])
-                    ->orWhere(function ($q2) {
-                        $q2->where('change_type', 'like', '%充值%')
-                            ->where('change_type', 'not like', '%返现%')
-                            ->where('change_type', 'not like', '%退%');
-                    });
-            })
-            ->whereIn('member_id', (clone $newUsers)->selectRaw('COALESCE(NULLIF(member_id, \'\'), user_id)'))
-            ->groupBy('member_id');
+        $registerRows = DB::select(
+            "SELECT
+                DATE(u.created_at) AS d,
+                SUM(CASE WHEN {$isApp} THEN 1 ELSE 0 END) AS app_register,
+                SUM(CASE WHEN {$isApp} THEN 0 ELSE 1 END) AS h5_register
+             FROM {$users} u
+             WHERE u.created_at BETWEEN ? AND ?
+             GROUP BY DATE(u.created_at)",
+            [$rangeStart, $rangeEnd]
+        );
+        $registerByDay = [];
+        foreach ($registerRows as $r) {
+            $registerByDay[(string)$r->d] = $r;
+        }
 
-        $firstDepositByDay = DB::query()
-            ->fromSub($firstDepositSub, 'fd')
-            ->joinSub($newUsers, 'nu', 'nu.member_key', '=', 'fd.member_id')
-            ->whereRaw('DATE(fd.first_at) = nu.reg_date')
-            ->selectRaw("
-                nu.reg_date as d,
-                SUM(CASE WHEN nu.is_app = 1 THEN 1 ELSE 0 END) as app_first_deposit,
-                SUM(CASE WHEN nu.is_app = 0 THEN 1 ELSE 0 END) as h5_first_deposit
-            ")
-            ->groupBy('nu.reg_date')
-            ->get()
-            ->keyBy(fn ($r) => (string)$r->d);
+        // 2) 首存:新用户历史上第一次正充值时间 = 注册日
+        $firstDepositRows = DB::select(
+            "SELECT
+                nu.reg_date AS d,
+                SUM(CASE WHEN nu.is_app = 1 THEN 1 ELSE 0 END) AS app_first_deposit,
+                SUM(CASE WHEN nu.is_app = 0 THEN 1 ELSE 0 END) AS h5_first_deposit
+             FROM (
+                SELECT
+                    DATE(u.created_at) AS reg_date,
+                    COALESCE(NULLIF(u.member_id, ''), u.user_id) AS member_key,
+                    CASE WHEN {$isApp} THEN 1 ELSE 0 END AS is_app
+                FROM {$users} u
+                WHERE u.created_at BETWEEN ? AND ?
+             ) nu
+             INNER JOIN (
+                SELECT bl.member_id, MIN(bl.created_at) AS first_at
+                FROM {$logs} bl
+                WHERE bl.amount > 0
+                  AND (
+                    bl.change_type IN ('充值', '人工充值', '三方充值')
+                    OR (
+                        bl.change_type LIKE '%充值%'
+                        AND bl.change_type NOT LIKE '%返现%'
+                        AND bl.change_type NOT LIKE '%退%'
+                    )
+                  )
+                GROUP BY bl.member_id
+             ) fd ON fd.member_id COLLATE utf8mb4_general_ci = nu.member_key COLLATE utf8mb4_general_ci
+             WHERE DATE(fd.first_at) = nu.reg_date
+             GROUP BY nu.reg_date",
+            [$rangeStart, $rangeEnd]
+        );
+        $firstDepositByDay = [];
+        foreach ($firstDepositRows as $r) {
+            $firstDepositByDay[(string)$r->d] = $r;
+        }
 
-        // 3) 流水:新用户在其注册日的 投注/存款/派奖(每人一行)
-        $memberFlow = DB::table('balance_logs as bl')
-            ->joinSub($newUsers, 'nu', 'nu.member_key', '=', 'bl.member_id')
-            ->whereRaw('DATE(bl.created_at) = nu.reg_date')
-            ->whereBetween('bl.created_at', [$rangeStart, $rangeEnd])
-            ->selectRaw("
-                nu.reg_date as d,
+        // 3) 流水:新用户在其注册日的投注/存款/派奖(每人每天一行)
+        $memberFlow = DB::select(
+            "SELECT
+                nu.reg_date AS d,
                 bl.member_id,
                 SUM(CASE
                     WHEN bl.change_type LIKE '%投注%'
                          AND bl.change_type NOT LIKE '%退款%'
                          AND bl.change_type NOT LIKE '%中奖%'
-                    THEN ABS(bl.amount) ELSE 0 END) as bet_amt,
+                    THEN ABS(bl.amount) ELSE 0 END) AS bet_amt,
                 SUM(CASE
                     WHEN bl.amount > 0 AND (
-                        bl.change_type IN ('充值','人工充值','三方充值')
+                        bl.change_type IN ('充值', '人工充值', '三方充值')
                         OR (
                             bl.change_type LIKE '%充值%'
                             AND bl.change_type NOT LIKE '%返现%'
                             AND bl.change_type NOT LIKE '%退%'
                         )
-                    ) THEN bl.amount ELSE 0 END) as deposit_amt,
+                    ) THEN bl.amount ELSE 0 END) AS deposit_amt,
                 SUM(CASE
-                    WHEN bl.change_type LIKE '%中奖%' THEN bl.amount ELSE 0 END) as win_amt
-            ")
-            ->groupBy('nu.reg_date', 'bl.member_id')
-            ->get();
+                    WHEN bl.change_type LIKE '%中奖%' THEN bl.amount ELSE 0 END) AS win_amt
+             FROM (
+                SELECT
+                    DATE(u.created_at) AS reg_date,
+                    COALESCE(NULLIF(u.member_id, ''), u.user_id) AS member_key
+                FROM {$users} u
+                WHERE u.created_at BETWEEN ? AND ?
+             ) nu
+             INNER JOIN {$logs} bl
+                ON bl.member_id COLLATE utf8mb4_general_ci = nu.member_key COLLATE utf8mb4_general_ci
+             WHERE DATE(bl.created_at) = nu.reg_date
+               AND bl.created_at BETWEEN ? AND ?
+             GROUP BY nu.reg_date, bl.member_id",
+            [$rangeStart, $rangeEnd, $rangeStart, $rangeEnd]
+        );
 
         $flowByDay = [];
         foreach ($memberFlow as $row) {