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 [ '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) { $onCondition .= " AND d.date BETWEEN '{$startDate}' AND '{$endDate}'"; } else { switch ($dateRange) { case 'Today': $onCondition .= " AND d.date = '" . date('Y-m-d') . "'"; break; case 'Yesterday': $onCondition .= " AND d.date = '" . date('Y-m-d', strtotime('-1 day')) . "'"; break; case 'Last Week': $onCondition .= " AND d.date >= '" . date('Y-m-d', strtotime('-1 week')) . "'"; break; case 'Last Month': $onCondition .= " AND d.date >= '" . date('Y-m-d', strtotime('-1 month')) . "'"; break; case 'Last Year': $onCondition .= " AND d.date >= '" . date('Y-m-d', strtotime('-1 year')) . "'"; break; default: break; } } // 添加 LEFT JOIN 日数据表 $query->leftJoin('bps.bps_google_ad_day_data d', $onCondition); // 添加字段、分组和查询条件 $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, a.metadata') // Include metadata field ->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) { // if ($keyword) { // $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) { // Extract square marketing images from metadata // Extract square marketing images from metadata $metadata = $item['metadata']; // 如果是对象,转换为数组 if (is_object($metadata)) { $metadata = (array)$metadata; } $imageUrls = isset($metadata['square_marketing_images']) ? $metadata['square_marketing_images'] : []; // Extract asset_id from the image URL $assetId = 0; if (!empty($imageUrls)) { // Example: "customers/8452924576/assets/191936503309" $imagePath = $imageUrls[0]; // Get the last element preg_match('/assets\/(\d+)/', $imagePath, $matches); if (isset($matches[1])) { $assetId = $matches[1]; } } // Query the asset_url from the bps_google_ads_asset table $assetUrl = ''; if ($assetId) { $asset = Asset::find($assetId); if ($asset) { $assetUrl = $asset['asset_url']; } } return [ 'id' => $item['ad_id'], 'customer_id' => $item['customer_id'], 'ad_group_id' => $item['ad_group_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['ad_status'], 'delivery_status' => '-', // Assuming active as '活动' 'be_roas' => $item['be_roas'] == -1 ? '-' : $item['be_roas'], 'image_url' => $assetUrl, // Add logic to populate image URLs if available ]; }, $ads->items()); // 汇总统计数据 // $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 [ 'pagination' => $pagination, 'statistics' => $statistics, 'data' => $result, ]; } /** * 导出广告列表到 Excel * * @param string $keyword * @param string $dateRange * @return void */ public static function exportAdListToExcel($customerIds,$keyword, $dateRange, $startDate = null, $endDate = null) { if (empty($customerIds)) { return []; } // 基础查询:广告表和日数据表联接 $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'); // 关联广告系列表 // 动态拼接 LEFT JOIN 的 ON 条件 $onCondition = 'a.ad_id = d.ad_id'; if ($startDate && $endDate) { $onCondition .= " AND d.date BETWEEN '{$startDate}' AND '{$endDate}'"; } else { switch ($dateRange) { case 'Today': $onCondition .= " AND d.date = '" . date('Y-m-d') . "'"; break; case 'Yesterday': $onCondition .= " AND d.date = '" . date('Y-m-d', strtotime('-1 day')) . "'"; break; case 'Last Week': $onCondition .= " AND d.date >= '" . date('Y-m-d', strtotime('-1 week')) . "'"; break; case 'Last Month': $onCondition .= " AND d.date >= '" . date('Y-m-d', strtotime('-1 month')) . "'"; break; case 'Last Year': $onCondition .= " AND d.date >= '" . date('Y-m-d', strtotime('-1 year')) . "'"; break; default: break; } } // 添加 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, -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('a.customer_id', 'in', $customerIds) ->where(function ($query) use ($keyword) { // if ($keyword) { // $query->where('a.ad_name', 'like', '%' . $keyword . '%'); // } }); // 获取所有广告数据 $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($customerIds, $page, $pageSize, $keyword, $dateRange, $startDate = null, $endDate = null) { // 检查 customerIds 是否为空,直接返回空结构 if (empty($customerIds)) { return [ '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'], 'customer_id' => $item['customer_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['campaign_status'], '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 [ 'pagination' => $pagination, 'statistics' => $statistics, 'data' => $result, ]; } /** * 获取广告系列列表 */ public static function getCampaignList1111($page, $pageSize, $keyword, $dateRange, $startDate = null, $endDate = null) { // 动态构建日期条件 $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') ->leftJoin('bps.bps_google_ad_day_data d', "c.campaign_id = d.campaign_id AND {$dateCondition}") // 将日期条件加入到 ON 子句中 ->field('c.campaign_id, c.status as campaign_status, c.campaign_name, c.customer_id, 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, -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 . '%'); } }); // 获取分页数据 $campaigns = $query->paginate($pageSize, false, ['page' => $page]); // 确保转换为数值 $result = array_map(function ($item) { $item['spend'] = (float)$item['spend']; $item['conversions_value'] = (float)$item['conversions_value']; return $item; }, $campaigns->items()); // 返回分页和总数信息 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 function exportCampaignsToExcel($customerIds,$keyword, $dateRange, $startDate = null, $endDate = null) { if(empty($customerIds)){ return []; } // 动态构建日期条件 $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') ->leftJoin('bps.bps_google_ad_day_data d', "c.campaign_id = d.campaign_id AND {$dateCondition}") // 将日期条件加入到 ON 子句中 ->field('c.campaign_id, c.status as campaign_status, c.campaign_name, c.customer_id, 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, -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) ->where(function ($query) use ($keyword) { if ($keyword) { $query->where('c.campaign_name', 'like', '%' . $keyword . '%'); } }); // 获取所有广告系列数据 $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($customerIds, $page, $pageSize, $keyword, $dateRange, $startDate = null, $endDate = null) { // 检查 customerIds 是否为空,直接返回空结构 if (empty($customerIds)) { return [ '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'], 'customer_id' => $item['customer_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 [ 'pagination' => $pagination, 'statistics' => $statistics, 'data' => $result, ]; } /** * 获取广告系列列表 */ public static function getAdGroupList1111($page, $pageSize, $keyword, $dateRange, $startDate = null, $endDate = null) { // 动态构建日期条件 $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), -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, -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 . '%'); } }); // 获取分页数据 $adGroups = $query->paginate($pageSize, false, ['page' => $page]); // 确保转换为数值 $result = array_map(function ($item) { $item['spend'] = (float)$item['spend']; $item['conversions_value'] = (float)$item['conversions_value']; return $item; }, $adGroups->items()); // 返回分页和总数信息 return [ 'data' => $adGroups->items(), 'total' => $adGroups->total(), 'current_page' => $adGroups->currentPage(), 'last_page' => $adGroups->lastPage(), ]; } /** * 将广告组数据导出到 Excel 文件 */ public function exportAdGroupsToExcel($customerIds,$keyword = '', $dateRange = 'Today', $startDate = null, $endDate = null) { if(empty($customerIds)){ return []; } // 动态构建日期条件 $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), -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, -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 . '%'); } }); // 获取所有广告组数据 $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()]; } } /** * 获取广告资产报告 * * @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($customerIds, $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 . '%'); // 关键词模糊匹配 } }); // 如果提供了 customerIds,增加查询条件 if (!empty($customerIds)) { $adIdsQuery->whereIn('a.customer_id', $customerIds); // 添加 customer_id 的查询约束 } else { return [ 'data' => [], 'chat_1_data' => [], // 返回按月汇总的 chat_data 'total' => 0, 'current_page' => 1, 'last_page' => 1, ]; } // 日期范围处理,筛选 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), ]; } }