creative图表的日期排序、格式化
This commit is contained in:
parent
6a9d7337c5
commit
368c45f050
@ -13,6 +13,7 @@ use app\model\BpsAdAd;
|
||||
use app\model\ThirdUser;
|
||||
use app\model\Asset;
|
||||
use app\model\AssetRelation;
|
||||
use DateTime;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
||||
use think\db\exception\DbException;
|
||||
@ -103,7 +104,7 @@ class AdsInsightService
|
||||
$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),
|
||||
'roas' => $total_spend == 0 ? '-' : round($total_revenue / $total_spend, 2) . 'X',
|
||||
'amount_spend' => '$' . number_format($total_spend, 2) ?: '$0.00', // 格式化支出
|
||||
'clicks' => $total_clicks,
|
||||
'impressions' => $total_impressions,
|
||||
@ -127,7 +128,16 @@ class AdsInsightService
|
||||
|
||||
// 确保数据格式统一
|
||||
$result = array_map(function ($item) {
|
||||
$ctr = $item['impressions'] > 0 ? number_format(($item['clicks'] / $item['impressions']) * 100, 2) . '%' : '-'; // 格式化为百分比
|
||||
// CTR 的计算:点击率 = 点击数 / 展示数
|
||||
$ctr = $item['impressions'] > 0 ? number_format(($item['clicks'] / $item['impressions']) * 100, 2) . '%' : '-';
|
||||
// Conversion Rate 的计算:转换率 = 购买数 / 点击数
|
||||
$conversion_rate = $item['clicks'] > 0 ? round(($item['purchases'] / $item['clicks']) * 100, 2) . '%' : '-';
|
||||
// Net Profit 的计算:净利润 = 收入 - 总成本
|
||||
$net_profit = ($item['revenue'] - $item['total_cost']) >= 0 ? '+$' . number_format($item['revenue'] - $item['total_cost'], 2) : '-$' . number_format($item['revenue'] - $item['total_cost'], 2);
|
||||
// Net Profit Margin 的计算:净利润率 = 净利润 / 收入
|
||||
$net_profit_margin = $item['revenue'] > 0 ? round(($item['revenue'] - $item['total_cost']) / $item['revenue'], 2) * 100 . '%' : '-';
|
||||
// Net Profit on Ad Spend 的计算:广告支出净利润 = (收入 - 总成本) / 广告支出
|
||||
$net_profit_on_ad_spend = $item['spend'] > 0 ? round(($item['revenue'] - $item['total_cost']) / $item['spend'], 2) : '-';
|
||||
return [
|
||||
'id' => $item['campaign_id'],
|
||||
'platform_type' => $item['platform_type'],
|
||||
@ -136,7 +146,7 @@ class AdsInsightService
|
||||
'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),
|
||||
'roas' => $item['spend'] == 0 ? '-' : round($item['revenue'] / $item['spend'], 2) . 'X',
|
||||
'spend' => '$' . number_format($item['spend'], 2), // 格式化支出
|
||||
'impressions' => $item['impressions'],
|
||||
'clicks' => $item['clicks'],
|
||||
@ -148,10 +158,10 @@ class AdsInsightService
|
||||
'cost_per_purchase' => $item['purchases'] > 0 ? '$' . number_format(($item['spend'] / $item['purchases']), 2) : '$0.00',
|
||||
'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 计算,保持为 '-'
|
||||
'conversion_rate' => $conversion_rate,
|
||||
'net_profit' => $net_profit,
|
||||
'net_profit_margin' => $net_profit_margin,
|
||||
'net_profit_on_ad_spend' => $net_profit_on_ad_spend,
|
||||
];
|
||||
}, $campaigns->items());
|
||||
|
||||
@ -243,6 +253,7 @@ class AdsInsightService
|
||||
$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'));
|
||||
$total_revenue = array_sum(array_column($allAdsets, 'revenue'));
|
||||
$total_purchases = array_sum(array_column($allAdsets, 'purchases'));
|
||||
$cost_per_purchase = $total_purchases == 0 ? 0 : round($total_spend / $total_purchases, 2);
|
||||
|
||||
@ -250,7 +261,7 @@ class AdsInsightService
|
||||
$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),
|
||||
'roas' => $total_spend == 0 ? '-' : round($total_revenue / $total_spend, 2) . 'X',
|
||||
'amount_spend' => '$' . number_format($total_spend, 2) ?: '$0.00', // 格式化支出
|
||||
'clicks' => $total_clicks,
|
||||
'impressions' => array_sum(array_column($allAdsets, 'impressions')),
|
||||
@ -261,10 +272,10 @@ class AdsInsightService
|
||||
'cost_per_purchase' => '$' . number_format($cost_per_purchase, 2) ?: '$0.00',
|
||||
'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,保持为 '-'
|
||||
'conversion_rate' => $total_clicks == 0 ? '-' : round(($total_purchases / $total_clicks) * 100, 2) . '%', // 转换率
|
||||
'net_profit' => ($total_revenue - $total_cost) >= 0 ? '+$' . number_format($total_revenue - $total_cost, 2) : '-$' . number_format($total_revenue - $total_cost, 2), // 净利润
|
||||
'net_profit_margin' => $total_revenue == 0 ? '-' : round(($total_revenue - $total_cost) / $total_revenue, 2) * 100 . '%', // 净利润率
|
||||
'net_profit_on_ad_spend' => $total_spend == 0 ? '-' : round(($total_revenue - $total_cost) / $total_spend, 2), // 广告支出净利润
|
||||
// 计算总的 CTR
|
||||
'ctr' => ($total_impressions > 0) ? number_format(($total_clicks / $total_impressions) * 100, 2) . '%' : '-', // 格式化为百分比
|
||||
];
|
||||
@ -274,7 +285,16 @@ class AdsInsightService
|
||||
|
||||
// 确保数据格式统一
|
||||
$result = array_map(function ($item) {
|
||||
$ctr = $item['impressions'] > 0 ? number_format(($item['clicks'] / $item['impressions']) * 100, 2) . '%' : '-'; // 格式化为百分比
|
||||
// CTR 的计算:点击率 = 点击数 / 展示数
|
||||
$ctr = $item['impressions'] > 0 ? number_format(($item['clicks'] / $item['impressions']) * 100, 2) . '%' : '-';
|
||||
// Conversion Rate 的计算:转换率 = 购买数 / 点击数
|
||||
$conversion_rate = $item['clicks'] > 0 ? round(($item['purchases'] / $item['clicks']) * 100, 2) . '%' : '-';
|
||||
// Net Profit 的计算:净利润 = 收入 - 总成本
|
||||
$net_profit = ($item['revenue'] - $item['total_cost']) >= 0 ? '+$' . number_format($item['revenue'] - $item['total_cost'], 2) : '-$' . number_format($item['revenue'] - $item['total_cost'], 2);
|
||||
// Net Profit Margin 的计算:净利润率 = 净利润 / 收入
|
||||
$net_profit_margin = $item['revenue'] > 0 ? round(($item['revenue'] - $item['total_cost']) / $item['revenue'], 2) * 100 . '%' : '-';
|
||||
// Net Profit on Ad Spend 的计算:广告支出净利润 = (收入 - 总成本) / 广告支出
|
||||
$net_profit_on_ad_spend = $item['spend'] > 0 ? round(($item['revenue'] - $item['total_cost']) / $item['spend'], 2) : '-';
|
||||
return [
|
||||
'id' => $item['ad_set_id'],
|
||||
'platform_type' => $item['platform_type'],
|
||||
@ -284,7 +304,7 @@ class AdsInsightService
|
||||
'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),
|
||||
'roas' => $item['spend'] == 0 ? '-' : round($item['purchases_value'] / $item['spend'], 2) . 'X',
|
||||
'spend' => '$' . number_format($item['spend'], 2), // 格式化支出
|
||||
'impressions' => $item['impressions'],
|
||||
'clicks' => $item['clicks'],
|
||||
@ -296,10 +316,10 @@ class AdsInsightService
|
||||
'cost_per_purchase' => $item['purchases'] > 0 ? '$' . number_format(($item['spend'] / $item['purchases']), 2) : '$0.00',
|
||||
'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 计算,保持为 '-'
|
||||
'conversion_rate' => $conversion_rate, // 没有提供有效的计算,保持为 '-'
|
||||
'net_profit' => $net_profit, // 没有提供 net_profit 计算,保持为 '-'
|
||||
'net_profit_margin' => $net_profit_margin, // 没有提供 net_profit_margin 计算,保持为 '-'
|
||||
'net_profit_on_ad_spend' => $net_profit_on_ad_spend, // 没有提供 net_profit_on_ad_spend 计算,保持为 '-'
|
||||
];
|
||||
}, $adsets->items());
|
||||
|
||||
@ -388,6 +408,7 @@ class AdsInsightService
|
||||
$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'));
|
||||
$total_revenue = array_sum(array_column($allAds, 'revenue'));
|
||||
$total_purchases = array_sum(array_column($allAds, 'purchases'));
|
||||
$cost_per_purchase = $total_purchases == 0 ? 0 : round($total_spend / $total_purchases, 2);
|
||||
|
||||
@ -405,10 +426,10 @@ class AdsInsightService
|
||||
'cost_per_purchase' => '$' . number_format($cost_per_purchase, 2) ?: '$0.00',
|
||||
'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,保持为 '-'
|
||||
'conversion_rate' => $total_clicks == 0 ? '-' : round(($total_purchases / $total_clicks) * 100, 2) . '%', // 转换率
|
||||
'net_profit' => ($total_revenue - $total_cost) >= 0 ? '+$' . number_format($total_revenue - $total_cost, 2) : '-$' . number_format($total_revenue - $total_cost, 2), // 净利润
|
||||
'net_profit_margin' => $total_revenue == 0 ? '-' : round(($total_revenue - $total_cost) / $total_revenue, 2) * 100 . '%', // 净利润率
|
||||
'net_profit_on_ad_spend' => $total_spend == 0 ? '-' : round(($total_revenue - $total_cost) / $total_spend, 2),
|
||||
'ctr' => ($total_impressions > 0) ? number_format(($total_clicks / $total_impressions) * 100, 2) . '%' : '-', // 格式化为百分比
|
||||
];
|
||||
|
||||
@ -669,9 +690,9 @@ class AdsInsightService
|
||||
// 1. 创建查询对象,初始化 BpsAdCreativeInsight 查询
|
||||
$creativeDataQuery = BpsAdCreativeInsight::alias('i')
|
||||
->join('bps.bps_ads_creative c', 'i.creative_id = c.creative_id', 'LEFT'); // 联接 bps_ads_creative 表
|
||||
if ($platformType != 0) {
|
||||
$creativeDataQuery->where('i.platform', $platformType); // 只有 platformType 不为 0 时才添加筛选
|
||||
}
|
||||
if ($platformType != 0) {
|
||||
$creativeDataQuery->where('i.platform', $platformType); // 只有 platformType 不为 0 时才添加筛选
|
||||
}
|
||||
|
||||
// 2. 日期范围筛选
|
||||
if ($startDate && $endDate) {
|
||||
@ -702,11 +723,12 @@ class AdsInsightService
|
||||
}
|
||||
|
||||
// 5. 数据聚合(按 creative_id 和其他字段)
|
||||
$creativeDataQuery->group('i.creative_id, i.platform, i.account_id, c.name, c.url, c.thumbnail_url') // 按需要的字段分组
|
||||
$creativeDataQuery->group('i.creative_id, i.platform, i.account_id, c.name, c.type,c.url, c.thumbnail_url') // 按需要的字段分组
|
||||
->field([
|
||||
'i.creative_id',
|
||||
'c.name AS creative_name', // 从 bps_ads_creative 表中选择 name
|
||||
'c.url AS creative_url', // 从 bps_ads_creative 表中选择 url
|
||||
'c.type AS creative_type', // 从 bps_ads_creative 表中选择 url
|
||||
'c.thumbnail_url', // 从 bps_ads_creative 表中选择 thumbnail_url
|
||||
ThinkDb::raw('SUM(i.spend) AS total_spend'),
|
||||
ThinkDb::raw('SUM(i.purchases_value) AS total_conversions_value'),
|
||||
@ -737,9 +759,10 @@ class AdsInsightService
|
||||
$creativeSummaryData[$creativeData->creative_id] = [
|
||||
'creative_id' => $creativeData->creative_id,
|
||||
'creative' => $creativeData->creative_name, // 使用联接查询中的 creative_name
|
||||
'creative_url' => $creativeData->creative_url?: '', // 使用联接查询中的 creative_url
|
||||
'thumbnail_url' => $creativeData->thumbnail_url?: '', // 使用联接查询中的 thumbnail_url
|
||||
'title' => $creativeData->title?: '', // 使用联接查询中的 title
|
||||
'creative_type' => $creativeData->creative_type, // 使用联接查询中的 creative_name
|
||||
'creative_url' => $creativeData->creative_url ?: '', // 使用联接查询中的 creative_url
|
||||
'thumbnail_url' => $creativeData->thumbnail_url ?: '', // 使用联接查询中的 thumbnail_url
|
||||
'title' => $creativeData->title ?: '', // 使用联接查询中的 title
|
||||
'spend' => 0,
|
||||
'purchase_value' => '-',
|
||||
'roas' => 0,
|
||||
@ -841,8 +864,10 @@ class AdsInsightService
|
||||
public function getAdcycleInsight($platformType, $customerIds, $cycle, $startDate = null, $endDate = null)
|
||||
{
|
||||
// 1. 查询全部数据集
|
||||
$adcycleDataQuery = BpsAdInsight::alias('i')
|
||||
->where('i.platform', $platformType); // 根据 platform 筛选
|
||||
$adcycleDataQuery = BpsAdInsight::alias('i');
|
||||
if ($platformType != 0) {
|
||||
$adcycleDataQuery->where('i.platform', $platformType); // 只有 platformType 不为 0 时才添加筛选
|
||||
}
|
||||
//dump($customerIds);
|
||||
// 2. 客户 ID 过滤(如果提供了)
|
||||
if (!empty($customerIds)) {
|
||||
@ -871,7 +896,7 @@ class AdsInsightService
|
||||
// dump(ThinkDb::getLastSql());
|
||||
|
||||
// 5. 处理数据,按照周期进行分组
|
||||
$processedData = $this->processDataByCycle($adcycleData, $cycle);
|
||||
$processedData = $this->processDataByCycle($adcycleData->toArray(), $cycle);
|
||||
|
||||
// 6. 返回处理后的数据
|
||||
return $processedData;
|
||||
@ -886,21 +911,27 @@ class AdsInsightService
|
||||
*/
|
||||
private function processDataByCycle($adcycleData, $cycle)
|
||||
{
|
||||
// 排序 adcycleData 数组,确保按照日期升序排列
|
||||
usort($adcycleData, function ($a, $b) {
|
||||
return $a['date'] <=> $b['date']; // 按照 'YYYYMMDD' 字符顺序排序
|
||||
});
|
||||
$groupedData = [];
|
||||
|
||||
foreach ($adcycleData as $data) {
|
||||
// 根据周期类型,调整日期分组
|
||||
switch ($cycle) {
|
||||
case 1:
|
||||
$key = $data->date; // 按日期直接分组
|
||||
// 将 'YYYYMMDD' 格式的日期转换为 'YYYY-MM-DD'
|
||||
$date = DateTime::createFromFormat('Ymd', $data['date']); // 转换为 DateTime 对象
|
||||
$key = $date ? $date->format('Y-m-d') : ''; // 格式化为 'YYYY-MM-DD'
|
||||
break;
|
||||
case 2:
|
||||
// 使用 ISO 周格式来分组
|
||||
$key = $this->getWeekFromDate($data->date);
|
||||
$key = $this->getWeekFromDate($data['date']);
|
||||
break;
|
||||
case 3:
|
||||
// 按年-月格式分组
|
||||
$key = $this->getMonthFromDate($data->date);
|
||||
$key = $this->getMonthFromDate($data['date']);
|
||||
break;
|
||||
default:
|
||||
throw new \InvalidArgumentException("Invalid cycle value. Use 'daily', 'weekly' or 'monthly'.");
|
||||
@ -919,8 +950,8 @@ class AdsInsightService
|
||||
}
|
||||
|
||||
// 累加数据
|
||||
$groupedData[$key]['spend'] += $data->spend;
|
||||
$groupedData[$key]['revenue'] += $data->revenue;
|
||||
$groupedData[$key]['spend'] += $data['spend'];
|
||||
$groupedData[$key]['revenue'] += $data['revenue'];
|
||||
// $groupedData[$key]['conversions_value'] += $data->purchases_value;
|
||||
// $groupedData[$key]['conversions'] += $data->purchases;
|
||||
// $groupedData[$key]['impressions'] += $data->impressions;
|
||||
@ -965,7 +996,7 @@ class AdsInsightService
|
||||
$dateObj = \DateTime::createFromFormat('Ymd', $dateStr);
|
||||
|
||||
// 获取 ISO 周格式
|
||||
return $dateObj->format('o-W');
|
||||
return $dateObj->format('o-W'). 'W';
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user