|
|
@@ -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) {
|