webman_ad/app/service/GoogleAdsReportService.php

574 lines
25 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace app\service;
use app\model\Ad;
use app\model\DayData;
use app\model\Campaign;
use app\model\AdGroup;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use think\db\exception\DbException;
use think\facade\Db;
use think\model\Collection;
class GoogleAdsReportService
{
/**
* 获取广告列表
*/
public static function getAdList($page, $pageSize, $keyword, $dateRange, $startDate = null, $endDate = null)
{
// 基础查询:广告表和日数据表联接
$query = Ad::alias('a')
->leftJoin('bps.bps_google_ads_ad_group g', 'a.ad_group_id = g.ad_group_id') // 关联广告组表
->leftJoin('bps.bps_google_ads_campaign c', 'a.campaign_id = c.campaign_id') // 关联广告系列表
->leftJoin('bps.bps_google_ad_day_data d', 'a.ad_id = d.ad_id')
->field('a.ad_id, -1 as ad_name, a.status as ad_status, a.customer_id,a.ad_group_id, g.ad_group_name, a.campaign_id,c.campaign_name,
SUM(d.clicks) as clicks, SUM(d.cost_micros) / 1000000 as spend,
SUM(d.conversions) as results, SUM(d.conversions_value) as conversions_value,
SUM(d.impressions) as reach,-1 as roas,-1 as be_roas,-1 as revenue, -1 as profit, -1 as delivery')
->group('a.ad_id, a.ad_name, a.status, a.customer_id, a.ad_group_id, g.ad_group_name, a.campaign_id, c.campaign_name') // 确保所有字段都在 group by 中
->where(function ($query) use ($keyword) {
if ($keyword) {
$query->where('a.ad_name', 'like', '%' . $keyword . '%');
}
});
// 如果提供了 startDate 和 endDate则根据范围查询
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;
}
}
// 获取分页数据
$ads = $query->paginate($pageSize, false, ['page' => $page]);
// 返回分页和总数信息
return [
'data' => $ads->items(),
'total' => $ads->total(),
'current_page' => $ads->currentPage(),
'last_page' => $ads->lastPage(),
];
}
/**
* 导出广告列表到 Excel
*
* @param string $keyword
* @param string $dateRange
* @return void
*/
public static function exportAdListToExcel($keyword, $dateRange, $startDate = null, $endDate = null)
{
// 获取所有的广告数据
$query = Ad::alias('a')
->leftJoin('bps.bps_google_ads_ad_group g', 'a.ad_group_id = g.ad_group_id') // 关联广告组表
->leftJoin('bps.bps_google_ads_campaign c', 'a.campaign_id = c.campaign_id') // 关联广告系列表
->leftJoin('bps.bps_google_ad_day_data d', 'a.ad_id = d.ad_id')
->field('a.ad_id, -1 as ad_name, a.status as ad_status, a.customer_id,a.ad_group_id, g.ad_group_name, a.campaign_id,c.campaign_name,
SUM(d.clicks) as clicks, SUM(d.cost_micros) / 1000000 as spend,
SUM(d.conversions) as results, SUM(d.conversions_value) as conversions_value,
SUM(d.impressions) as reach,-1 as roas,-1 as be_roas,-1 as revenue, -1 as profit, -1 as delivery')
->group('a.ad_id, a.ad_name, a.status, a.customer_id, a.ad_group_id, g.ad_group_name, a.campaign_id, c.campaign_name') // 确保所有字段都在 group by 中
->where(function ($query) use ($keyword) {
if ($keyword) {
$query->where('a.ad_name', 'like', '%' . $keyword . '%');
}
});
// 如果提供了 startDate 和 endDate则根据范围查询
if ($startDate && $endDate) {
$query->whereBetween('d.date', [$startDate, $endDate]);
$dateRange = $startDate. 'to'. $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;
}
}
// 获取所有广告数据
$ads = $query->select();
// 创建一个新的 Spreadsheet 对象
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$ad_status = [
0 => 'UNSPECIFIED',
1 => 'UNKNOWN', // UNKNOW
2 => 'ENABLED', // ENABLED
3 => 'PAUSED', // PAUSED
4 => 'REMOVED', // REMOVED
];
// 设置表头
$sheet->setCellValue('A1', 'Ad ID');
$sheet->setCellValue('B1', 'Ad Status');
$sheet->setCellValue('C1', 'Name');
$sheet->setCellValue('D1', 'Campaign');
$sheet->setCellValue('E1', 'Ad Set');
$sheet->setCellValue('F1', 'Delivery');
$sheet->setCellValue('G1', 'Results');
$sheet->setCellValue('H1', 'Reach');
$sheet->setCellValue('I1', 'Revenue');
$sheet->setCellValue('J1', 'ROAS');
$sheet->setCellValue('K1', 'beROAS');
$sheet->setCellValue('L1', 'Profit');
$sheet->setCellValue('M1', 'Spend');
// $sheet->setCellValue('N1', 'Customer ID');
// $sheet->setCellValue('E1', 'Clicks');
// $sheet->setCellValue('F1', 'Cost Micros');
// $sheet->setCellValue('G1', 'Conversions');
// $sheet->setCellValue('H1', 'Conversions Value');
// $sheet->setCellValue('I1', 'Impressions');
// 填充数据
$row = 2; // 从第二行开始
foreach ($ads as $ad) {
$sheet->setCellValueExplicit('A' . $row, (string)$ad->ad_id, \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING); // 设置 ad_id 为文本
$sheet->setCellValue('B' . $row, $ad_status[$ad->ad_status]);
$sheet->setCellValue('C' . $row, $ad->ad_name); // 直接设置 ad_name
$sheet->setCellValue('D' . $row, $ad->campaign_name); // 直接设置 ad_name
$sheet->setCellValue('E' . $row, $ad->ad_group_name); // 直接设置 ad_name
$sheet->setCellValue('F' . $row, $ad->delivery); // 直接设置 ad_name
$sheet->setCellValue('G' . $row, $ad->results);
$sheet->setCellValue('H' . $row, $ad->reach);
$sheet->setCellValue('I' . $row, $ad->revenue);
$sheet->setCellValue('J' . $row, $ad->roas);
$sheet->setCellValue('K' . $row, $ad->be_roas);
$sheet->setCellValue('L' . $row, $ad->profit);
$sheet->setCellValue('M' . $row, $ad->spend);
// $sheet->setCellValueExplicit('N' . $row, (string)$ad->customer_id, \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING); // 设置 customer_id 为文本
$row++;
}
// 设置 Excel 文件名
$fileName = 'Ad_Report_' . $dateRange . '_' . date('Y-m-d_H-i-s') . '.xlsx';
// 创建 Excel 文件并保存
$writer = new Xlsx($spreadsheet);
$filePath = public_path() . '/' . $fileName;
try {
$writer->save($filePath);
return response()->download($filePath, $fileName);
// return ['success' => true, 'file_path' => $filePath];
} catch (\Exception $e) {
return ['' => false, 'message' => $e->getMessage()];
}
}
/**
* 获取广告系列列表
*/
public static function getCampaignList($page, $pageSize, $keyword, $dateRange, $startDate = null, $endDate = null)
{
// 基础查询:广告活动和日数据表联接
$query = Campaign::alias('c')
->leftJoin('bps.bps_google_ad_day_data d', 'c.campaign_id = d.campaign_id')
->field('c.campaign_id, c.status as campaign_status,c.campaign_name, c.customer_id,
SUM(d.clicks) as clicks, SUM(d.cost_micros) / 1000000 as spend,
SUM(d.conversions) as results, SUM(d.conversions_value) as conversions_value,
SUM(d.impressions) as reach,-1 as roas,-1 as be_roas,-1 as revenue, -1 as profit, -1 as delivery')
->group('c.campaign_id, c.status,c.customer_id, c.campaign_name')
->where(function ($query) use ($keyword) {
if ($keyword) {
$query->where('c.campaign_name', 'like', '%' . $keyword . '%');
}
});
// 如果提供了 startDate 和 endDate则根据范围查询
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;
}
}
// 获取分页数据
$campaigns = $query->paginate($pageSize, false, ['page' => $page]);
// 返回分页和总数信息
return [
'data' => $campaigns->items(),
'total' => $campaigns->total(),
'current_page' => $campaigns->currentPage(),
'last_page' => $campaigns->lastPage(),
];
}
/**
* 导出广告系列数据到 Excel
*
* @param string $keyword
* @param string $dateRange
* @return void
*/
public static function exportCampaignsToExcel($keyword, $dateRange, $startDate = null, $endDate = null)
{
// 获取所有的广告系列数据
$query = Campaign::alias('c')
->leftJoin('bps.bps_google_ad_day_data d', 'c.campaign_id = d.campaign_id')
->field('c.campaign_id, c.status as campaign_status,c.campaign_name, c.customer_id,
SUM(d.clicks) as clicks, SUM(d.cost_micros) / 1000000 as spend,
SUM(d.conversions) as results, SUM(d.conversions_value) as conversions_value,
SUM(d.impressions) as reach,-1 as roas,-1 as be_roas,-1 as revenue, -1 as profit, -1 as delivery')
->group('c.campaign_id, c.status,c.customer_id, c.campaign_name')
->where(function ($query) use ($keyword) {
if ($keyword) {
$query->where('c.campaign_name', 'like', '%' . $keyword . '%');
}
});
// 如果提供了 startDate 和 endDate则根据范围查询
if ($startDate && $endDate) {
$query->whereBetween('d.date', [$startDate, $endDate]);
$dateRange = $startDate. 'to'. $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;
}
}
// 获取所有广告系列数据
$campaigns = $query->select();
// 创建一个新的 Spreadsheet 对象
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$campaignsStatus = [
0 => 'UNSPECIFIED', // UNSPECIFIED
1 => 'UNKNOWN', // UNKNOWN
2 => 'ENABLED', // ENABLED
3 => 'PAUSED', // PAUSED
4 => 'REMOVED', // REMOVED
];
// 设置表头
$sheet->setCellValue('A1', 'Campaign ID');
$sheet->setCellValue('B1', 'Status');
$sheet->setCellValue('C1', 'Name');
$sheet->setCellValue('D1', 'Delivery');
$sheet->setCellValue('E1', 'Results');
$sheet->setCellValue('F1', 'Reach');
$sheet->setCellValue('G1', 'Revenue');
$sheet->setCellValue('H1', 'ROAS');
$sheet->setCellValue('I1', 'beROAS');
$sheet->setCellValue('J1', 'Profit');
$sheet->setCellValue('K1', 'Spend');
// 填充数据
$row = 2; // 从第二行开始
foreach ($campaigns as $campaign) {
//使用 setCellValueExplicit 显式设置为文本格式
$sheet->setCellValueExplicit('A' . $row, (string)$campaign->campaign_id, \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING); // 设置为文本格式
$sheet->setCellValue('B' . $row, $campaignsStatus[$campaign->campaign_status]);
$sheet->setCellValue('C' . $row, $campaign->campaign_name);
$sheet->setCellValue('D' . $row, $campaign->delivery); // 直接设置 ad_name
$sheet->setCellValue('E' . $row, $campaign->results);
$sheet->setCellValue('F' . $row, $campaign->reach);
$sheet->setCellValue('G' . $row, $campaign->revenue);
$sheet->setCellValue('H' . $row, $campaign->roas);
$sheet->setCellValue('I' . $row, $campaign->be_roas);
$sheet->setCellValue('J' . $row, $campaign->profit);
$sheet->setCellValue('K' . $row, $campaign->spend);
// $sheet->setCellValueExplicit('N' . $row, (string)$campaign->customer_id, \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING); // 设置为文本格式
$row++;
}
// 设置 Excel 文件名
$fileName = 'Campaign_Report_' . $dateRange . '_' . date('Y-m-d_H-i-s') . '.xlsx';
// 创建 Excel 文件并保存
$writer = new Xlsx($spreadsheet);
$filePath = public_path() . '/' . $fileName;
try {
$writer->save($filePath);
return response()->download($filePath, $fileName);
// return ['success' => true, 'file_path' => $filePath];
} catch (\Exception $e) {
return ['' => false, 'message' => $e->getMessage()];
}
}
/**
* 获取广告系列列表
*/
public static function getAdGroupList($page, $pageSize, $keyword, $dateRange, $startDate = null, $endDate = null)
{
// 初始化查询
$query = AdGroup::alias('ag')
->leftJoin('bps.bps_google_ad_day_data d', 'ag.ad_group_id = d.ad_group_id')
->leftJoin('bps.bps_google_ads_campaign c', 'ag.campaign_id = c.campaign_id') // 关联广告系列表
->field('ag.ad_group_id,ag.ad_group_name,ag.status as ad_group_status, ag.campaign_id,c.campaign_name, ag.customer_id,
SUM(d.clicks) as clicks, SUM(d.cost_micros) / 1000000 as spend,
SUM(d.conversions) as results, SUM(d.conversions_value) as conversions_value,
SUM(d.impressions) as reach,-1 as roas,-1 as be_roas,-1 as revenue, -1 as profit, -1 as delivery')
->group('ag.ad_group_id,ag.ad_group_name,ag.status, ag.campaign_id,c.campaign_name, ag.customer_id')
->where(function ($query) use ($keyword) {
if ($keyword) {
$query->where('ag.ad_group_name', 'like', '%' . $keyword . '%');
}
});
// 如果提供了 startDate 和 endDate则根据范围查询
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;
}
}
// 分页查询
try {
// $sql = $query->fetchSql()->select(); // fetchSql() 会返回 SQL 查询语句
// echo "Executed SQL: " . $sql; // 输出执行的 SQL
$result = $query->paginate([
'list_rows' => $pageSize, // 每页数量
'page' => $page, // 当前页码
]);
// 返回分页数据
return [
'data' => $result->items(),
'total' => $result->total(),
'current_page' => $result->currentPage(),
'last_page' => $result->lastPage(),
];
} catch (DbException $e) {
// 处理数据库查询错误
return [
'error' => 'Database query failed: ' . $e->getMessage(),
];
}
}
/**
* 将广告组数据导出到 Excel 文件
*/
public static function exportAdGroupsToExcel($keyword = '', $dateRange = 'Today', $startDate = null, $endDate = null)
{
// 初始化查询
$query = AdGroup::alias('ag')
->leftJoin('bps.bps_google_ad_day_data d', 'ag.ad_group_id = d.ad_group_id')
->leftJoin('bps.bps_google_ads_campaign c', 'ag.campaign_id = c.campaign_id') // 关联广告系列表
->field('ag.ad_group_id,ag.ad_group_name,ag.status as ad_group_status, ag.campaign_id,c.campaign_name, ag.customer_id,
SUM(d.clicks) as clicks, SUM(d.cost_micros) / 1000000 as spend,
SUM(d.conversions) as results, SUM(d.conversions_value) as conversions_value,
SUM(d.impressions) as reach,-1 as roas,-1 as be_roas,-1 as revenue, -1 as profit, -1 as delivery')
->group('ag.ad_group_id,ag.ad_group_name,ag.status, ag.campaign_id,c.campaign_name, ag.customer_id')
->where(function ($query) use ($keyword) {
if ($keyword) {
$query->where('ag.ad_group_name', 'like', '%' . $keyword . '%');
}
});
// 如果提供了 startDate 和 endDate则根据范围查询
if ($startDate && $endDate) {
$query->whereBetween('d.date', [$startDate, $endDate]);
$dateRange = $startDate. 'to'. $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_groups = $query->select();
// 创建一个新的 Spreadsheet 对象
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
// 设置表头
$sheet->setCellValue('A1', 'Ad Group ID');
$sheet->setCellValue('B1', 'Status');
$sheet->setCellValue('C1', 'Name');
$sheet->setCellValue('D1', 'Campaign');
$sheet->setCellValue('E1', 'Delivery');
$sheet->setCellValue('F1', 'Results');
$sheet->setCellValue('G1', 'Reach');
$sheet->setCellValue('H1', 'Revenue');
$sheet->setCellValue('I1', 'ROAS');
$sheet->setCellValue('J1', 'beROAS');
$sheet->setCellValue('K1', 'Profit');
$sheet->setCellValue('L1', 'Spend');
$ad_groups_status = [
0 => 'UNSPECIFIED', // UNSPECIFIED
1 => 'UNKNOWN', // UNKNOWN
2 => 'ENABLED', // ENABLED
3 => 'PAUSED', // PAUSED
4 => 'REMOVED', // REMOVED
];
// 填充数据
$row = 2;
foreach ($ad_groups as $adGroup) {
// 使用 setCellValueExplicit 显式设置为文本格式
$sheet->setCellValueExplicit('A' . $row, (string)$adGroup->ad_group_id, \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING); // 设置为文本格式
// $sheet->setCellValueExplicit('B' . $row, (string)$adGroup->campaign_id, \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING);
$sheet->setCellValue('B' . $row, $ad_groups_status[$adGroup->ad_group_status]);
$sheet->setCellValue('C' . $row, $adGroup->ad_group_name);
$sheet->setCellValue('D' . $row, $adGroup->campaign_name);
$sheet->setCellValue('E' . $row, $adGroup->delivery); // 直接设置 ad_name
$sheet->setCellValue('F' . $row, $adGroup->results);
$sheet->setCellValue('G' . $row, $adGroup->reach);
$sheet->setCellValue('H' . $row, $adGroup->revenue);
$sheet->setCellValue('I' . $row, $adGroup->roas);
$sheet->setCellValue('J' . $row, $adGroup->be_roas);
$sheet->setCellValue('K' . $row, $adGroup->profit);
$sheet->setCellValue('L' . $row, $adGroup->spend);
// $sheet->setCellValueExplicit('M' . $row, (string)$adGroup->customer_id, \PhpOffice\PhpSpreadsheet\Cell\DataType::TYPE_STRING);
$row++;
}
// 自动调整所有列宽
foreach (range('A', 'H') as $column) {
$spreadsheet->getActiveSheet()->getColumnDimension($column)->setAutoSize(true);
}
// 设置 Excel 文件名
$fileName = 'AdGroup_Report_' . $dateRange . '_' . date('Y-m-d_H-i-s') . '.xlsx';
// 创建 Excel 文件并保存
$writer = new Xlsx($spreadsheet);
$filePath = public_path() . '/' . $fileName;
try {
$writer->save($filePath);
return response()->download($filePath, $fileName);
// return ['success' => true, 'file_path' => $filePath];
} catch (\Exception $e) {
return ['' => false, 'message' => $e->getMessage()];
}
}
}