diff --git a/app/service/AdsInsightService.php b/app/service/AdsInsightService.php index e56f026..8e24687 100644 --- a/app/service/AdsInsightService.php +++ b/app/service/AdsInsightService.php @@ -1826,10 +1826,11 @@ class AdsInsightService ThinkDb::raw('COALESCE(SUM(i.link_clicks), 0) AS total_link_clicks'), ThinkDb::raw('COALESCE(SUM(i.adds_to_cart), 0) AS total_adds_to_cart'), ThinkDb::raw('COALESCE(SUM(i.outbound_clicks), 0) AS total_outbound_clicks'), - ThinkDb::raw('COALESCE(SUM(i.video_25),0) AS video_plays_25_rate'), - ThinkDb::raw('COALESCE(SUM(i.video_50),0) AS video_plays_50_rate'), - ThinkDb::raw('COALESCE(SUM(i.video_75),0) AS video_plays_75_rate'), - ThinkDb::raw('COALESCE(SUM(i.video_100),0) AS video_plays_100_rate'), + ThinkDb::raw('COALESCE(SUM(i.video_25),0) AS video_25'), + ThinkDb::raw('COALESCE(SUM(i.video_50),0) AS video_50'), + ThinkDb::raw('COALESCE(SUM(i.video_75),0) AS video_75'), + ThinkDb::raw('COALESCE(SUM(i.video_100),0) AS video_100'), + ThinkDb::raw('COALESCE(SUM(i.video_play),0) AS video_plays'), ThinkDb::raw('-1 AS hold_rate') ]); @@ -1881,10 +1882,15 @@ class AdsInsightService 'ctr_outbound' => '-', 'click_to_purchase' => '-', 'ctr_all' => '-', - 'video_plays_25_rate' => 0, - 'video_plays_50_rate' => 0, - 'video_plays_75_rate' => 0, - 'video_plays_100_rate' => 0, + 'video_25' => 0, + 'video_50' => 0, + 'video_75' => 0, + 'video_100' => 0, + 'video_plays' => 0, + 'video_plays_25_rate' => '-', + 'video_plays_50_rate' => '-', + 'video_plays_75_rate' => '-', + 'video_plays_100_rate' => '-', 'hold_rate' => '-', 'total_conversions_value' => 0, 'total_conversions' => 0, @@ -1899,19 +1905,20 @@ class AdsInsightService } // 更新该 creative_id 的统计数据 - $creativeSummaryData[$creativeId]['spend'] += $creativeData['total_spend']; - $creativeSummaryData[$creativeId]['purchases_value'] += $creativeData['total_purchases_value']; - $creativeSummaryData[$creativeId]['purchases'] += $creativeData['total_purchases']; - $creativeSummaryData[$creativeId]['impressions'] += $creativeData['total_impressions']; - $creativeSummaryData[$creativeId]['clicks'] += $creativeData['total_clicks']; - $creativeSummaryData[$creativeId]['link_clicks'] += $creativeData['total_link_clicks']; - $creativeSummaryData[$creativeId]['outbound_clicks'] += $creativeData['total_outbound_clicks']; - $creativeSummaryData[$creativeId]['adds_to_cart'] += $creativeData['total_adds_to_cart']; - $creativeSummaryData[$creativeId]['revenue'] += $creativeData['total_revenue']; - $creativeSummaryData[$creativeId]['video_plays_25_rate'] += $creativeData['video_plays_25_rate']; - $creativeSummaryData[$creativeId]['video_plays_50_rate'] += $creativeData['video_plays_50_rate']; - $creativeSummaryData[$creativeId]['video_plays_75_rate'] += $creativeData['video_plays_75_rate']; - $creativeSummaryData[$creativeId]['video_plays_100_rate'] += $creativeData['video_plays_100_rate']; + $creativeSummaryData[$creativeId]['spend'] += $creativeData['total_spend']; + $creativeSummaryData[$creativeId]['purchases_value'] += $creativeData['total_purchases_value']; + $creativeSummaryData[$creativeId]['purchases'] += $creativeData['total_purchases']; + $creativeSummaryData[$creativeId]['impressions'] += $creativeData['total_impressions']; + $creativeSummaryData[$creativeId]['clicks'] += $creativeData['total_clicks']; + $creativeSummaryData[$creativeId]['link_clicks'] += $creativeData['total_link_clicks']; + $creativeSummaryData[$creativeId]['outbound_clicks'] += $creativeData['total_outbound_clicks']; + $creativeSummaryData[$creativeId]['adds_to_cart'] += $creativeData['total_adds_to_cart']; + $creativeSummaryData[$creativeId]['revenue'] += $creativeData['total_revenue']; + $creativeSummaryData[$creativeId]['video_25'] += $creativeData['video_25']; + $creativeSummaryData[$creativeId]['video_50'] += $creativeData['video_50']; + $creativeSummaryData[$creativeId]['video_75'] += $creativeData['video_75']; + $creativeSummaryData[$creativeId]['video_100'] += $creativeData['video_100']; + $creativeSummaryData[$creativeId]['video_plays'] += $creativeData['video_plays']; // 填充广告计数 // $creativeSummaryData[$creativeData->creative_id]['ad_count'] = rand(10, 200); // 每个 creative_id 对应一个广告 } @@ -1927,6 +1934,11 @@ class AdsInsightService $statisticsData['outbound_clicks'] = array_sum(array_column($creativeSummaryData, 'outbound_clicks')); $statisticsData['adds_to_cart'] = array_sum(array_column($creativeSummaryData, 'adds_to_cart')); $statisticsData['revenue'] = array_sum(array_column($creativeSummaryData, 'revenue')); + $statisticsData['video_25'] = array_sum(array_column($creativeSummaryData, 'video_25')); + $statisticsData['video_50'] = array_sum(array_column($creativeSummaryData, 'video_50')); + $statisticsData['video_75'] = array_sum(array_column($creativeSummaryData, 'video_75')); + $statisticsData['video_100'] = array_sum(array_column($creativeSummaryData, 'video_100')); + $statisticsData['video_plays'] = array_sum(array_column($creativeSummaryData, 'video_plays')); // 汇总统计数据 $statistics = [ 'spend' => '$' . number_format($statisticsData['spend'], 2), // 格式化金额 @@ -1940,16 +1952,16 @@ class AdsInsightService 'click_to_atc_ratio' => ($statisticsData['clicks'] > 0) ? number_format(($statisticsData['adds_to_cart'] / $statisticsData['clicks']) * 100, 2) . '%' : '-', 'atc_to_purchase_ratio' => ($statisticsData['adds_to_cart'] > 0) ? number_format(($statisticsData['purchases'] / $statisticsData['adds_to_cart']) * 100, 2) . '%' : '-', 'purchases' => $statisticsData['purchases'], - 'first_frame_retention' => '-', - 'thumbstop' => '-', + 'first_frame_retention' => self::calculateFirstFrameRetention($statisticsData['impressions'], $statisticsData['video_plays'], $statisticsData['video_25']), + 'thumbstop' => self::calculateThumbstop($statisticsData['impressions'], $statisticsData['video_plays'], $statisticsData['video_25']), 'ctr_outbound' => ($statisticsData['impressions'] > 0) ? number_format(($statisticsData['outbound_clicks'] / $statisticsData['impressions']) * 100, 2) . '%' : '-', // 格式化为百分比 'click_to_purchase' => ($statisticsData['purchases'] > 0) ? number_format(($statisticsData['outbound_clicks'] / $statisticsData['purchases']) * 100, 2) . '%' : '-', 'ctr_all' => ($statisticsData['impressions'] > 0) ? number_format(($statisticsData['clicks'] / $statisticsData['impressions']) * 100, 2) . '%' : '-', // 格式化为百分比 - 'video_plays_25_rate' => array_sum(array_column($creativeSummaryData, 'video_plays_25_rate')), - 'video_plays_50_rate' => array_sum(array_column($creativeSummaryData, 'video_plays_50_rate')), - 'video_plays_75_rate' => array_sum(array_column($creativeSummaryData, 'video_plays_75_rate')), - 'video_plays_100_rate' => array_sum(array_column($creativeSummaryData, 'video_plays_100_rate')), - 'hold_rate' => '-',// 格式化百分比 + 'video_plays_25_rate' => ($statisticsData['video_plays'] > 0) ? number_format(($statisticsData['video_plays_25_rate'] / $statisticsData['video_plays']) * 100, 2) . '%' : '-', + 'video_plays_50_rate' => ($statisticsData['video_plays'] > 0) ? number_format(($statisticsData['video_plays_25_rate'] / $statisticsData['video_plays']) * 100, 2) . '%' : '-', + 'video_plays_75_rate' => ($statisticsData['video_plays'] > 0) ? number_format(($statisticsData['video_plays_25_rate'] / $statisticsData['video_plays']) * 100, 2) . '%' : '-', + 'video_plays_100_rate' => ($statisticsData['video_plays'] > 0) ? number_format(($statisticsData['video_plays_25_rate'] / $statisticsData['video_plays']) * 100, 2) . '%' : '-', + 'hold_rate' => self::calculateHoldRate($statisticsData['video_25'], $statisticsData['video_50'], $statisticsData['video_75'], $statisticsData['video_100']),// 格式化百分比 ]; // 获取每个 creative_id 对应的广告数量 @@ -2010,18 +2022,17 @@ class AdsInsightService 'click_to_atc_ratio' => ($item['clicks'] > 0) ? number_format(($item['adds_to_cart'] / $item['clicks']) * 100, 2) . '%' : '-', 'atc_to_purchase_ratio' => ($item['adds_to_cart'] > 0) ? number_format(($item['purchases'] / $item['adds_to_cart']) * 100, 2) . '%' : '-', 'purchases' => $item['purchases'], - 'first_frame_retention' => '-', - 'thumbstop' => '-', + 'first_frame_retention' => self::calculateFirstFrameRetention($item['impressions'], $item['video_plays'], $item['video_25']), + 'thumbstop' => self::calculateThumbstop($item['impressions'], $item['video_plays'], $item['video_25']), 'ctr_outbound' => ($item['impressions'] > 0) ? number_format(($item['outbound_clicks'] / $item['impressions']) * 100, 2) . '%' : '-', // 格式化为百分比 'click_to_purchase' => ($item['purchases'] > 0) ? number_format(($item['outbound_clicks'] / $item['purchases']) * 100, 2) . '%' : '-', 'ctr_all' => ($item['impressions'] > 0) ? number_format(($item['clicks'] / $item['impressions']) * 100, 2) . '%' : '-', 'total_conversions_value' => '$' . number_format($item['purchases_value'], 2), //准备删除 'impressions' => $item['impressions'], - 'video_plays_25_rate' => $item['video_plays_25_rate'], - 'video_plays_50_rate' => $item['video_plays_50_rate'], - 'video_plays_75_rate' => $item['video_plays_75_rate'], - 'video_plays_100_rate' => $item['video_plays_100_rate'], - 'hold_rate' => '-', + 'video_plays_25_rate' => ($item['video_plays'] > 0) ? number_format($item['video_25'] / $item['video_plays'], 2). '%' : '-', + 'video_plays_50_rate' => ($item['video_plays'] > 0) ? number_format($item['video_50'] / $item['video_plays'], 2). '%' : '-', + 'video_plays_75_rate' => ($item['video_plays'] > 0) ? number_format($item['video_75'] / $item['video_plays'], 2). '%' : '-', + 'hold_rate' => self::calculateHoldRate($item['video_25'], $item['video_50'], $item['video_75'], $item['video_100']), 'ad_count' => $item['ad_count'], // 添加更多的格式化字段 ]; @@ -2044,6 +2055,54 @@ class AdsInsightService ]; } + public static function calculateFirstFrameRetention($impressions, $video_play, $video_25) + { + // 如果 impressions 为 0 或 NULL,直接返回 0 + if ($impressions == 0 || $video_play == 0) { + return '-'; + } + + // 处理 NULL 值,用 0 替换 + $video_25 = $video_25 ?? 0; + + // 计算公式 + return number_format(($video_play / $impressions) * ($video_25 / $video_play) * 100, 2) . '%'; + } + + public static function calculateThumbstop($impressions, $video_play, $video_25) + { + // 如果 impressions 为 0 或 NULL,直接返回 0 + if ($impressions == 0) { + return '-'; + } + + // 处理 NULL 值,用 0 替换 + $video_play = $video_play ?? 0; + $video_25 = $video_25 ?? 0; + + // 计算公式 + return number_format((($video_play * 0.7) + ($video_25 * 0.3)) / $impressions * 100, 2) . '%'; + } + + public static function calculateHoldRate($video_25, $video_50, $video_75, $video_100) + { + // 如果 video_25 为 0 或 NULL,直接返回 0 + if ($video_25 == 0) { + return '-'; + } + + // 处理 NULL 值,用 0 替换 + $video_25 = $video_25 ?? 0; + $video_50 = $video_50 ?? 0; + $video_75 = $video_75 ?? 0; + $video_100 = $video_100 ?? 0; + + // 计算公式 + $numerator = $video_25 + $video_50 + $video_75 + $video_100; + $denominator = $video_25 * 4; + return number_format(($numerator / $denominator) * 100, 2) . '%'; + } + /** * 初始化统计数据