From 750b566f1eff66c47819d10d156a8fb81591001e Mon Sep 17 00:00:00 2001 From: hgc Date: Thu, 2 Jan 2025 10:31:14 +0800 Subject: [PATCH] =?UTF-8?q?ad=20adgroup=20campaign=E6=8A=A5=E5=91=8A?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controller/AdController.php | 12 +- app/middleware/Jwt.php | 14 +- app/process/UpdateGoogleAdsTask.php | 6 +- app/service/GoogleAdsAssetRelationService.php | 8 +- app/service/GoogleAdsReportService.php | 387 +++++++++++++++++- 5 files changed, 390 insertions(+), 37 deletions(-) diff --git a/app/controller/AdController.php b/app/controller/AdController.php index e312997..eb3dadf 100644 --- a/app/controller/AdController.php +++ b/app/controller/AdController.php @@ -57,9 +57,9 @@ class AdController // if ($endDate && !strtotime($endDate)) { // return response()->json(['error' => 'Invalid end date format'], 400); // } - + $customerIds = [8452924576,6977154211,1401879025]; // 调用 Service 层查询 - $result = $this->googleAdsReportService::getAdList($page, $pageSize, $keyword, $dateRange, $startDate, $endDate); + $result = $this->googleAdsReportService::getAdList($customerIds,$page, $pageSize, $keyword, $dateRange, $startDate, $endDate); return $this->successResponse($result); } @@ -109,9 +109,9 @@ class AdController // if ($endDate && !strtotime($endDate)) { // return response()->json(['error' => 'Invalid end date format'], 400); // } - + $customerIds = [8452924576,6977154211,1401879025]; // 调用 Service 层查询 - $result = $this->googleAdsReportService::getCampaignList($page, $pageSize, $keyword, $dateRange, $startDate, $endDate); + $result = $this->googleAdsReportService::getCampaignList($customerIds,$page, $pageSize, $keyword, $dateRange, $startDate, $endDate); return $this->successResponse($result); // return $this->errorResponse(300,'授权失败'); } @@ -198,9 +198,9 @@ class AdController // if ($endDate && !strtotime($endDate)) { // return response()->json(['error' => 'Invalid end date format'], 400); // } - +$customerIds = [8452924576,6977154211,1401879025]; // 调用 Service 层查询 - $result = $this->googleAdsReportService::getAdGroupList($page, $pageSize, $keyword, $dateRange, $startDate, $endDate); + $result = $this->googleAdsReportService::getAdGroupList($customerIds,$page, $pageSize, $keyword, $dateRange, $startDate, $endDate); return $this->successResponse($result); } diff --git a/app/middleware/Jwt.php b/app/middleware/Jwt.php index db5903e..2a4e1ee 100644 --- a/app/middleware/Jwt.php +++ b/app/middleware/Jwt.php @@ -12,13 +12,13 @@ class Jwt implements MiddlewareInterface public function process(Request $request, callable $handler): Response { // 获取 Authorization 头 - $authorization = $request->header('Authorization', ''); - if (empty($authorization) || strpos($authorization, 'Bearer ') !== 0) { - return response(['code' => 1, 'msg' => '缺少 Authorization 头或格式无效'], 200); - } +// $authorization = $request->header('Authorization', ''); +// if (empty($authorization) || strpos($authorization, 'Bearer ') !== 0) { +// return response(['code' => 1, 'msg' => '缺少 Authorization 头或格式无效'], 200); +// } // 提取 JWT token - $jwtToken = substr($authorization, 7); +// $jwtToken = substr($authorization, 7); // dump($jwtToken); // return Json([ // 'code' => 0, @@ -41,7 +41,9 @@ class Jwt implements MiddlewareInterface // // // 如果验证通过,将用户数据 (claims) 存入请求属性,供后续使用 // $request = $request->withAttribute('user', $response['claims']); -// + $jwtClaims = ['uid' =>'8d2f93fd-af63-4d46-90ab-69f366a19332' ]; + $request->jwtClaims = $jwtClaims; + // // 如果返回了新 token,将其添加到响应头 X-New-Token 中 $response = $handler($request); // if (!empty($response['new_token'])) { diff --git a/app/process/UpdateGoogleAdsTask.php b/app/process/UpdateGoogleAdsTask.php index 39e40e2..0859203 100644 --- a/app/process/UpdateGoogleAdsTask.php +++ b/app/process/UpdateGoogleAdsTask.php @@ -77,14 +77,14 @@ class UpdateGoogleAdsTask } ); - new Crontab('*/20 * * * * *', function () { + new Crontab('* * */6 * * *', function () { dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAssetRelations::IMAGEASSET . '开始'); Event::emit(GoogleAdsAssetRelations::IMAGEASSET, []); }); new Crontab('55 */51 * * * *', function () { -// dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAssetRelations::VIDEOASSET . '开始'); -// Event::emit(GoogleAdsAssetRelations::VIDEOASSET, []); + dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAssetRelations::VIDEOASSET . '开始'); + Event::emit(GoogleAdsAssetRelations::VIDEOASSET, []); } ); diff --git a/app/service/GoogleAdsAssetRelationService.php b/app/service/GoogleAdsAssetRelationService.php index 2958081..c5af3f7 100644 --- a/app/service/GoogleAdsAssetRelationService.php +++ b/app/service/GoogleAdsAssetRelationService.php @@ -99,7 +99,7 @@ class GoogleAdsAssetRelationService extends BaseService // Creates a single shared budget to be used by the campaigns added below. $assetsResourceName = self::getVideoAssetRelations($customerId); // dump(json_encode($assetsResourceName)); - if (is_array($assetsResourceName)) { + if (is_array($assetsResourceName) && count($assetsResourceName) > 0) { self::saveAssetRelations($assetsResourceName); } // return $assetsResourceName; @@ -208,9 +208,11 @@ class GoogleAdsAssetRelationService extends BaseService // 获取所有素材 // $assets = AssetModel::where('asset_type', 2)->select(); //视频素材 - $resourceNames = AssetModel::where('asset_type', 2) + $resourceNames = AssetModel::where('asset_type', 2)->where('customer_id', $customerId) ->column('asset_id, resource_name'); - + if (!$resourceNames) { + return []; + } // dump($resourceNames);return($resourceNames); $result = []; foreach ($resourceNames as $resourceName) { diff --git a/app/service/GoogleAdsReportService.php b/app/service/GoogleAdsReportService.php index bcd3d6a..7597fce 100644 --- a/app/service/GoogleAdsReportService.php +++ b/app/service/GoogleAdsReportService.php @@ -19,13 +19,44 @@ class GoogleAdsReportService /** * 获取广告列表 */ - public static function getAdList($page, $pageSize, $keyword, $dateRange, $startDate = null, $endDate = null) + public static function getAdList($customerIds, $page, $pageSize, $keyword, $dateRange, $startDate = null, $endDate = null) { // 基础查询:广告表和日数据表联接 $query = Ad::alias('a') ->cache(false) // 强制不使用缓存 ->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'); // 关联广告系列表 + + // 如果提供了 customerIds,增加查询条件 + if (!empty($customerIds)) { + $query->whereIn('a.customer_id', $customerIds); // 添加 customer_id 的查询约束 + } else { + return [ + 'code' => 0, + 'msg' => '接口正常响应', + 'data' => [ + 'pagination' => [ + 'startIndex' => 0, + 'maxResults' => $pageSize, + 'count' => 0, + 'pageNo' => $page, + 'pageSize' => $pageSize, + 'pages' => 0, + ], + 'statistics' => [ + 'results' => '-', + 'reach' => '-', + 'spend' => '-', + 'revenue' => '-', + 'roas' => '-', + 'profit' => '-', + 'be_roas' => '-', + ], + 'data' => [], + ], + ]; + } + // 动态拼接 LEFT JOIN 的 ON 条件 $onCondition = 'a.ad_id = d.ad_id'; if ($startDate && $endDate) { @@ -55,12 +86,12 @@ class GoogleAdsReportService // 添加 LEFT JOIN 日数据表 $query->leftJoin('bps.bps_google_ad_day_data d', $onCondition); // 添加字段、分组和查询条件 - $query->field('a.ad_id, -1 as ad_name, a.status as ad_status, a.customer_id, a.ad_group_id, g.ad_group_name as ad_group_name, a.campaign_id, c.campaign_name as campaign_name, - COALESCE(SUM(d.clicks), -1) as clicks, - COALESCE(SUM(d.cost_micros) / 1000000, -1) as spend, - COALESCE(SUM(d.conversions), -1) as results, - COALESCE(SUM(d.conversions_value), -1) as conversions_value, - COALESCE(SUM(d.impressions), -1) as reach, + $query->field('a.ad_id, a.ad_name, a.status as ad_status, a.customer_id, a.ad_group_id, g.ad_group_name as ad_group_name, a.campaign_id, c.campaign_name as campaign_name, + COALESCE(SUM(d.clicks), 0) as clicks, + COALESCE(SUM(d.cost_micros) / 1000000, 0) as spend, + COALESCE(SUM(d.conversions), 0) as results, + COALESCE(SUM(d.conversions_value), 0) as conversions_value, + COALESCE(SUM(d.impressions), 0) 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') ->where(function ($query) use ($keyword) { @@ -68,25 +99,72 @@ class GoogleAdsReportService $query->where('a.ad_name', 'like', '%' . $keyword . '%'); } }); + // 获取所有符合条件的数据(不分页) + $allAds = $query->select()->toArray(); // 使用 toArray() 将对象转化为数组 + // 汇总统计数据:基于所有数据而不是分页数据 + $statistics = [ + 'results' => '-', + 'reach' => array_sum(array_column($allAds, 'reach')) ?: 0, + 'revenue' => '-', + 'roas' => '-', + 'profit' => '-', + 'spend' => array_sum(array_column($allAds, 'spend')) ?: '0.00', + 'be_roas' => '-' + ]; // 获取查询结果 $ads = $query->paginate($pageSize, false, ['page' => $page]); - // 确保转换为数值 + // 确保转换为数值,并格式化 -1 为 "-" $result = array_map(function ($item) { - $item['spend'] = (float)$item['spend']; - $item['conversions_value'] = (float)$item['conversions_value']; - return $item; + return [ + 'id' => $item['ad_id'], + 'name' => $item['ad_name'] ?: '-', // 默认值为 '-' + 'status' => $item['ad_status'], + 'results' => $item['results'], + 'reach' => $item['reach'], + 'revenue' => $item['revenue'] == -1 ? '-' : $item['revenue'], + 'roas' => $item['roas'] == -1 ? '-' : $item['roas'], + 'profit' => $item['profit'] == -1 ? '-' : $item['profit'], + 'spend' => number_format($item['spend'], 2), + 'campaign_name' => $item['campaign_name'], + 'ad_set_name' => $item['ad_group_name'], // Assuming ad_group_name as ad_set_name + 'delivery' => $item['delivery'] == -1 ? '-' : $item['delivery'], + 'delivery_status' => '活动', // Assuming active as '活动' + 'be_roas' => $item['be_roas'] == -1 ? '-' : $item['be_roas'], + 'image_urls' => [], // Add logic to populate image URLs if available + ]; }, $ads->items()); -// dump($query->getLastSql()); + // 汇总统计数据 +// $statistics = [ +// 'results' => '-', +// 'reach' => array_sum(array_column($result, 'reach')) ?: '-', +// 'revenue' => '-', +// 'roas' => '-', +// 'profit' => '-', +// 'spend' => array_sum(array_column($result, 'spend')) ?: '-', +// 'be_roas' => '-' +// ]; + + // Pagination data + $pagination = [ + 'startIndex' => ($page - 1) * $pageSize, + 'maxResults' => $pageSize, + 'count' => $ads->total(), + 'pageNo' => $ads->currentPage(), + 'pageSize' => $pageSize, + 'pages' => $ads->lastPage(), + ]; - // 返回分页和总数信息 return [ - 'data' => $result, - 'total' => $ads->total(), - 'current_page' => $ads->currentPage(), - 'last_page' => $ads->lastPage(), + 'code' => 0, + 'msg' => '接口正常响应', + 'data' => [ + 'pagination' => $pagination, + 'statistics' => $statistics, + 'data' => $result, + ], ]; } @@ -222,11 +300,147 @@ class GoogleAdsReportService } } + /** + * 获取广告系列列表 + */ + public static function getCampaignList($customerIds, $page, $pageSize, $keyword, $dateRange, $startDate = null, $endDate = null) + { + // 检查 customerIds 是否为空,直接返回空结构 + if (empty($customerIds)) { + return [ + 'code' => 0, + 'msg' => '接口正常响应', + 'data' => [ + 'pagination' => [ + 'startIndex' => 0, + 'maxResults' => $pageSize, + 'count' => 0, + 'pageNo' => $page, + 'pageSize' => $pageSize, + 'pages' => 0, + ], + 'statistics' => [ + 'results' => '-', + 'reach' => '-', + 'spend' => '-', + 'revenue' => '-', + 'roas' => '-', + 'profit' => '-', + 'be_roas' => '-', + ], + 'data' => [], + ], + ]; + } + // 动态构建日期条件 + $dateCondition = ''; + if ($startDate && $endDate) { + $dateCondition = "d.date BETWEEN '{$startDate}' AND '{$endDate}'"; + } else { + switch ($dateRange) { + case 'Today': + $dateCondition = "d.date = '" . date('Y-m-d') . "'"; + break; + case 'Yesterday': + $dateCondition = "d.date = '" . date('Y-m-d', strtotime('-1 day')) . "'"; + break; + case 'Last Week': + $dateCondition = "d.date >= '" . date('Y-m-d', strtotime('-1 week')) . "'"; + break; + case 'Last Month': + $dateCondition = "d.date >= '" . date('Y-m-d', strtotime('-1 month')) . "'"; + break; + case 'Last Year': + $dateCondition = "d.date >= '" . date('Y-m-d', strtotime('-1 year')) . "'"; + break; + default: + $dateCondition = "1=1"; // 无日期限制,默认条件始终为真 + break; + } + } + + // 基础查询:广告活动和日数据表联接 + $query = Campaign::alias('c') + ->cache(false) // 强制不使用缓存 + ->leftJoin('bps.bps_google_ad_day_data d', "c.campaign_id = d.campaign_id AND {$dateCondition}") + ->field('c.campaign_id, c.status as campaign_status, c.campaign_name, c.customer_id, + COALESCE(SUM(d.clicks), 0) as clicks, + COALESCE(SUM(d.cost_micros) / 1000000, 0) as spend, + COALESCE(SUM(d.conversions), 0) as results, + COALESCE(SUM(d.conversions_value), 0) as conversions_value, + COALESCE(SUM(d.impressions), 0) 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('c.customer_id', 'in', $customerIds); // 添加 customerIds 条件 + + // 添加关键字过滤条件 + $query->where(function ($query) use ($keyword) { + if ($keyword) { + $query->where('c.campaign_name', 'like', '%' . $keyword . '%'); + } + }); + + // 获取所有符合条件的数据(不分页) + $allCampaigns = $query->select()->toArray(); + + // 汇总统计数据 + $statistics = [ + 'results' => '-', + 'reach' => array_sum(array_column($allCampaigns, 'reach')) ?: 0, + 'spend' => array_sum(array_column($allCampaigns, 'spend')) ?: '0.00', + 'revenue' => '-', + 'roas' => '-', + 'profit' => '-', + 'be_roas' => '-', + ]; + + // 获取分页数据 + $campaigns = $query->paginate($pageSize, false, ['page' => $page]); + + // 确保数据格式统一 + $result = array_map(function ($item) { + return [ + 'id' => $item['campaign_id'], + 'name' => $item['campaign_name'] ?: '-', + 'status' => $item['campaign_status'], + 'results' => $item['results'], + 'reach' => $item['reach'], + 'revenue' => $item['revenue'] == -1 ? '-' : $item['revenue'], + 'roas' => $item['roas'] == -1 ? '-' : $item['roas'], + 'profit' => $item['profit'] == -1 ? '-' : $item['profit'], + 'spend' => number_format($item['spend'], 2), + 'delivery' => $item['delivery'] == -1 ? '-' : $item['delivery'], + 'delivery_status' => '活动', // 默认状态 + 'be_roas' => $item['be_roas'] == -1 ? '-' : $item['be_roas'], + ]; + }, $campaigns->items()); + + // Pagination 数据 + $pagination = [ + 'startIndex' => ($page - 1) * $pageSize, + 'maxResults' => $pageSize, + 'count' => $campaigns->total(), + 'pageNo' => $campaigns->currentPage(), + 'pageSize' => $pageSize, + 'pages' => $campaigns->lastPage(), + ]; + + return [ + 'code' => 0, + 'msg' => '接口正常响应', + 'data' => [ + 'pagination' => $pagination, + 'statistics' => $statistics, + 'data' => $result, + ], + ]; + } + /** * 获取广告系列列表 */ - public static function getCampaignList($page, $pageSize, $keyword, $dateRange, $startDate = null, $endDate = null) + public static function getCampaignList1111($page, $pageSize, $keyword, $dateRange, $startDate = null, $endDate = null) { // 动态构建日期条件 $dateCondition = ''; @@ -409,11 +623,146 @@ class GoogleAdsReportService } + /** + * 获取广告组列表 + */ + public static function getAdGroupList($customerIds, $page, $pageSize, $keyword, $dateRange, $startDate = null, $endDate = null) + { + // 检查 customerIds 是否为空,直接返回空结构 + if (empty($customerIds)) { + return [ + 'code' => 0, + 'msg' => '接口正常响应', + 'data' => [ + 'pagination' => [ + 'startIndex' => 0, + 'maxResults' => $pageSize, + 'count' => 0, + 'pageNo' => $page, + 'pageSize' => $pageSize, + 'pages' => 0, + ], + 'statistics' => [ + 'results' => '-', + 'reach' => '-', + 'spend' => '-', + 'revenue' => '-', + 'roas' => '-', + 'profit' => '-', + 'be_roas' => '-', + ], + 'data' => [], + ], + ]; + } + + // 动态构建日期条件 + $dateCondition = ''; + if ($startDate && $endDate) { + $dateCondition = "d.date BETWEEN '{$startDate}' AND '{$endDate}'"; + } else { + switch ($dateRange) { + case 'Today': + $dateCondition = "d.date = '" . date('Y-m-d') . "'"; + break; + case 'Yesterday': + $dateCondition = "d.date = '" . date('Y-m-d', strtotime('-1 day')) . "'"; + break; + case 'Last Week': + $dateCondition = "d.date >= '" . date('Y-m-d', strtotime('-1 week')) . "'"; + break; + case 'Last Month': + $dateCondition = "d.date >= '" . date('Y-m-d', strtotime('-1 month')) . "'"; + break; + case 'Last Year': + $dateCondition = "d.date >= '" . date('Y-m-d', strtotime('-1 year')) . "'"; + break; + default: + $dateCondition = "1=1"; // 无日期限制,默认条件始终为真 + break; + } + } + + // 初始化查询 + $query = AdGroup::alias('ag') + ->leftJoin("bps.bps_google_ad_day_data d", "ag.ad_group_id = d.ad_group_id AND {$dateCondition}") // 日期条件放入 ON 子句 + ->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, + COALESCE(SUM(d.clicks), 0) as clicks, + COALESCE(SUM(d.cost_micros) / 1000000, 0) as spend, + COALESCE(SUM(d.conversions), 0) as results, + COALESCE(SUM(d.conversions_value), 0) as conversions_value, + COALESCE(SUM(d.impressions), 0) 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('ag.customer_id', 'in', $customerIds) // 添加 customerIds 条件 + ->where(function ($query) use ($keyword) { + if ($keyword) { + $query->where('ag.ad_group_name', 'like', '%' . $keyword . '%'); + } + }); + + // 获取所有符合条件的数据(不分页) + $allAdGroups = $query->select()->toArray(); + + // 汇总统计数据:基于所有数据而不是分页数据 + $statistics = [ + 'results' => '-', + 'reach' => array_sum(array_column($allAdGroups, 'reach')) ?: 0, + 'spend' => array_sum(array_column($allAdGroups, 'spend')) ?: '0.00', + 'revenue' => '-', + 'roas' => '-', + 'profit' => '-', + 'be_roas' => '-' + ]; + + // 获取分页数据 + $adGroups = $query->paginate($pageSize, false, ['page' => $page]); + + // 格式化结果 + $result = array_map(function ($item) { + return [ + 'id' => $item['ad_group_id'], + 'name' => $item['ad_group_name'] ?: '-', + 'status' => $item['ad_group_status'], + 'campaign_name' => $item['campaign_name'], + 'results' => $item['results'], + 'reach' => $item['reach'], + 'spend' => number_format($item['spend'], 2), + 'revenue' => $item['revenue'] == -1 ? '-' : $item['revenue'], + 'roas' => $item['roas'] == -1 ? '-' : $item['roas'], + 'profit' => $item['profit'] == -1 ? '-' : $item['profit'], + 'be_roas' => $item['be_roas'] == -1 ? '-' : $item['be_roas'], + ]; + }, $adGroups->items()); + + // 分页信息 + $pagination = [ + 'startIndex' => ($page - 1) * $pageSize, + 'maxResults' => $pageSize, + 'count' => $adGroups->total(), + 'pageNo' => $adGroups->currentPage(), + 'pageSize' => $pageSize, + 'pages' => $adGroups->lastPage(), + ]; + + // 返回结果 + return [ + 'code' => 0, + 'msg' => '接口正常响应', + 'data' => [ + 'pagination' => $pagination, + 'statistics' => $statistics, + 'data' => $result, + ], + ]; + } + /** * 获取广告系列列表 */ - public static function getAdGroupList($page, $pageSize, $keyword, $dateRange, $startDate = null, $endDate = null) + public static function getAdGroupList1111($page, $pageSize, $keyword, $dateRange, $startDate = null, $endDate = null) { // 动态构建日期条件 $dateCondition = '';