From e29de817002649708f719ca4d9e27150445c4c4f Mon Sep 17 00:00:00 2001 From: hgc Date: Sat, 28 Dec 2024 15:53:54 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=B7=E6=AD=8C=E5=88=9B=E6=84=8F=E7=B4=A0?= =?UTF-8?q?=E6=9D=903?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controller/AdController.php | 27 ++ app/process/UpdateGoogleAdsTask.php | 10 +- app/service/GoogleAdsAssetRelationService.php | 65 +++- app/service/GoogleAdsCampaignService.php | 56 +++- app/service/GoogleAdsReportService.php | 294 +++++++++++++++++- config/route.php | 5 + 6 files changed, 444 insertions(+), 13 deletions(-) diff --git a/app/controller/AdController.php b/app/controller/AdController.php index d40a571..e312997 100644 --- a/app/controller/AdController.php +++ b/app/controller/AdController.php @@ -63,6 +63,33 @@ class AdController return $this->successResponse($result); } + public function listAssets(Request $request) + { + // 获取请求参数 + $page = $request->input('page', 1); // 页码 + $pageSize = $request->input('page_size', 20); // 每页数量 + $keyword = $request->input('keyword', ''); // 关键字搜索 + $dateRange = $request->input('date_range', 'Last Week'); // 日期范围 + + // 获取自定义日期范围 + $startDate = $request->input('start_date', null); // 开始日期,默认为 null + $endDate = $request->input('end_date', null); // 结束日期,默认为 null + + $customerId = 4060397299; + + // 你可以进一步验证日期格式(可选) +// if ($startDate && !strtotime($startDate)) { +// return response()->json(['error' => 'Invalid start date format'], 400); +// } +// if ($endDate && !strtotime($endDate)) { +// return response()->json(['error' => 'Invalid end date format'], 400); +// } + + // 调用 Service 层查询 + $result = $this->googleAdsReportService->getAssetConversionData($customerId,$page, $pageSize, $keyword, $dateRange, $startDate, $endDate); + return $this->successResponse($result); + } + public function listCampaigns(Request $request) { // 获取请求参数 diff --git a/app/process/UpdateGoogleAdsTask.php b/app/process/UpdateGoogleAdsTask.php index 2f5570b..4d51a8e 100644 --- a/app/process/UpdateGoogleAdsTask.php +++ b/app/process/UpdateGoogleAdsTask.php @@ -77,16 +77,18 @@ class UpdateGoogleAdsTask ); new Crontab('55 */50 * * * *', function () { - dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsAssetRelations::IMAGEASSET . '开始'); - Event::emit(GoogleAdsAssetRelations::IMAGEASSET, []); +// 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, []); } ); + + // 每15分钟执行一次 // new Crontab('58 */15 * * * *', function () { // dump(date('Y-m-d H:i:s') . '更新' . GoogleAdsCampaigns::type . '开始'); diff --git a/app/service/GoogleAdsAssetRelationService.php b/app/service/GoogleAdsAssetRelationService.php index 5ebff6f..fcd9bd4 100644 --- a/app/service/GoogleAdsAssetRelationService.php +++ b/app/service/GoogleAdsAssetRelationService.php @@ -116,9 +116,9 @@ class GoogleAdsAssetRelationService extends BaseService $tableName = getenv('DB_PG_SCHEMA') ? getenv('DB_PG_SCHEMA') . '.' . $tableName : 'public' . $tableName; foreach ($assetsResourceName as $data) { // 修改后的插入 SQL 语句 - $sql = "INSERT INTO {$tableName} - (asset_id, ad_id, ad_group_id, campaign_id, date, create_at, update_at) - VALUES (:asset_id, :ad_id, :ad_group_id, :campaign_id, :date, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) + $sql = "INSERT INTO {$tableName} + (asset_id, ad_id, ad_group_id, campaign_id, date,month,season,year, create_at, update_at) + VALUES (:asset_id, :ad_id, :ad_group_id, :campaign_id, :date,:month,:season,:year, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) ON CONFLICT (asset_id, ad_id, date) DO NOTHING"; // 如果 (asset_id, ad_id, date) 存在,忽略插入操作 @@ -134,6 +134,14 @@ class GoogleAdsAssetRelationService extends BaseService public static function getAssetRelations(int $customerId) { + $date = date('Y-m-d'); + // 调用私有方法提取 year, month, season + $dateDetails = self::extractDateDetails($date); + + $year = $dateDetails['year']; + $month = $dateDetails['month']; + $season = $dateDetails['season']; + // 获取所有素材 // $assets = AssetModel::where('asset_type', 4)->select(); //图片素材 @@ -162,7 +170,10 @@ class GoogleAdsAssetRelationService extends BaseService $result[$resourceName['asset_id']]['ad_group_id'] = $ad['ad_group_id']; $result[$resourceName['asset_id']]['campaign_id'] = $ad['campaign_id']; $result[$resourceName['asset_id']]['asset_id'] = $resourceName['asset_id']; - $result[$resourceName['asset_id']]['date'] = date('Y-m-d'); + $result[$resourceName['asset_id']]['date'] = $date; + $result[$resourceName['asset_id']]['month'] = $month; + $result[$resourceName['asset_id']]['season'] = $season; + $result[$resourceName['asset_id']]['year'] = $year; } } @@ -178,6 +189,14 @@ class GoogleAdsAssetRelationService extends BaseService public static function getVideoAssetRelations(int $customerId) { + $date = date('Y-m-d'); + // 调用私有方法提取 year, month, season + $dateDetails = self::extractDateDetails($date); + + $year = $dateDetails['year']; + $month = $dateDetails['month']; + $season = $dateDetails['season']; + // 获取所有素材 // $assets = AssetModel::where('asset_type', 2)->select(); //视频素材 @@ -196,7 +215,10 @@ class GoogleAdsAssetRelationService extends BaseService $result[$resourceName['asset_id']]['ad_group_id'] = $ad['ad_group_id']; $result[$resourceName['asset_id']]['campaign_id'] = $ad['campaign_id']; $result[$resourceName['asset_id']]['asset_id'] = $resourceName['asset_id']; - $result[$resourceName['asset_id']]['date'] = date('Y-m-d'); + $result[$resourceName['asset_id']]['date'] = $date; + $result[$resourceName['asset_id']]['month'] = $month; + $result[$resourceName['asset_id']]['season'] = $season; + $result[$resourceName['asset_id']]['year'] = $year; } } @@ -206,6 +228,39 @@ class GoogleAdsAssetRelationService extends BaseService } + /** + * 从日期字符串中提取年、月、季节信息,并返回这些信息 + * + * @param string $date 日期,格式为 'Y-m-d' + * @return array 包含 year, month 和 season 的数组 + */ + private static function extractDateDetails($date) + { + $dateObj = new DateTime($date); // 将日期字符串转换为 DateTime 对象 + + // 提取年和月 + $year = (int)$dateObj->format('Y'); + $month = (int)$dateObj->format('m'); + + // 计算季度 + if ($month >= 1 && $month <= 3) { + $season = (int)$dateObj->format('Ym') . '01'; // Q1 + } elseif ($month >= 4 && $month <= 6) { + $season = (int)$dateObj->format('Ym') . '02'; // Q2 + } elseif ($month >= 7 && $month <= 9) { + $season = (int)$dateObj->format('Ym') . '03'; // Q3 + } else { + $season = (int)$dateObj->format('Ym') . '04'; // Q4 + } + + return [ + 'year' => $year, + 'month' => $month, + 'season' => $season + ]; + } + + /** * This example updates the CPC bid and status for a given ad group. To get ad groups, run * GetAdAds.php. diff --git a/app/service/GoogleAdsCampaignService.php b/app/service/GoogleAdsCampaignService.php index dae2a8d..d4a5f93 100644 --- a/app/service/GoogleAdsCampaignService.php +++ b/app/service/GoogleAdsCampaignService.php @@ -304,6 +304,14 @@ class GoogleAdsCampaignService extends BaseService public static function getDateDatas(GoogleAdsClient $googleAdsClient, int $customerId, $date = '2024-12-19') { + // 调用私有方法提取 year, month, season + $dateDetails = self::extractDateDetails($date); + + $year = $dateDetails['year']; + $month = $dateDetails['month']; + $season = $dateDetails['season']; + + $googleAdsServiceClient = $googleAdsClient->getGoogleAdsServiceClient(); // Creates a query that retrieves all campaigns. @@ -331,12 +339,51 @@ class GoogleAdsCampaignService extends BaseService $resourceName['conversions_value'] = $googleAdsRow->getMetrics()->getConversionsValue(); $resourceName['impressions'] = $googleAdsRow->getMetrics()->getImpressions(); $resourceName['date'] = $date; + $resourceName['month'] = $month; + $resourceName['season'] = $season; + $resourceName['year'] = $year; + + + // $resourceName['budget_id'] = $googleAdsRow->getCampaignBudget()->getId(); $resourceNames[] = $resourceName; } return $resourceNames; } + + /** + * 从日期字符串中提取年、月、季节信息,并返回这些信息 + * + * @param string $date 日期,格式为 'Y-m-d' + * @return array 包含 year, month 和 season 的数组 + */ + private static function extractDateDetails($date) + { + $dateObj = new DateTime($date); // 将日期字符串转换为 DateTime 对象 + + // 提取年和月 + $year = (int) $dateObj->format('Y'); + $month = (int) $dateObj->format('m'); + + // 计算季度 + if ($month >= 1 && $month <= 3) { + $season = (int) $dateObj->format('Ym') . '01'; // Q1 + } elseif ($month >= 4 && $month <= 6) { + $season = (int) $dateObj->format('Ym') . '02'; // Q2 + } elseif ($month >= 7 && $month <= 9) { + $season = (int) $dateObj->format('Ym') . '03'; // Q3 + } else { + $season = (int) $dateObj->format('Ym') . '04'; // Q4 + } + + return [ + 'year' => $year, + 'month' => $month, + 'season' => $season + ]; + } + /** * Runs the example. * @@ -395,9 +442,9 @@ class GoogleAdsCampaignService extends BaseService // ThinkDb::execute($sql, $data); $sql = "INSERT INTO bps.bps_google_ad_day_data - (ad_id, customer_id, ad_name, ad_resource_name, ad_group_id, campaign_id, clicks, cost_micros, conversions, conversions_value, impressions, date) - VALUES (:ad_id, :customer_id, :ad_name, :ad_resource_name, :ad_group_id, :campaign_id, :clicks, :cost_micros, :conversions, :conversions_value, :impressions, :date) - ON CONFLICT (ad_id, date) -- 假设 (ad_id, date) 为唯一约束 + (ad_id, customer_id, ad_name, ad_resource_name, ad_group_id, campaign_id, clicks, cost_micros, conversions, conversions_value, impressions, date, month, season, year) + VALUES (:ad_id, :customer_id, :ad_name, :ad_resource_name, :ad_group_id, :campaign_id, :clicks, :cost_micros, :conversions, :conversions_value, :impressions, :date, :month, :season, :year) + ON CONFLICT (ad_id, date) -- 假设 (ad_id, date) 为唯一约束 DO UPDATE SET customer_id = EXCLUDED.customer_id, ad_name = EXCLUDED.ad_name, @@ -409,6 +456,9 @@ class GoogleAdsCampaignService extends BaseService conversions = EXCLUDED.conversions, conversions_value = EXCLUDED.conversions_value, impressions = EXCLUDED.impressions, + month = EXCLUDED.month, + season = EXCLUDED.season, + year = EXCLUDED.year, update_at = EXCLUDED.update_at"; // 更新其他字段和更新时间戳 ThinkDb::execute($sql, $data); diff --git a/app/service/GoogleAdsReportService.php b/app/service/GoogleAdsReportService.php index 70df58a..bcd3d6a 100644 --- a/app/service/GoogleAdsReportService.php +++ b/app/service/GoogleAdsReportService.php @@ -6,10 +6,12 @@ use app\model\Ad; use app\model\DayData; use app\model\Campaign; use app\model\AdGroup; +use app\model\Asset; +use app\model\AssetRelation; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Writer\Xlsx; use think\db\exception\DbException; -use think\facade\Db; +use think\facade\Db as ThinkDb; use think\model\Collection; class GoogleAdsReportService @@ -603,4 +605,294 @@ class GoogleAdsReportService } } + + /** + * 获取广告资产报告 + * + * @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($customerId, $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 . '%'); // 关键词模糊匹配 + } + }); + $adIdsQuery->where('a.customer_id', '=', $customerId); + // 日期范围处理,筛选 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])) { + // 获取 asset 相关信息,通过模型查询 Asset + $asset = Asset::find($assetRelation->asset_id); // 根据 asset_id 查找对应的 Asset 数据 + + $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' + } + + // 累加该 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; // 避免除以零 + } + } + } + + // 5. 格式化输出数据 + // 生成最终输出的数据 + $resultData = []; + $chat_data = []; + foreach ($assetSummaryData as $assetId => $data) { + // 计算 ROAS + $roas = $data['total_spend'] ? ($data['total_conversions_value'] / $data['total_spend']) * 100 : 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) . '%', + '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']; + + } + + + } + + // 计算每个月的总 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) * 100 : 0; + // 格式化 ROAS 为百分比 + $chat_data[$month]['roas'] = number_format($chat_data[$month]['roas'], 2) . '%'; + } + + // 返回分页数据 + $resultDataPaginated = array_slice($resultData, ($page - 1) * $pageSize, $pageSize); + + return [ + 'data' => $resultDataPaginated, + 'chat_1_data' => array_values($chat_data), // 返回按月汇总的 chat_data + 'total' => count($resultData), + 'current_page' => (int)$page, + 'last_page' => ceil(count($resultData) / $pageSize), + ]; + } + } diff --git a/config/route.php b/config/route.php index 35206ae..0735672 100644 --- a/config/route.php +++ b/config/route.php @@ -63,6 +63,11 @@ Route::group('/googleads', function () { })->middleware([ app\middleware\OauthCheck::class, ]); + Route::group('/asset', function () { + Route::post('/list', [AdController::class, 'listAssets']); + })->middleware([ + app\middleware\OauthCheck::class, + ]); Route::group('/auth', function () { Route::get('/code', [OAuthController::class, 'getAuthCode']);