'ENABLE', // 2 代表广告已启用 3 => 'PAUSED', // 3 代表广告待审核等状态 // 其他状态可以继续添加 ]; /** * 获取广告系列列表 */ public static function getCampaignList($platformType, $customerIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null) { // 检查 customerIds 是否为空,直接返回空结构 if (empty($customerIds)) { return [ 'pagination' => [ 'startIndex' => 0, 'maxResults' => $pageSize, 'count' => 0, 'pageNo' => $page, 'pageSize' => $pageSize, 'pages' => 0, ], 'statistics' => [ ], 'data' => [], ]; } // 动态构建日期条件 $dateCondition = ''; if ($startDate && $endDate) { $dateCondition = "d.date BETWEEN '{$startDate}' AND '{$endDate}'"; } else { } // 基础查询:广告活动和日数据表联接 $query = BpsAdCampaign::alias('c') ->cache(false) // 强制不使用缓存 ->leftJoin('bps.bps_ads_insights d', "c.campaign_id = d.ad_campaign_id AND c.platform_type = d.platform AND {$dateCondition}") ->field('c.campaign_id, c.status as status, c.name, c.account_id, COALESCE(SUM(d.assisted_purchases), 0) as assisted_purchases, COALESCE(SUM(d.last_clicked_purchases), 0) as last_clicked_purchases, COALESCE(SUM(d.clicks), 0) as clicks, COALESCE(SUM(d.spend) / 1000000, 0) as spend, COALESCE(SUM(d.impressions), 0) as impressions, COALESCE(SUM(d.adds_to_cart), 0) as adds_to_cart, COALESCE(SUM(d.cost_per_atc), 0) as cost_per_atc, COALESCE(SUM(d.purchases), 0) as purchases, COALESCE(SUM(d.purchases_value), 0) as purchases_value, COALESCE(SUM(d.revenue), 0) as revenue, COALESCE(SUM(d.total_cost), 0) as total_cost, -1 as conversion_rate, -1 as roas, -1 as ctr,-1 as net_profit,-1 as net_profit_margin,-1 as net_profit_on_ad_spend') ->group('c.campaign_id, c.status, c.account_id, c.name') ->where('c.account_id', 'in', $customerIds); // 添加 customerIds 条件 // 添加关键字过滤条件 $query->where(function ($query) use ($keyword, $platformType) { if ($keyword) { $query->where('c.campaign_name', 'like', '%' . $keyword . '%'); } if ($platformType) { $platformType = (int)$platformType; $query->where('c.platform_type', '=', $platformType); } }); // 获取所有符合条件的数据(不分页) $allCampaigns = $query->select()->toArray(); $total_spend = array_sum(array_column($allCampaigns, 'spend')); $total_cost = array_sum(array_column($allCampaigns, 'total_cost')); $total_impressions = array_sum(array_column($allCampaigns, 'impressions')); $total_clicks = array_sum(array_column($allCampaigns, 'clicks')); $total_purchases_value = array_sum(array_column($allCampaigns, 'purchases_value')); // 汇总统计数据 $statistics = [ 'assisted_purchases' => array_sum(array_column($allCampaigns, 'assisted_purchases')), 'last_clicked_purchases' => array_sum(array_column($allCampaigns, 'last_clicked_purchases')), 'roas' => $total_spend === 0 ? '-' : round($total_purchases_value / $total_spend, 2), 'amount_spend' => '$' . number_format($total_spend, 2) ?: '$0.00', // 格式化支出 'clicks' => $total_clicks, 'impressions' => $total_impressions, 'adds_to_cart' => array_sum(array_column($allCampaigns, 'adds_to_cart')), 'cost_per_atc' => array_sum(array_column($allCampaigns, 'cost_per_atc')), 'purchases' => array_sum(array_column($allCampaigns, 'purchases')), 'purchases_value' => array_sum(array_column($allCampaigns, 'purchases_value')), 'revenue' => '$' . number_format(array_sum(array_column($allCampaigns, 'revenue')), 2) ?: '$0.00', // 格式化收入 'total_cost' => '$' . number_format($total_cost, 2) ?: '$0.00', // 格式化总成本 'conversion_rate' => '-', // 没有计算逻辑,保持为 '-' 'net_profit' => '-', // 没有计算 net_profit,保持为 '-' 'net_profit_margin' => '-', // 没有计算 net_profit_margin,保持为 '-' 'net_profit_on_ad_spend' => '-', // 没有计算 net_profit_on_ad_spend,保持为 '-' // 计算总的 CTR 'ctr' => ($total_impressions > 0) ? number_format(($total_clicks / $total_impressions) * 100, 2) . '%' : '-', // 格式化为百分比 ]; // 获取分页数据 $campaigns = $query->paginate($pageSize, false, ['page' => $page]); // 确保数据格式统一 $result = array_map(function ($item) { $ctr = $item['impressions'] > 0 ? number_format(($item['clicks'] / $item['impressions']) * 100, 2) . '%' : '-'; // 格式化为百分比 return [ 'id' => $item['campaign_id'], 'account_id' => $item['account_id'], // 映射为 customer_id 'name' => $item['name'] ?: '-', // 若 name 为空则显示 '-' 'status' => $item['status'], 'assisted_purchases' => $item['assisted_purchases'], 'last_clicked_purchases' => $item['last_clicked_purchases'], 'roas' => $item['spend'] == 0 ? '-' : round($item['purchases_value'] / $item['spend'], 2), 'spend' => '$' . number_format($item['spend'], 2), // 格式化支出 'impressions' => $item['impressions'], 'clicks' => $item['clicks'], 'ctr' => $ctr, // CTR 字段 'adds_to_cart' => $item['adds_to_cart'], 'cost_per_atc' => $item['cost_per_atc'], 'purchases' => $item['purchases'], 'purchases_value' => '$' . number_format($item['purchases_value'], 2), // 格式化购买金额 'revenue' => '$' . number_format($item['revenue'], 2), // 格式化收入 'total_cost' => '$' . number_format($item['total_cost'], 2), // 格式化总成本 'conversion_rate' => '-', // 没有提供有效的计算,保持为 '-' 'net_profit' => '-', // 没有提供 net_profit 计算,保持为 '-' 'net_profit_margin' => '-', // 没有提供 net_profit_margin 计算,保持为 '-' 'net_profit_on_ad_spend' => '-', // 没有提供 net_profit_on_ad_spend 计算,保持为 '-' ]; }, $campaigns->items()); // Pagination 数据 $pagination = [ 'startIndex' => ($page - 1) * $pageSize, 'maxResults' => $pageSize, 'count' => $campaigns->total(), 'pageNo' => $campaigns->currentPage(), 'pageSize' => $pageSize, 'pages' => $campaigns->lastPage(), ]; return [ 'pagination' => $pagination, 'statistics' => $statistics, 'data' => $result, ]; } /** * 获取广告组列表 */ public static function getAdsetList($platformType, $customerIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null) { // 检查 customerIds 是否为空,直接返回空结构 if (empty($customerIds)) { return [ 'pagination' => [ 'startIndex' => 0, 'maxResults' => $pageSize, 'count' => 0, 'pageNo' => $page, 'pageSize' => $pageSize, 'pages' => 0, ], 'statistics' => [ ], 'data' => [], ]; } // 动态构建日期条件 $dateCondition = ''; if ($startDate && $endDate) { $dateCondition = "d.date BETWEEN '{$startDate}' AND '{$endDate}'"; } // 基础查询:广告组和日数据表联接 $query = BpsAdSet::alias('s') ->cache(false) // 强制不使用缓存 ->leftJoin('bps.bps_ads_insights d', "s.ad_set_id = d.ad_set_id AND s.platform_type = d.platform AND {$dateCondition}") ->field('s.ad_set_id, s.status as status, s.name, s.account_id, COALESCE(SUM(d.assisted_purchases), 0) as assisted_purchases, COALESCE(SUM(d.last_clicked_purchases), 0) as last_clicked_purchases, COALESCE(SUM(d.clicks), 0) as clicks, COALESCE(SUM(d.spend) / 1000000, 0) as spend, COALESCE(SUM(d.impressions), 0) as impressions, COALESCE(SUM(d.adds_to_cart), 0) as adds_to_cart, COALESCE(SUM(d.cost_per_atc), 0) as cost_per_atc, COALESCE(SUM(d.purchases), 0) as purchases, COALESCE(SUM(d.purchases_value), 0) as purchases_value, COALESCE(SUM(d.revenue), 0) as revenue, COALESCE(SUM(d.total_cost), 0) as total_cost, -1 as conversion_rate, -1 as roas, -1 as ctr,-1 as net_profit,-1 as net_profit_margin,-1 as net_profit_on_ad_spend') ->group('s.ad_set_id, s.status, s.account_id, s.name') ->where('s.account_id', 'in', $customerIds); // 添加 customerIds 条件 // 添加关键字过滤条件 $query->where(function ($query) use ($keyword, $platformType) { if ($keyword) { $query->where('s.name', 'like', '%' . $keyword . '%'); } if ($platformType) { $platformType = (int)$platformType; $query->where('s.platform_type', '=', $platformType); } }); // 获取所有符合条件的数据(不分页) $allAdsets = $query->select()->toArray(); $total_spend = array_sum(array_column($allAdsets, 'spend')); $total_cost = array_sum(array_column($allAdsets, 'total_cost')); $total_impressions = array_sum(array_column($allAdsets, 'impressions')); $total_clicks = array_sum(array_column($allAdsets, 'clicks')); $total_purchases_value = array_sum(array_column($allAdsets, 'purchases_value')); // 汇总统计数据 $statistics = [ 'assisted_purchases' => array_sum(array_column($allAdsets, 'assisted_purchases')), 'last_clicked_purchases' => array_sum(array_column($allAdsets, 'last_clicked_purchases')), 'roas' => $total_spend === 0 ? '-' : round($total_purchases_value / $total_spend, 2), 'amount_spend' => '$' . number_format($total_spend, 2) ?: '$0.00', // 格式化支出 'clicks' => $total_clicks, 'impressions' => array_sum(array_column($allAdsets, 'impressions')), 'adds_to_cart' => array_sum(array_column($allAdsets, 'adds_to_cart')), 'cost_per_atc' => array_sum(array_column($allAdsets, 'cost_per_atc')), 'purchases' => array_sum(array_column($allAdsets, 'purchases')), 'purchases_value' => array_sum(array_column($allAdsets, 'purchases_value')), 'revenue' => '$' . number_format(array_sum(array_column($allAdsets, 'revenue')), 2) ?: '$0.00', // 格式化收入 'total_cost' => '$' . number_format($total_cost, 2) ?: '$0.00', // 格式化总成本 'conversion_rate' => '-', // 没有计算逻辑,保持为 '-' 'net_profit' => '-', // 没有计算 net_profit,保持为 '-' 'net_profit_margin' => '-', // 没有计算 net_profit_margin,保持为 '-' 'net_profit_on_ad_spend' => '-', // 没有计算 net_profit_on_ad_spend,保持为 '-' // 计算总的 CTR 'ctr' => ($total_impressions > 0) ? number_format(($total_clicks / $total_impressions) * 100, 2) . '%' : '-', // 格式化为百分比 ]; // 获取分页数据 $adsets = $query->paginate($pageSize, false, ['page' => $page]); // 确保数据格式统一 $result = array_map(function ($item) { $ctr = $item['impressions'] > 0 ? number_format(($item['clicks'] / $item['impressions']) * 100, 2) . '%' : '-'; // 格式化为百分比 return [ 'id' => $item['ad_set_id'], 'account_id' => $item['account_id'], // 映射为 customer_id 'name' => $item['name'] ?: '-', // 若 name 为空则显示 '-' 'status' => $item['status'], 'assisted_purchases' => $item['assisted_purchases'], 'last_clicked_purchases' => $item['last_clicked_purchases'], 'roas' => $item['spend'] == 0 ? '-' : round($item['purchases_value'] / $item['spend'], 2), 'spend' => '$' . number_format($item['spend'], 2), // 格式化支出 'impressions' => $item['impressions'], 'clicks' => $item['clicks'], 'ctr' => $ctr, // CTR 字段 'adds_to_cart' => $item['adds_to_cart'], 'cost_per_atc' => $item['cost_per_atc'], 'purchases' => $item['purchases'], 'purchases_value' => '$' . number_format($item['purchases_value'], 2), // 格式化购买金额 'revenue' => '$' . number_format($item['revenue'], 2), // 格式化收入 'total_cost' => '$' . number_format($item['total_cost'], 2), // 格式化总成本 'conversion_rate' => '-', // 没有提供有效的计算,保持为 '-' 'net_profit' => '-', // 没有提供 net_profit 计算,保持为 '-' 'net_profit_margin' => '-', // 没有提供 net_profit_margin 计算,保持为 '-' 'net_profit_on_ad_spend' => '-', // 没有提供 net_profit_on_ad_spend 计算,保持为 '-' ]; }, $adsets->items()); // Pagination 数据 $pagination = [ 'startIndex' => ($page - 1) * $pageSize, 'maxResults' => $pageSize, 'count' => $adsets->total(), 'pageNo' => $adsets->currentPage(), 'pageSize' => $pageSize, 'pages' => $adsets->lastPage(), ]; return [ 'pagination' => $pagination, 'statistics' => $statistics, 'data' => $result, ]; } public static function getAdList($platformType, $customerIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null) { // 检查 customerIds 是否为空,直接返回空结构 if (empty($customerIds)) { return [ 'pagination' => [ 'startIndex' => 0, 'maxResults' => $pageSize, 'count' => 0, 'pageNo' => $page, 'pageSize' => $pageSize, 'pages' => 0, ], 'statistics' => [], 'data' => [], ]; } // 动态构建日期条件 $dateCondition = ''; if ($startDate && $endDate) { $dateCondition = "d.date BETWEEN '{$startDate}' AND '{$endDate}'"; } // 基础查询:广告和日数据表联接 $query = BpsAdAd::alias('a') ->cache(false) // 强制不使用缓存 ->leftJoin('bps.bps_ads_insights d', "a.ad_id = d.ad_id AND a.platform_type = d.platform AND {$dateCondition}") ->field('a.ad_id, a.status as status, a.name, a.account_id, COALESCE(SUM(d.assisted_purchases), 0) as assisted_purchases, COALESCE(SUM(d.last_clicked_purchases), 0) as last_clicked_purchases, COALESCE(SUM(d.clicks), 0) as clicks, COALESCE(SUM(d.spend) / 1000000, 0) as spend, COALESCE(SUM(d.impressions), 0) as impressions, COALESCE(SUM(d.adds_to_cart), 0) as adds_to_cart, COALESCE(SUM(d.cost_per_atc), 0) as cost_per_atc, COALESCE(SUM(d.purchases), 0) as purchases, COALESCE(SUM(d.purchases_value), 0) as purchases_value, COALESCE(SUM(d.revenue), 0) as revenue, COALESCE(SUM(d.total_cost), 0) as total_cost, -1 as conversion_rate, -1 as roas, -1 as ctr, -1 as net_profit, -1 as net_profit_margin, -1 as net_profit_on_ad_spend') ->group('a.ad_id, a.status, a.account_id, a.name') ->where('a.account_id', 'in', $customerIds); // 添加 customerIds 条件 // 添加关键字过滤条件 $query->where(function ($query) use ($keyword, $platformType) { if ($keyword) { $query->where('a.name', 'like', '%' . $keyword . '%'); } if ($platformType) { $platformType = (int)$platformType; $query->where('a.platform_type', '=', $platformType); } }); // 获取所有符合条件的数据(不分页) $allAds = $query->select()->toArray(); // 汇总统计数据 $total_spend = array_sum(array_column($allAds, 'spend')); $total_cost = array_sum(array_column($allAds, 'total_cost')); $total_impressions = array_sum(array_column($allAds, 'impressions')); $total_clicks = array_sum(array_column($allAds, 'clicks')); $total_purchases_value = array_sum(array_column($allAds, 'purchases_value')); $statistics = [ 'assisted_purchases' => array_sum(array_column($allAds, 'assisted_purchases')), 'last_clicked_purchases' => array_sum(array_column($allAds, 'last_clicked_purchases')), 'roas' => $total_spend === 0 ? '-' : round($total_purchases_value / $total_spend, 2), 'amount_spend' => '$' . number_format($total_spend, 2) ?: '$0.00', // 格式化支出 'clicks' => $total_clicks, 'impressions' => array_sum(array_column($allAds, 'impressions')), 'adds_to_cart' => array_sum(array_column($allAds, 'adds_to_cart')), 'cost_per_atc' => array_sum(array_column($allAds, 'cost_per_atc')), 'purchases' => array_sum(array_column($allAds, 'purchases')), 'purchases_value' => array_sum(array_column($allAds, 'purchases_value')), 'revenue' => '$' . number_format(array_sum(array_column($allAds, 'revenue')), 2) ?: '$0.00', // 格式化收入 'total_cost' => '$' . number_format($total_cost, 2) ?: '$0.00', // 格式化总成本 'conversion_rate' => '-', // 没有计算逻辑,保持为 '-' 'net_profit' => '-', // 没有计算 net_profit,保持为 '-' 'net_profit_margin' => '-', // 没有计算 net_profit_margin,保持为 '-' 'net_profit_on_ad_spend' => '-', // 没有计算 net_profit_on_ad_spend,保持为 '-' 'ctr' => ($total_impressions > 0) ? number_format(($total_clicks / $total_impressions) * 100, 2) . '%' : '-', // 格式化为百分比 ]; // 获取分页数据 $ads = $query->paginate($pageSize, false, ['page' => $page]); // 确保数据格式统一 $result = array_map(function ($item) { $ctr = $item['impressions'] > 0 ? number_format(($item['clicks'] / $item['impressions']) * 100, 2) . '%' : '-'; // 格式化为百分比 return [ 'id' => $item['ad_id'], 'account_id' => $item['account_id'], // 映射为 customer_id 'name' => $item['name'] ?: '-', // 若 name 为空则显示 '-' 'status' => $item['status'], 'assisted_purchases' => $item['assisted_purchases'], 'last_clicked_purchases' => $item['last_clicked_purchases'], 'roas' => $item['spend'] == 0 ? '-' : round($item['purchases_value'] / $item['spend'], 2), 'spend' => '$' . number_format($item['spend'], 2), // 格式化支出 'impressions' => $item['impressions'], 'clicks' => $item['clicks'], 'ctr' => $ctr, // CTR 字段 'adds_to_cart' => $item['adds_to_cart'], 'cost_per_atc' => $item['cost_per_atc'], 'purchases' => $item['purchases'], 'purchases_value' => '$' . number_format($item['purchases_value'], 2), // 格式化购买金额 'revenue' => '$' . number_format($item['revenue'], 2), // 格式化收入 'total_cost' => '$' . number_format($item['total_cost'], 2), // 格式化总成本 'conversion_rate' => '-', // 没有提供有效的计算,保持为 '-' 'net_profit' => '-', // 没有提供 net_profit 计算,保持为 '-' 'net_profit_margin' => '-', // 没有提供 net_profit_margin 计算,保持为 '-' 'net_profit_on_ad_spend' => '-', // 没有提供 net_profit_on_ad_spend 计算,保持为 '-' ]; }, $ads->items()); // Pagination 数据 $pagination = [ 'startIndex' => ($page - 1) * $pageSize, 'maxResults' => $pageSize, 'count' => $ads->total(), 'pageNo' => $ads->currentPage(), 'pageSize' => $pageSize, 'pages' => $ads->lastPage(), ]; return [ 'pagination' => $pagination, 'statistics' => $statistics, 'data' => $result, ]; } public static function getThirdUserList($platformType, $userIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null) { // 检查 userIds 是否为空,直接返回空结构 if (empty($userIds)) { return [ 'pagination' => [ 'startIndex' => 0, 'maxResults' => $pageSize, 'count' => 0, 'pageNo' => $page, 'pageSize' => $pageSize, 'pages' => 0, ], 'statistics' => [], 'data' => [], ]; } // dump($userIds); // 动态构建日期条件 $dateCondition = '1=1'; // 默认没有日期限制 if ($startDate && $endDate) { $dateCondition = "d.date BETWEEN '{$startDate}' AND '{$endDate}'"; } // u.user_id as third_user_id, u.third_type, u.facebook_user_id, // a.advertiser_id, a.advertiser_name, a.google_manager, a.google_test_account, // 基础查询:第三方用户和广告商数据表联接 $query = ThirdUser::alias('u') ->cache(false) // 强制不使用缓存 ->leftJoin('bps.bps_third_user_advertiser a', "u.id = a.doc_") ->field('u.id as user_id,u.third_type,a.advertiser_name, COALESCE(SUM(d.assisted_purchases), 0) as assisted_purchases, COALESCE(SUM(d.last_clicked_purchases), 0) as last_clicked_purchases, COALESCE(SUM(d.spend) / 1000000, 0) as spend, COALESCE(SUM(d.impressions), 0) as impressions, COALESCE(SUM(d.clicks), 0) as clicks, COALESCE(SUM(d.adds_to_cart), 0) as adds_to_cart, COALESCE(SUM(d.cost_per_atc), 0) as cost_per_atc, COALESCE(SUM(d.purchases), 0) as purchases, COALESCE(SUM(d.purchases_value), 0) as purchases_value, COALESCE(SUM(d.revenue), 0) as revenue, COALESCE(SUM(d.total_cost), 0) as total_cost') ->leftJoin('bps.bps_ads_insights d', "a.advertiser_id = d.account_id AND {$dateCondition}") ->where('u.id', 'in', $userIds); // 添加 userIds 条件 // 添加关键字过滤条件 $query->where(function ($query) use ($keyword, $platformType) { if ($keyword) { $query->where('a.advertiser_name', 'like', '%' . $keyword . '%'); } if ($platformType) { $query->where('d.platform', '=', $platformType); } }); // 添加 GROUP BY 子句 // $query->group('u.id, u.user_id, u.third_type, u.facebook_user_id, // a.advertiser_id, a.advertiser_name, a.google_manager, a.google_test_account'); $query->group('u.id,u.third_type,a.advertiser_name'); // 调试打印 SQL // 获取所有符合条件的数据(不分页) $allUsers = $query->select()->toArray(); // dump($query->getLastSql()); // // dump($allUsers); // 汇总统计数据 $total_spend = array_sum(array_column($allUsers, 'spend')); $total_impressions = array_sum(array_column($allUsers, 'impressions')); $total_clicks = array_sum(array_column($allUsers, 'clicks')); $total_adds_to_cart = array_sum(array_column($allUsers, 'adds_to_cart')); $total_cost_per_atc = array_sum(array_column($allUsers, 'cost_per_atc')); $total_purchases = array_sum(array_column($allUsers, 'purchases')); $total_purchases_value = array_sum(array_column($allUsers, 'purchases_value')); $total_revenue = array_sum(array_column($allUsers, 'revenue')); $total_cost = array_sum(array_column($allUsers, 'total_cost')); // 计算 ROAS $roas = $total_spend === 0 ? '-' : round($total_purchases_value / $total_spend, 2); // 计算 CTR $ctr = $total_impressions > 0 ? number_format(($total_clicks / $total_impressions) * 100, 2) . '%' : '-'; // 汇总统计字段初始化 $statistics = [ 'assisted_purchases' => 0, 'last_clicked_purchases' => 0, 'roas' => $total_spend === 0 ? '-' : round($total_purchases_value / $total_spend, 2), 'amount_spend' => '$' . number_format($total_spend, 2) ?: '$0.00', // 格式化支出 'clicks' => $total_clicks, 'impressions' => $total_impressions, 'adds_to_cart' => $total_adds_to_cart, 'cost_per_atc' => $total_cost_per_atc, 'purchases' => $total_purchases, 'purchases_value' => '$' . number_format($total_purchases_value, 2) ?: '$0.00', // 格式化销售额$total_purchases_value, 'revenue' => '$' . number_format($total_revenue, 2) ?: '$0.00', // 格式化收入 'total_cost' => '$' . number_format($total_cost, 2) ?: '$0.00', // 格式化总成本 'conversion_rate' => '-', // 没有计算逻辑,保持为 '-' 'net_profit' => '-', // 没有提供 net_profit,保持为 '-' 'net_profit_margin' => '-', // 没有提供 net_profit_margin,保持为 '-' 'net_profit_on_ad_spend' => '-', // 没有提供 net_profit_on_ad_spend,保持为 '-' 'ctr' => $ctr, // CTR 字段 ]; // 获取分页数据 $users = $query->paginate($pageSize, false, ['page' => $page]); // 按照 third_user_id 聚合统计字段 $aggregatedUsers = []; // 遍历每个用户的统计数据 foreach ($users->items() as $item) { $thirdUserId = $item['user_id']; if (!isset($aggregatedUsers[$thirdUserId])) { $aggregatedUsers[$thirdUserId] = [ 'user_id' => $item['user_id'], 'third_type' => $item['third_type'], 'advertiser_name' => $item['advertiser_name'], 'assisted_purchases' => 0, 'last_clicked_purchases' => 0, 'roas' => 0, 'spend' => 0, 'impressions' => 0, 'clicks' => 0, 'adds_to_cart' => 0, 'cost_per_atc' => 0, 'purchases' => 0, 'purchases_value' => 0, 'revenue' => 0, 'total_cost' => 0, 'net_profit' => '-', // 没有提供 net_profit,保持为 '-' 'net_profit_margin' => '-', // 没有提供 net_profit_margin,保持为 '-' 'net_profit_on_ad_spend' => '-', // 没有提供 net_profit_on_ad_spend,保持为 '-' ]; } // 汇总统计 $aggregatedUsers[$thirdUserId]['spend'] += $item['spend']; $aggregatedUsers[$thirdUserId]['impressions'] += $item['impressions']; $aggregatedUsers[$thirdUserId]['clicks'] += $item['clicks']; $aggregatedUsers[$thirdUserId]['adds_to_cart'] += $item['adds_to_cart']; $aggregatedUsers[$thirdUserId]['cost_per_atc'] += $item['cost_per_atc']; $aggregatedUsers[$thirdUserId]['purchases'] += $item['purchases']; $aggregatedUsers[$thirdUserId]['purchases_value'] += $item['purchases_value']; $aggregatedUsers[$thirdUserId]['revenue'] += $item['revenue']; $aggregatedUsers[$thirdUserId]['total_cost'] += $item['total_cost']; $aggregatedUsers[$thirdUserId]['assisted_purchases'] += $item['assisted_purchases']; $aggregatedUsers[$thirdUserId]['last_clicked_purchases'] += $item['last_clicked_purchases']; } // 计算统计口径字段:ROAS, CTR等 foreach ($aggregatedUsers as $userId => $data) { $total_spend = $data['spend']; $total_purchases_value = $data['purchases_value']; $total_revenue = $data['revenue']; $total_cost = $data['total_cost']; $total_clicks = $data['clicks']; $total_impressions = $data['impressions']; // $total_adds_to_cart = $data['adds_to_cart']; // $total_cost_per_atc = $data['cost_per_atc']; // $total_purchases = $data['purchases']; // $total_assisted_purchases = $data['assisted_purchases']; // $total_last_clicked_purchases = $data['last_clicked_purchases']; // 计算 ROAS, CTR 和其他需要的字段 $aggregatedUsers[$userId]['roas'] = $total_spend === 0 ? '-' : round($total_purchases_value / $total_spend, 2); $aggregatedUsers[$userId]['amount_spend'] = '$' . number_format($total_spend, 2) ?: '$0.00'; $aggregatedUsers[$userId]['purchases_value'] = '$' . number_format($total_purchases_value, 2) ?: '$0.00'; $aggregatedUsers[$userId]['revenue'] = '$' . number_format($total_revenue, 2) ?: '$0.00'; $aggregatedUsers[$userId]['total_cost'] = '$' . number_format($total_cost, 2) ?: '$0.00'; $aggregatedUsers[$userId]['conversion_rate'] = $total_impressions === 0 ? '-' : round(($total_clicks / $total_impressions) * 100, 2) . '%'; $aggregatedUsers[$userId]['ctr'] = $total_impressions === 0 ? '-' : round(($total_clicks / $total_impressions) * 100, 2) . '%'; } // 最终分页信息 $pagination = [ 'startIndex' => ($page - 1) * $pageSize, 'maxResults' => $pageSize, 'count' => $users->total(), 'pageNo' => $page, 'pageSize' => $pageSize, 'pages' => ceil($users->total() / $pageSize), ]; return [ 'pagination' => $pagination, 'statistics' => $statistics, 'data' => $aggregatedUsers, ]; } /** * 获取广告资产报告 * * @param string $keyword 关键词(广告素材名称模糊搜索) * @param string $dateRange 日期范围:Today, Yesterday, Last Week, Last Month, Last Year * @param string|null $startDate 起始日期(可选) * @param string|null $endDate 结束日期(可选) * @param int $page 当前页码 * @param int $pageSize 每页数量 * @return array */ public function getAssetConversionData($customerIds, $page, $pageSize, $keyword, $dateRange, $startDate = null, $endDate = null) { $isSameMonth = true; // 判断是否跨月 $currentMonth = date('Y-m'); //一个月内的统计需要确定是什么月份。 if ($startDate && $endDate) { // 比较日期的年月是否相同,若不同则为跨月 $isSameMonth = date('Y-m', strtotime($startDate)) === date('Y-m', strtotime($endDate)); if ($isSameMonth) { $currentMonth = date('Y-m', strtotime($startDate)); } } // 1. 获取符合条件的 ad_id 列表,并且筛选 AssetRelation 的 date 字段 $adIdsQuery = AssetRelation::alias('r') ->leftJoin('bps.bps_google_ads_asset a', 'r.asset_id = a.asset_id') // 关联资产表 ->where(function ($query) use ($keyword) { if ($keyword) { $query->where('a.asset_name', 'like', '%' . $keyword . '%'); // 关键词模糊匹配 } }); // 如果提供了 customerIds,增加查询条件 if (!empty($customerIds)) { $adIdsQuery->whereIn('a.customer_id', $customerIds); // 添加 customer_id 的查询约束 } else { return [ 'data' => [], 'chat_1_data' => [], // 返回按月汇总的 chat_data 'total' => 0, 'statistics' => [], 'pagination' => [ 'startIndex' => 0, 'maxResults' => $pageSize, 'count' => 0, 'pageNo' => 1, 'pageSize' => $pageSize, 'pages' => 1 ] ]; } // 日期范围处理,筛选 AssetRelation 的 date 字段 if ($startDate && $endDate) { $adIdsQuery->whereBetween('r.date', [$startDate, $endDate]); } else { switch ($dateRange) { case 'Today': $adIdsQuery->where('r.date', '=', date('Y-m-d')); $currentMonth = date('Y-m'); $isSameMonth = true; break; case 'Yesterday': $adIdsQuery->where('r.date', '=', date('Y-m-d', strtotime('-1 day'))); $currentMonth = date('Y-m', strtotime('-1 day')); $isSameMonth = true; break; case 'Last Week': $adIdsQuery->where('r.date', '>=', date('Y-m-d', strtotime('-1 week'))); // 比较日期的年月是否相同,若不同则为跨月 $isSameMonth = date('Y-m', strtotime('-1 week')) === date('Y-m'); break; case 'Last Month': $adIdsQuery->where('r.date', '>=', date('Y-m-d', strtotime('-1 month'))); $isSameMonth = false; break; case 'Last Year': $adIdsQuery->where('r.date', '>=', date('Y-m-d', strtotime('-1 year'))); $isSameMonth = false; break; default: break; } } // 获取唯一的 ad_id 列表 $adIds = $adIdsQuery->distinct(true)->column('r.ad_id'); // dump($adIds);return($adIds); // 2. 根据 ad_id 和日期范围去查询 DayData 表,按 ad_id 和日期聚合统计 $dayDataQuery = DayData::alias('d') // ->leftJoin('bps.bps_google_ads_campaign c', 'd.campaign_id = c.campaign_id') // 关联广告系列表(如果有) // ->leftJoin('bps.bps_google_ads_ad_group ag', 'd.ad_group_id = ag.ad_group_id') // 关联广告组表(如果有) ->whereIn('d.ad_id', $adIds) // 使用 ad_id 过滤 ->where(function ($query) use ($startDate, $endDate, $dateRange) { // 日期范围的筛选 if ($startDate && $endDate) { $query->whereBetween('d.date', [$startDate, $endDate]); } else { switch ($dateRange) { case 'Today': $query->where('d.date', '=', date('Y-m-d')); break; case 'Yesterday': $query->where('d.date', '=', date('Y-m-d', strtotime('-1 day'))); break; case 'Last Week': $query->where('d.date', '>=', date('Y-m-d', strtotime('-1 week'))); break; case 'Last Month': $query->where('d.date', '>=', date('Y-m-d', strtotime('-1 month'))); break; case 'Last Year': $query->where('d.date', '>=', date('Y-m-d', strtotime('-1 year'))); break; default: break; } } }); // 如果跨月,按月聚合;如果不跨月,按 ad_id 聚合 if (!$isSameMonth) { $dayDataQuery->group("d.month,d.ad_id,d.ad_name, d.ad_resource_name, d.ad_group_id, d.campaign_id, d.customer_id"); // 按月聚合 $dayDataQuery->field([ 'd.ad_id', 'd.month', // ThinkDb::raw("TO_CHAR(d.date, 'YYYY-MM') AS month"), // 格式化为 YYYY-MM 格式 ThinkDb::raw('SUM(d.cost_micros) / 1000000 AS total_spend'), ThinkDb::raw('SUM(d.conversions_value) AS total_conversions_value'), ThinkDb::raw('SUM(d.conversions) AS total_conversions'), ThinkDb::raw('SUM(d.impressions) AS total_impressions'), ThinkDb::raw('SUM(d.clicks) AS total_clicks') ]); } else { $dayDataQuery->group('d.ad_id,d.ad_name, d.ad_resource_name, d.ad_group_id, d.campaign_id, d.customer_id'); // 按 ad_id 聚合 $dayDataQuery->field([ 'd.ad_id', ThinkDb::raw('SUM(d.cost_micros) / 1000000 AS total_spend'), ThinkDb::raw('SUM(d.conversions_value) AS total_conversions_value'), ThinkDb::raw('SUM(d.conversions) AS total_conversions'), ThinkDb::raw('SUM(d.impressions) AS total_impressions'), ThinkDb::raw('SUM(d.clicks) AS total_clicks') ]); } // 获取聚合数据,不需要再传递字段给 select() $aggregatedData = $dayDataQuery->select(); // dump($aggregatedData);return($aggregatedData); // 3. 获取与 ad_id 关联的 asset_id 以及相关数据 $assetRelationsQuery = AssetRelation::whereIn('ad_id', $adIds) ->whereBetween('date', [$startDate, $endDate]) // 加上 AssetRelation 的 date 过滤 ->field(['asset_id', 'ad_id'])->select(); // dump($assetRelationsQuery);return($assetRelationsQuery); // 4. 汇总每个 asset_id 下的所有 ad_id 的聚合数据 $assetSummaryData = []; foreach ($assetRelationsQuery as $assetRelation) { // 从聚合数据中找到当前 ad_id 的相关数据 // $adStats = $aggregatedData->where('ad_id', $assetRelation->ad_id)->first(); // 获取该 ad_id 的所有聚合数据(可能有多条记录) $adStatsCollection = $aggregatedData->where('ad_id', $assetRelation->ad_id); // dump($adStatsCollection);return($adStatsCollection); if (!$adStatsCollection->isEmpty()) { // 如果该 ad_id 有对应的聚合数据,初始化资产汇总数据 if (!isset($assetSummaryData[$assetRelation->asset_id])) { $assetSummaryData[$assetRelation->asset_id] = [ 'asset_id' => $assetRelation->asset_id, 'asset_name' => '-', // 获取 asset_name 'asset_type' => 0, // 获取 asset_type 'asset_url' => '-', // 获取 asset_url 'total_spend' => 0, 'total_conversions_value' => 0, 'total_conversions' => 0, 'total_impressions' => 0, 'ad_count' => 0, 'monthly_data' => [], // 按月存储数据 ]; } // 遍历该 ad_id 所有的统计数据 foreach ($adStatsCollection as $adStats) { // 获取当前月份 if ($isSameMonth) { $month = $currentMonth; // 格式化为 YYYY-MM } else { $month = $adStats->month; // 格式化日期为 'YYYY-MM' } // 获取 asset 相关信息,通过模型查询 Asset $asset = Asset::find($assetRelation->asset_id); // 根据 asset_id 查找对应的 Asset 数据 // 累加该 ad_id 的统计数据到对应的 asset_id 汇总 $assetSummaryData[$assetRelation->asset_id]['asset_name'] = $asset->asset_name; $assetSummaryData[$assetRelation->asset_id]['asset_type'] = $asset->asset_type; $assetSummaryData[$assetRelation->asset_id]['asset_url'] = $asset->asset_url; $assetSummaryData[$assetRelation->asset_id]['total_spend'] += $adStats->total_spend; $assetSummaryData[$assetRelation->asset_id]['total_conversions_value'] += $adStats->total_conversions_value; $assetSummaryData[$assetRelation->asset_id]['total_conversions'] += $adStats->total_conversions; $assetSummaryData[$assetRelation->asset_id]['total_impressions'] += $adStats->total_impressions; $assetSummaryData[$assetRelation->asset_id]['ad'][] = $adStats->ad_id; // 存储 ad_id下一步统计数量 // 按月分开存储每个月的 spend 和 ROAS if (!isset($assetSummaryData[$assetRelation->asset_id]['monthly_data'][$month])) { $assetSummaryData[$assetRelation->asset_id]['monthly_data'][$month] = [ 'month' => $month, 'spend' => 0, 'conversions_value' => 0, ]; } // 累加每个月的数据 $assetSummaryData[$assetRelation->asset_id]['monthly_data'][$month]['spend'] += $adStats->total_spend; $assetSummaryData[$assetRelation->asset_id]['monthly_data'][$month]['conversions_value'] += $adStats->total_conversions_value; // 避免除以零 } } } //return $assetSummaryData; // 5. 格式化输出数据 // 生成最终输出的数据 $resultData = []; $chat_data = []; $statistics = $this->initializeStatistics(); // Initialize statistics before processing foreach ($assetSummaryData as $assetId => $data) { // 计算 ROAS $roas = $data['total_spend'] ? ($data['total_conversions_value'] / $data['total_spend']) : 0; // 合并月度数据到总数据 $resultData[] = [ 'creative_id' => $assetId, 'creative' => $data['asset_name'], 'creative_type' => $data['asset_type'], 'creative_url' => $data['asset_url'], 'spend' => '$' . number_format($data['total_spend'], 2), 'purchase_value' => '-', 'roas' => number_format($roas, 2) . 'X', 'cpa' => '-', 'cpc_link_click' => '-', 'cpm' => '-', 'cpc_all' => '-', 'aov' => '-', 'click_to_atc_ratio' => '-', 'atc_to_purchase_ratio' => '-', 'purchases' => '-', 'first_frame_retention' => '-', 'thumbstop' => '-', 'ctr_outbound' => '-', 'click_to_purchase' => '-', 'ctr_all' => '-', 'video_plays_25_rate' => '-', 'video_plays_50_rate' => '-', 'video_plays_75_rate' => '-', 'video_plays_100_rate' => '-', 'hold_rate' => '-', 'total_conversions_value' => '$' . number_format($data['total_conversions_value'], 2), 'total_conversions' => $data['total_conversions'], 'total_impressions' => $data['total_impressions'], 'ad_count' => count($data['ad']), // 'monthly_data' => $data['monthly_data'], // 合并月度数据 ]; // 计算每个月的汇总数据,用于 chat_data foreach ($data['monthly_data'] as $month => $monthlyData) { // 如果 chat_data 中已有该月的数据,则累加 if (!isset($chat_data[$month])) { $chat_data[$month] = [ 'month' => $month, 'total_spend' => 0, 'total_conversions_value' => 0, 'roas' => 0, ]; } // 累加该月的 spend 和 conversions_value $chat_data[$month]['total_spend'] += $monthlyData['spend']; $chat_data[$month]['total_conversions_value'] += $monthlyData['conversions_value']; // Aggregate statistics for overall summary $statistics['spend'] += $monthlyData['spend']; $statistics['conversions_value'] += $monthlyData['conversions_value']; } } // 计算每个月的总 ROAS,ROAS = 总的转换值 / 总的支出 foreach ($chat_data as $month => $data) { // 计算 ROAS $totalSpend = $data['total_spend']; $totalConversionsValue = $data['total_conversions_value']; // 如果有支出数据,计算 ROAS $chat_data[$month]['roas'] = $totalSpend ? ($totalConversionsValue / $totalSpend) : 0; // 格式化 ROAS 为倍数 $chat_data[$month]['roas'] = round($chat_data[$month]['roas'], 2); } // 计算整体的 ROAS $statistics['spend'] = '$' . number_format($statistics['spend'], 2); $statistics['roas'] = $statistics['spend'] > 0 ? ($statistics['conversions_value'] / $statistics['spend']) : 0; // 返回分页数据 $totalItems = count($assetSummaryData); $totalPages = ceil($totalItems / $pageSize); $startIndex = ($page - 1) * $pageSize; // 截取返回的数据 // $pagedData = array_slice($assetSummaryData, $startIndex, $pageSize); $resultDataPaginated = array_slice($resultData, ($page - 1) * $pageSize, $pageSize); return [ 'pagination' => [ 'startIndex' => $startIndex, 'maxResults' => $pageSize, 'count' => $totalItems, 'pageNo' => $page, 'pageSize' => $pageSize, 'pages' => $totalPages ], 'chat_1_data' => array_values($chat_data), // 返回按月汇总的 chat_data 'data' => $resultDataPaginated, 'statistics' => $statistics ]; } /** * 初始化统计数据 */ private function initializeStatistics() { return [ 'conversions_value' => 0, 'spend' => 0, 'purchase_value' => '-', // 可根据需求进一步计算 'roas' => 0, // 可以根据需要计算总体 ROAS 'cpa' => '-', 'cpc_link_click' => '-', 'cpm' => '-', 'cpc_all' => '-', 'aov' => '-', 'click_to_atc_ratio' => '-', 'atc_to_purchase_ratio' => '-', 'purchases' => '-', 'first_frame_retention' => '-', 'thumbstop' => '-', 'ctr_outbound' => '-', 'click_to_purchase' => '-', 'ctr_all' => '-', 'video_plays_25_rate' => '-', 'video_plays_50_rate' => '-', 'video_plays_75_rate' => '-', 'video_plays_100_rate' => '-', 'hold_rate' => '-' // Add other stats as necessary ]; } }