1566 lines
		
	
	
		
			80 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			1566 lines
		
	
	
		
			80 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						||
 | 
						||
namespace app\service;
 | 
						||
 | 
						||
use app\model\Ad;
 | 
						||
use app\model\BpsAdCreativeInsight;
 | 
						||
use app\model\BpsAdInsight;
 | 
						||
use app\model\DayData;
 | 
						||
use app\model\Campaign;
 | 
						||
use app\model\BpsAdCampaign;
 | 
						||
use app\model\BpsAdSet;
 | 
						||
use app\model\BpsAdAd;
 | 
						||
use app\model\ThirdUser;
 | 
						||
use app\model\Asset;
 | 
						||
use app\model\AssetRelation;
 | 
						||
use app\model\ThirdUserAdvertiser;
 | 
						||
use DateTime;
 | 
						||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
 | 
						||
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
 | 
						||
use think\db\exception\DbException;
 | 
						||
use think\facade\Db as ThinkDb;
 | 
						||
use support\Redis;
 | 
						||
 | 
						||
class AdsInsightService
 | 
						||
{
 | 
						||
    // 状态映射数组
 | 
						||
    private static $statusMapping = [
 | 
						||
        2 => 'ENABLE',    // 2 代表广告已启用
 | 
						||
        3 => 'PAUSED',   // 3 代表广告待审核等状态
 | 
						||
        // 其他状态可以继续添加
 | 
						||
    ];
 | 
						||
 | 
						||
    // Redis 键名前缀
 | 
						||
    const REDIS_KEY_PREFIX = 'ad_data_count:';
 | 
						||
 | 
						||
    /**
 | 
						||
     * 获取广告数据的各项总数(统一接口)
 | 
						||
     *
 | 
						||
     * @param array $customerIds 客户 ID 数组
 | 
						||
     * @return array 各项 count 统计数据
 | 
						||
     */
 | 
						||
    public static function getAdCountData($customerIds, $startDate, $endDate)
 | 
						||
    {
 | 
						||
        if (empty($customerIds)) {
 | 
						||
            return [];
 | 
						||
        }
 | 
						||
        // 生成唯一的哈希键
 | 
						||
        $hashKey  = self::generateHashKey($customerIds);
 | 
						||
        $redisKey = self::REDIS_KEY_PREFIX . $hashKey;
 | 
						||
 | 
						||
        // 尝试从 Redis 中获取缓存值
 | 
						||
        $cachedData = Redis::get($redisKey);
 | 
						||
        if (!empty($cachedData)) {
 | 
						||
            return json_decode($cachedData, true);
 | 
						||
        }
 | 
						||
 | 
						||
        // 没有缓存时重新计算
 | 
						||
        $countData = self::calculateCountData($customerIds, $startDate, $endDate);
 | 
						||
 | 
						||
        // 缓存到 Redis,有效期 10 分钟
 | 
						||
        Redis::setex($redisKey, 600, json_encode($countData));
 | 
						||
 | 
						||
        return $countData;
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    /**
 | 
						||
     * 计算广告数据的 count
 | 
						||
     */
 | 
						||
    protected static function calculateCountData(array $customerIds, $startDate, $endDate)
 | 
						||
    {
 | 
						||
        if (!$startDate || !$endDate) {
 | 
						||
            [$startDate, $endDate] = self::getLastWeekDateRange();
 | 
						||
        }
 | 
						||
        return [
 | 
						||
            'account_list_count' => self::getAccountListCount($customerIds, $startDate, $endDate),
 | 
						||
            'campaign_list_count' => self::getCampaignListCount($customerIds, $startDate, $endDate),
 | 
						||
            'adset_list_count' => self::getAdsetListCount($customerIds, $startDate, $endDate),
 | 
						||
            'ad_list_count' => self::getAdListCount($customerIds, $startDate, $endDate),
 | 
						||
            'creative_list_count' => self::getCreativeListCount($customerIds, $startDate, $endDate),
 | 
						||
        ];
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 生成 Redis 键的唯一哈希值
 | 
						||
     */
 | 
						||
    protected static function generateHashKey(array $customerIds)
 | 
						||
    {
 | 
						||
        sort($customerIds);
 | 
						||
        return md5(json_encode($customerIds));
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 获取广告列表的 count
 | 
						||
     */
 | 
						||
    protected static function getAdListCount(array $customerIds, $startDate, $endDate)
 | 
						||
    {
 | 
						||
        return self::getAdList(0, $customerIds, 1, 1, '', $startDate, $endDate, 0, true);
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 获取广告系列列表的 count
 | 
						||
     */
 | 
						||
    protected static function getCampaignListCount(array $customerIds, $startDate, $endDate)
 | 
						||
    {
 | 
						||
        return self::getCampaignList(0, $customerIds, 1, 1, '', $startDate, $endDate, 0, true);
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 获取广告组列表的 count
 | 
						||
     */
 | 
						||
    protected static function getAdsetListCount(array $customerIds, $startDate, $endDate)
 | 
						||
    {
 | 
						||
        return self::getAdsetList(0, $customerIds, 1, 1, '', $startDate, $endDate, 0, true);
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 获取账户列表的 count
 | 
						||
     */
 | 
						||
    protected static function getAccountListCount(array $customerIds, $startDate, $endDate)
 | 
						||
    {
 | 
						||
        return self::getAccountList(0, $customerIds, 1, 1, '', $startDate, $endDate, true);
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 获取账户列表的 count
 | 
						||
     */
 | 
						||
    protected static function getCreativeListCount(array $customerIds, $startDate, $endDate)
 | 
						||
    {
 | 
						||
        return self::getCreativeInsightData(0, $customerIds, 1, 1, '', $startDate, $endDate, true);
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 获取最近 7 天的起始和结束日期
 | 
						||
     */
 | 
						||
    protected static function getLastWeekDateRange()
 | 
						||
    {
 | 
						||
        $endDate   = (int)date('Ymd');
 | 
						||
        $startDate = (int)date('Ymd', strtotime('-6 days'));
 | 
						||
        return [$startDate, $endDate];
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    /**
 | 
						||
     * 获取广告系列列表
 | 
						||
     */
 | 
						||
    public static function getCampaignList($platformType, $customerIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null, $status = 0, $countOnly = false)
 | 
						||
    {
 | 
						||
        // 检查 customerIds 是否为空,直接返回空结构
 | 
						||
        if (empty($customerIds)) {
 | 
						||
            return $countOnly ? 0 : [
 | 
						||
                'pagination' => [
 | 
						||
                    'startIndex' => 0,
 | 
						||
                    'maxResults' => 0,
 | 
						||
                    'count' => 0,
 | 
						||
                    'pageNo' => $page,
 | 
						||
                    'pageSize' => $pageSize,
 | 
						||
                    'pages' => 0,
 | 
						||
                ],
 | 
						||
                'statistics' => [],
 | 
						||
                'data' => [],
 | 
						||
            ];
 | 
						||
        }
 | 
						||
 | 
						||
        // 基础查询:广告活动和日数据表联接
 | 
						||
        $query = BpsAdCampaign::alias('c')
 | 
						||
            ->cache(false) // 强制不使用缓存
 | 
						||
            ->where('c.account_id', 'in', $customerIds);
 | 
						||
        // 如果只需要记录条数,执行计数查询
 | 
						||
        if ($countOnly) {
 | 
						||
            return $query->count();
 | 
						||
        }
 | 
						||
 | 
						||
        // 动态构建日期条件
 | 
						||
        $dateCondition = '';
 | 
						||
        if ($startDate && $endDate) {
 | 
						||
            $query->leftJoin('bps.bps_ads_insights d', "c.campaign_id = d.ad_campaign_id AND c.platform_type = d.platform AND {$dateCondition}");
 | 
						||
            $dateCondition = "d.date BETWEEN '{$startDate}' AND '{$endDate}'";
 | 
						||
        } else {
 | 
						||
        }
 | 
						||
        $query->leftJoin('bps.bps_ads_insights d', "c.campaign_id = d.ad_campaign_id AND c.platform_type = d.platform AND {$dateCondition}")
 | 
						||
            ->field('c.campaign_id, c.status as status, c.name, c.account_id,c.platform_type,
 | 
						||
             COALESCE(SUM(d.assisted_purchases), 0) as assisted_purchases,
 | 
						||
             COALESCE(SUM(d.last_clicked_purchases), 0) as last_clicked_purchases,
 | 
						||
             COALESCE(SUM(d.clicks), 0) as clicks,
 | 
						||
             COALESCE(SUM(d.spend) / 1000000, 0) as spend,
 | 
						||
             COALESCE(SUM(d.impressions), 0) as impressions,
 | 
						||
             COALESCE(SUM(d.adds_to_cart), 0) as adds_to_cart,
 | 
						||
             COALESCE(SUM(d.cost_per_atc), 0) as cost_per_atc,
 | 
						||
             COALESCE(SUM(d.purchases), 0) as purchases,
 | 
						||
             COALESCE(SUM(d.purchases_value / 1000000), 0) as purchases_value,
 | 
						||
             COALESCE(SUM(d.revenue / 1000000), 0) as revenue,
 | 
						||
             COALESCE(SUM(d.total_cost / 1000000), 0) as total_cost,
 | 
						||
             -1 as conversion_rate, -1 as roas, -1 as ctr,-1 as net_profit,-1 as net_profit_margin,-1 as net_profit_on_ad_spend')
 | 
						||
            ->group('c.campaign_id, c.status, c.account_id, c.name,c.platform_type')
 | 
						||
            ->where('c.account_id', 'in', $customerIds); // 添加 customerIds 条件
 | 
						||
        if ($status !== 0) {
 | 
						||
            $query->where('c.status', '=', $status);
 | 
						||
        }
 | 
						||
        // 添加关键字过滤条件
 | 
						||
        $query->where(function ($query) use ($keyword, $platformType) {
 | 
						||
            if ($keyword) {
 | 
						||
                $query->whereRaw('LOWER(c.name) LIKE ?', ['%' . strtolower($keyword) . '%']);
 | 
						||
            }
 | 
						||
            if ($platformType) {
 | 
						||
                $platformType = (int)$platformType;
 | 
						||
                $query->where('c.platform_type', '=', $platformType);
 | 
						||
            }
 | 
						||
        });
 | 
						||
 | 
						||
        // 获取所有符合条件的数据(不分页)
 | 
						||
        $allCampaigns = $query->select()->toArray();
 | 
						||
 | 
						||
        $total_spend           = array_sum(array_column($allCampaigns, 'spend'));
 | 
						||
        $total_cost            = array_sum(array_column($allCampaigns, 'total_cost'));
 | 
						||
        $total_impressions     = array_sum(array_column($allCampaigns, 'impressions'));
 | 
						||
        $total_clicks          = array_sum(array_column($allCampaigns, 'clicks'));
 | 
						||
        $total_purchases_value = array_sum(array_column($allCampaigns, 'purchases_value'));
 | 
						||
        $total_revenue         = array_sum(array_column($allCampaigns, 'revenue'));
 | 
						||
        $total_purchases       = array_sum(array_column($allCampaigns, 'purchases'));
 | 
						||
        $cost_per_purchase     = $total_purchases == 0 ? 0 : round($total_spend / $total_purchases, 2);
 | 
						||
        // 汇总统计数据
 | 
						||
        $statistics = [
 | 
						||
            'assisted_purchases' => array_sum(array_column($allCampaigns, 'assisted_purchases')),
 | 
						||
            'last_clicked_purchases' => array_sum(array_column($allCampaigns, 'last_clicked_purchases')),
 | 
						||
            'roas' => $total_spend == 0 ? '-' : round($total_revenue / $total_spend, 2) . 'X',
 | 
						||
            'amount_spend' => '$' . number_format($total_spend, 2) ?: '$0.00', // 格式化支出
 | 
						||
            'clicks' => $total_clicks,
 | 
						||
            'impressions' => $total_impressions,
 | 
						||
            'adds_to_cart' => array_sum(array_column($allCampaigns, 'adds_to_cart')),
 | 
						||
            'cost_per_atc' => array_sum(array_column($allCampaigns, 'cost_per_atc')),
 | 
						||
            'purchases' => array_sum(array_column($allCampaigns, 'purchases')),
 | 
						||
            'purchases_value' => array_sum(array_column($allCampaigns, 'purchases_value')),
 | 
						||
            'cost_per_purchase' => '$' . number_format($cost_per_purchase, 2) ?: '$0.00',
 | 
						||
            'revenue' => '$' . number_format(array_sum(array_column($allCampaigns, 'revenue')), 2) ?: '$0.00', // 格式化收入
 | 
						||
            'total_cost' => '$' . number_format($total_cost, 2) ?: '$0.00', // 格式化总成本
 | 
						||
            'conversion_rate' => $total_clicks == 0 ? '-' : round(($total_purchases / $total_clicks) * 100, 2) . '%',  // 转换率
 | 
						||
            'net_profit' => ($total_revenue - $total_cost) >= 0 ? '+$' . number_format($total_revenue - $total_cost, 2) : '-$' . number_format(abs($total_revenue - $total_cost), 2),  // 净利润
 | 
						||
            'net_profit_margin' => $total_revenue == 0 ? '-' : round(($total_revenue - $total_cost) / $total_revenue, 2) * 100 . '%',  // 净利润率
 | 
						||
            'net_profit_on_ad_spend' => $total_spend == 0 ? '-' : round(($total_revenue - $total_cost) / $total_spend, 2) * 100 . '%', // 广告支出净利润
 | 
						||
            // 计算总的 CTR
 | 
						||
            'ctr' => ($total_impressions > 0) ? number_format(($total_clicks / $total_impressions) * 100, 2) . '%' : '-',  // 格式化为百分比
 | 
						||
        ];
 | 
						||
 | 
						||
        // 获取分页数据
 | 
						||
//        $campaigns = $query->paginate($pageSize, false, ['page' => $page]);
 | 
						||
        // 获取分页数据
 | 
						||
        $page = max(1, (int)$page); // 确保页码不小于 1
 | 
						||
//             $ads = $query->page($page, $pageSize)->select();
 | 
						||
        $campaigns = $query->limit(($page - 1) * $pageSize, $pageSize)->select();
 | 
						||
 | 
						||
        // 确保数据格式统一
 | 
						||
        $result = array_map(function ($item) {
 | 
						||
            // CTR 的计算:点击率 = 点击数 / 展示数
 | 
						||
            $ctr = $item['impressions'] > 0 ? number_format(($item['clicks'] / $item['impressions']) * 100, 2) . '%' : '-';
 | 
						||
            // Conversion Rate 的计算:转换率 = 购买数 / 点击数
 | 
						||
            $conversion_rate = $item['clicks'] > 0 ? round(($item['purchases'] / $item['clicks']) * 100, 2) . '%' : '-';
 | 
						||
            // Net Profit 的计算:净利润 = 收入 - 总成本
 | 
						||
            $net_profit = ($item['revenue'] - $item['total_cost']) >= 0 ? '+$' . number_format($item['revenue'] - $item['total_cost'], 2) : '-$' . number_format(abs($item['revenue'] - $item['total_cost']), 2);
 | 
						||
            // Net Profit Margin 的计算:净利润率 = 净利润 / 收入
 | 
						||
            $net_profit_margin = $item['revenue'] > 0 ? round(($item['revenue'] - $item['total_cost']) / $item['revenue'], 2) * 100 . '%' : '-';
 | 
						||
            // Net Profit on Ad Spend 的计算:广告支出净利润 = (收入 - 总成本) / 广告支出
 | 
						||
            $net_profit_on_ad_spend = $item['spend'] > 0 ? round(($item['revenue'] - $item['total_cost']) / $item['spend'], 2) * 100 . '%' : '-';
 | 
						||
            return [
 | 
						||
                'id' => $item['campaign_id'],
 | 
						||
                'platform_type' => $item['platform_type'],
 | 
						||
                'account_id' => $item['account_id'],  // 映射为 customer_id
 | 
						||
                'name' => $item['name'] ?: '-',  // 若 name 为空则显示 '-'
 | 
						||
                'status' => $item['status'],
 | 
						||
                'assisted_purchases' => $item['assisted_purchases'],
 | 
						||
                'last_clicked_purchases' => $item['last_clicked_purchases'],
 | 
						||
                'roas' => $item['spend'] == 0 ? '-' : round($item['revenue'] / $item['spend'], 2) . 'X',
 | 
						||
                'spend' => '$' . number_format($item['spend'], 2),  // 格式化支出
 | 
						||
                'impressions' => $item['impressions'],
 | 
						||
                'clicks' => $item['clicks'],
 | 
						||
                'ctr' => $ctr,  // CTR 字段
 | 
						||
                'adds_to_cart' => $item['adds_to_cart'],
 | 
						||
                'cost_per_atc' => $item['cost_per_atc'],
 | 
						||
                'purchases' => $item['purchases'],
 | 
						||
                'purchases_value' => '$' . number_format($item['purchases_value'], 2),  // 格式化购买金额
 | 
						||
                'cost_per_purchase' => $item['purchases'] > 0 ? '$' . number_format(($item['spend'] / $item['purchases']), 2) : '$0.00',
 | 
						||
                'revenue' => '$' . number_format($item['revenue'], 2),  // 格式化收入
 | 
						||
                'total_cost' => '$' . number_format($item['total_cost'], 2),  // 格式化总成本
 | 
						||
                'conversion_rate' => $conversion_rate,
 | 
						||
                'net_profit' => $net_profit,
 | 
						||
                'net_profit_margin' => $net_profit_margin,
 | 
						||
                'net_profit_on_ad_spend' => $net_profit_on_ad_spend,
 | 
						||
            ];
 | 
						||
        }, $campaigns->toArray());
 | 
						||
 | 
						||
        // Pagination 数据
 | 
						||
        $pagination = [
 | 
						||
            'startIndex' => ($page - 1) * $pageSize + 1, // 确保索引从 1 开始
 | 
						||
            'maxResults' => count($campaigns),               // 当前页实际返回数据数量
 | 
						||
            'count' => count($allCampaigns),            // 符合条件的总记录数
 | 
						||
            'pageNo' => $page,                         // 当前页码
 | 
						||
            'pageSize' => $pageSize,                   // 每页条数
 | 
						||
            'pages' => (int)ceil(count($allCampaigns) / $pageSize), // 总页数
 | 
						||
        ];
 | 
						||
 | 
						||
        return [
 | 
						||
            'pagination' => $pagination,
 | 
						||
            'statistics' => $statistics,
 | 
						||
            'data' => $result,
 | 
						||
        ];
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 获取广告组列表
 | 
						||
     */
 | 
						||
    public static function getAdsetList($platformType, $customerIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null, $status = 0, $countOnly = false)
 | 
						||
    {
 | 
						||
        // 检查 customerIds 是否为空,直接返回空结构
 | 
						||
        if (empty($customerIds)) {
 | 
						||
            return $countOnly ? 0 : [
 | 
						||
                'pagination' => [
 | 
						||
                    'startIndex' => 0,
 | 
						||
                    'maxResults' => 0,
 | 
						||
                    'count' => 0,
 | 
						||
                    'pageNo' => $page,
 | 
						||
                    'pageSize' => $pageSize,
 | 
						||
                    'pages' => 0,
 | 
						||
                ],
 | 
						||
                'statistics' => [],
 | 
						||
                'data' => [],
 | 
						||
            ];
 | 
						||
        }
 | 
						||
 | 
						||
        // 基础查询:广告活动和日数据表联接
 | 
						||
        $query = BpsAdSet::alias('s')
 | 
						||
            ->cache(false) // 强制不使用缓存
 | 
						||
            ->where('s.account_id', 'in', $customerIds);
 | 
						||
        // 如果只需要记录条数,执行计数查询
 | 
						||
        if ($countOnly) {
 | 
						||
            return $query->count();
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        // 动态构建日期条件
 | 
						||
        $dateCondition = '';
 | 
						||
        if ($startDate && $endDate) {
 | 
						||
            $dateCondition = "d.date BETWEEN '{$startDate}' AND '{$endDate}'";
 | 
						||
            $query->leftJoin('bps.bps_ads_insights d', "s.ad_set_id = d.ad_set_id AND s.platform_type = d.platform AND {$dateCondition}");
 | 
						||
        }
 | 
						||
 | 
						||
        // 基础查询:广告组和日数据表联接
 | 
						||
 | 
						||
        $query->leftJoin('bps.bps_ads_campaign c', 's.campaign_id = c.campaign_id') // 联接广告系列表
 | 
						||
        ->field('s.ad_set_id, s.status as status, s.name, s.account_id,s.platform_type,c.name as campaign_name,
 | 
						||
            COALESCE(SUM(d.assisted_purchases), 0) as assisted_purchases,
 | 
						||
            COALESCE(SUM(d.last_clicked_purchases), 0) as last_clicked_purchases,
 | 
						||
            COALESCE(SUM(d.clicks), 0) as clicks,
 | 
						||
            COALESCE(SUM(d.spend) / 1000000, 0) as spend,
 | 
						||
            COALESCE(SUM(d.impressions), 0) as impressions,
 | 
						||
            COALESCE(SUM(d.adds_to_cart), 0) as adds_to_cart,
 | 
						||
            COALESCE(SUM(d.cost_per_atc), 0) as cost_per_atc,
 | 
						||
            COALESCE(SUM(d.purchases), 0) as purchases,
 | 
						||
            COALESCE(SUM(d.purchases_value / 1000000), 0) as purchases_value,
 | 
						||
            COALESCE(SUM(d.revenue / 1000000), 0) as revenue,
 | 
						||
            COALESCE(SUM(d.total_cost / 1000000), 0) as total_cost,
 | 
						||
            -1 as conversion_rate, -1 as roas, -1 as ctr,-1 as net_profit,-1 as net_profit_margin,-1 as net_profit_on_ad_spend')
 | 
						||
            ->group('s.ad_set_id, s.status, s.account_id, s.name,s.platform_type,c.name')
 | 
						||
            ->where('s.account_id', 'in', $customerIds); // 添加 customerIds 条件
 | 
						||
        if ($status !== 0) {
 | 
						||
            $query->where('s.status', '=', $status);
 | 
						||
        }
 | 
						||
 | 
						||
        // 添加关键字过滤条件
 | 
						||
        $query->where(function ($query) use ($keyword, $platformType) {
 | 
						||
            if ($keyword) {
 | 
						||
//                $query->where('s.name', 'like', '%' . $keyword . '%');
 | 
						||
                $query->whereRaw('LOWER(s.name) LIKE ?', ['%' . strtolower($keyword) . '%']);
 | 
						||
            }
 | 
						||
            if ($platformType) {
 | 
						||
                $platformType = (int)$platformType;
 | 
						||
                $query->where('s.platform_type', '=', $platformType);
 | 
						||
            }
 | 
						||
        });
 | 
						||
 | 
						||
        // 获取所有符合条件的数据(不分页)
 | 
						||
        $allAdsets = $query->select()->toArray();
 | 
						||
 | 
						||
        $total_spend           = array_sum(array_column($allAdsets, 'spend'));
 | 
						||
        $total_cost            = array_sum(array_column($allAdsets, 'total_cost'));
 | 
						||
        $total_impressions     = array_sum(array_column($allAdsets, 'impressions'));
 | 
						||
        $total_clicks          = array_sum(array_column($allAdsets, 'clicks'));
 | 
						||
        $total_purchases_value = array_sum(array_column($allAdsets, 'purchases_value'));
 | 
						||
        $total_revenue         = array_sum(array_column($allAdsets, 'revenue'));
 | 
						||
        $total_purchases       = array_sum(array_column($allAdsets, 'purchases'));
 | 
						||
        $cost_per_purchase     = $total_purchases == 0 ? 0 : round($total_spend / $total_purchases, 2);
 | 
						||
 | 
						||
        // 汇总统计数据
 | 
						||
        $statistics = [
 | 
						||
            'assisted_purchases' => array_sum(array_column($allAdsets, 'assisted_purchases')),
 | 
						||
            'last_clicked_purchases' => array_sum(array_column($allAdsets, 'last_clicked_purchases')),
 | 
						||
            'roas' => $total_spend == 0 ? '-' : round($total_revenue / $total_spend, 2) . 'X',
 | 
						||
            'amount_spend' => '$' . number_format($total_spend, 2) ?: '$0.00', // 格式化支出
 | 
						||
            'clicks' => $total_clicks,
 | 
						||
            'impressions' => array_sum(array_column($allAdsets, 'impressions')),
 | 
						||
            'adds_to_cart' => array_sum(array_column($allAdsets, 'adds_to_cart')),
 | 
						||
            'cost_per_atc' => array_sum(array_column($allAdsets, 'cost_per_atc')),
 | 
						||
            'purchases' => array_sum(array_column($allAdsets, 'purchases')),
 | 
						||
            'purchases_value' => array_sum(array_column($allAdsets, 'purchases_value')),
 | 
						||
            'cost_per_purchase' => '$' . number_format($cost_per_purchase, 2) ?: '$0.00',
 | 
						||
            'revenue' => '$' . number_format(array_sum(array_column($allAdsets, 'revenue')), 2) ?: '$0.00', // 格式化收入
 | 
						||
            'total_cost' => '$' . number_format($total_cost, 2) ?: '$0.00', // 格式化总成本
 | 
						||
            'conversion_rate' => $total_clicks == 0 ? '-' : round(($total_purchases / $total_clicks) * 100, 2) . '%',  // 转换率
 | 
						||
            'net_profit' => ($total_revenue - $total_cost) >= 0 ? '+$' . number_format($total_revenue - $total_cost, 2) : '-$' . number_format(abs($total_revenue - $total_cost), 2),  // 净利润
 | 
						||
            'net_profit_margin' => $total_revenue == 0 ? '-' : round(($total_revenue - $total_cost) / $total_revenue, 2) * 100 . '%',  // 净利润率
 | 
						||
            'net_profit_on_ad_spend' => $total_spend == 0 ? '-' : round(($total_revenue - $total_cost) / $total_spend, 2) * 100 . '%', // 广告支出净利润
 | 
						||
            // 计算总的 CTR
 | 
						||
            'ctr' => ($total_impressions > 0) ? number_format(($total_clicks / $total_impressions) * 100, 2) . '%' : '-',  // 格式化为百分比
 | 
						||
        ];
 | 
						||
 | 
						||
        // 获取分页数据
 | 
						||
//        $adsets = $query->paginate($pageSize, false, ['page' => $page]);
 | 
						||
        $page   = max(1, (int)$page); // 确保页码不小于 1
 | 
						||
        $adsets = $query->limit(($page - 1) * $pageSize, $pageSize)->select();
 | 
						||
 | 
						||
        // 确保数据格式统一
 | 
						||
        $result = array_map(function ($item) {
 | 
						||
            // CTR 的计算:点击率 = 点击数 / 展示数
 | 
						||
            $ctr = $item['impressions'] > 0 ? number_format(($item['clicks'] / $item['impressions']) * 100, 2) . '%' : '-';
 | 
						||
            // Conversion Rate 的计算:转换率 = 购买数 / 点击数
 | 
						||
            $conversion_rate = $item['clicks'] > 0 ? round(($item['purchases'] / $item['clicks']) * 100, 2) . '%' : '-';
 | 
						||
            // Net Profit 的计算:净利润 = 收入 - 总成本
 | 
						||
            $net_profit = ($item['revenue'] - $item['total_cost']) >= 0 ? '+$' . number_format($item['revenue'] - $item['total_cost'], 2) : '-$' . number_format(abs($item['revenue'] - $item['total_cost']), 2);
 | 
						||
            // Net Profit Margin 的计算:净利润率 = 净利润 / 收入
 | 
						||
            $net_profit_margin = $item['revenue'] > 0 ? round(($item['revenue'] - $item['total_cost']) / $item['revenue'], 2) * 100 . '%' : '-';
 | 
						||
            // Net Profit on Ad Spend 的计算:广告支出净利润 = (收入 - 总成本) / 广告支出
 | 
						||
            $net_profit_on_ad_spend = $item['spend'] > 0 ? round(($item['revenue'] - $item['total_cost']) / $item['spend'], 2) * 100 . '%' : '-';
 | 
						||
            return [
 | 
						||
                'id' => $item['ad_set_id'],
 | 
						||
                'platform_type' => $item['platform_type'],
 | 
						||
                'account_id' => $item['account_id'],  // 映射为 customer_id
 | 
						||
                'name' => $item['name'] ?: '-',  // 若 name 为空则显示 '-'
 | 
						||
                'campaign_name' => $item['campaign_name'] ?: '-',  // 若 name 为空则显示 '-'
 | 
						||
                'status' => $item['status'],
 | 
						||
                'assisted_purchases' => $item['assisted_purchases'],
 | 
						||
                'last_clicked_purchases' => $item['last_clicked_purchases'],
 | 
						||
                'roas' => $item['spend'] == 0 ? '-' : round($item['purchases_value'] / $item['spend'], 2) . 'X',
 | 
						||
                'spend' => '$' . number_format($item['spend'], 2),  // 格式化支出
 | 
						||
                'impressions' => $item['impressions'],
 | 
						||
                'clicks' => $item['clicks'],
 | 
						||
                'ctr' => $ctr,  // CTR 字段
 | 
						||
                'adds_to_cart' => $item['adds_to_cart'],
 | 
						||
                'cost_per_atc' => $item['cost_per_atc'],
 | 
						||
                'purchases' => $item['purchases'],
 | 
						||
                'purchases_value' => '$' . number_format($item['purchases_value'], 2),  // 格式化购买金额
 | 
						||
                'cost_per_purchase' => $item['purchases'] > 0 ? '$' . number_format(($item['spend'] / $item['purchases']), 2) : '$0.00',
 | 
						||
                'revenue' => '$' . number_format($item['revenue'], 2),  // 格式化收入
 | 
						||
                'total_cost' => '$' . number_format($item['total_cost'], 2),  // 格式化总成本
 | 
						||
                'conversion_rate' => $conversion_rate,  // 没有提供有效的计算,保持为 '-'
 | 
						||
                'net_profit' => $net_profit,  // 没有提供 net_profit 计算,保持为 '-'
 | 
						||
                'net_profit_margin' => $net_profit_margin,  // 没有提供 net_profit_margin 计算,保持为 '-'
 | 
						||
                'net_profit_on_ad_spend' => $net_profit_on_ad_spend,  // 没有提供 net_profit_on_ad_spend 计算,保持为 '-'
 | 
						||
            ];
 | 
						||
        }, $adsets->toArray());
 | 
						||
 | 
						||
        // Pagination 数据
 | 
						||
        $pagination = [
 | 
						||
            'startIndex' => ($page - 1) * $pageSize + 1, // 确保索引从 1 开始
 | 
						||
            'maxResults' => count($adsets),               // 当前页实际返回数据数量
 | 
						||
            'count' => count($allAdsets),            // 符合条件的总记录数
 | 
						||
            'pageNo' => $page,                         // 当前页码
 | 
						||
            'pageSize' => $pageSize,                   // 每页条数
 | 
						||
            'pages' => (int)ceil(count($allAdsets) / $pageSize), // 总页数
 | 
						||
        ];
 | 
						||
 | 
						||
        return [
 | 
						||
            'pagination' => $pagination,
 | 
						||
            'statistics' => $statistics,
 | 
						||
            'data' => $result,
 | 
						||
        ];
 | 
						||
    }
 | 
						||
 | 
						||
    public static function getAccountList($platformType, $customerIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null, $countOnly = false)
 | 
						||
    {
 | 
						||
        // 检查 customerIds 是否为空,直接返回计数为 0
 | 
						||
        if (empty($customerIds)) {
 | 
						||
            return $countOnly ? 0 : [
 | 
						||
                'pagination' => [
 | 
						||
                    'startIndex' => 0,
 | 
						||
                    'maxResults' => $pageSize,
 | 
						||
                    'count' => 0,
 | 
						||
                    'pageNo' => $page,
 | 
						||
                    'pageSize' => $pageSize,
 | 
						||
                    'pages' => 0,
 | 
						||
                ],
 | 
						||
                'statistics' => [],
 | 
						||
                'data' => [],
 | 
						||
            ];
 | 
						||
        }
 | 
						||
        // 构建查询条件
 | 
						||
        $query = ThirdUserAdvertiser::alias('a')
 | 
						||
            ->cache(false)
 | 
						||
            ->where('a.advertiser_id', 'in', $customerIds);
 | 
						||
 | 
						||
        // 仅计数时优化查询
 | 
						||
        if ($countOnly) {
 | 
						||
            return $query->count(); // 只查询总记录数
 | 
						||
        }
 | 
						||
        // 动态构建日期条件
 | 
						||
        $dateCondition = '';
 | 
						||
        if ($startDate && $endDate) {
 | 
						||
            $dateCondition = "d.date BETWEEN '{$startDate}' AND '{$endDate}'";
 | 
						||
            $query->leftJoin('bps.bps_ads_insights d', "a.advertiser_id = d.account_id AND {$dateCondition}");
 | 
						||
        }
 | 
						||
 | 
						||
        // 基础查询:广告和日数据表联接
 | 
						||
        // 其他联表及字段计算
 | 
						||
        $query->leftJoin('bps.bps_third_user u', 'a.doc_ = u.id')
 | 
						||
            ->field('a.advertiser_id, a.advertiser_name,u.third_type,
 | 
						||
        COALESCE(SUM(d.assisted_purchases), 0) as assisted_purchases,
 | 
						||
        COALESCE(SUM(d.last_clicked_purchases), 0) as last_clicked_purchases,
 | 
						||
        COALESCE(SUM(d.clicks), 0) as clicks,
 | 
						||
        COALESCE(SUM(d.spend) / 1000000, 0) as spend,
 | 
						||
        COALESCE(SUM(d.impressions), 0) as impressions,
 | 
						||
        COALESCE(SUM(d.adds_to_cart), 0) as adds_to_cart,
 | 
						||
        COALESCE(SUM(d.cost_per_atc), 0) as cost_per_atc,
 | 
						||
        COALESCE(SUM(d.purchases), 0) as purchases,
 | 
						||
        COALESCE(SUM(d.purchases_value) / 1000000, 0) as purchases_value,
 | 
						||
        COALESCE(SUM(d.revenue) / 1000000, 0) as revenue,
 | 
						||
        COALESCE(SUM(d.total_cost) / 1000000, 0) as total_cost,
 | 
						||
        -1 as conversion_rate, -1 as roas, -1 as ctr, -1 as net_profit, -1 as net_profit_margin, -1 as net_profit_on_ad_spend')
 | 
						||
            ->group('a.advertiser_id, a.advertiser_name,u.third_type')
 | 
						||
            ->where('a.advertiser_id', 'in', $customerIds); // 添加 customerIds 条件
 | 
						||
        // 如果传入了 status 参数,按状态筛选
 | 
						||
//        if ($status !== 0) {
 | 
						||
//            $query->where('a.status', '=', $status);
 | 
						||
//        }
 | 
						||
        // 添加关键字过滤条件
 | 
						||
        $query->where(function ($query) use ($keyword, $platformType) {
 | 
						||
            if ($keyword) {
 | 
						||
                $query->whereRaw('LOWER(a.advertiser_name) LIKE ?', ['%' . strtolower($keyword) . '%']);
 | 
						||
            }
 | 
						||
            if ($platformType) {
 | 
						||
                $a                 = (int)$platformType;
 | 
						||
                $platformTypeNames = [1 => 'facebook', 2 => 'google', 3 => 'tiktok'];
 | 
						||
                $query->where('u.third_type', '=', $platformTypeNames[$a]);
 | 
						||
            }
 | 
						||
        });
 | 
						||
        $query->order('u.third_type', 'asc');
 | 
						||
 | 
						||
        // 获取所有符合条件的数据(不分页)
 | 
						||
        $allAccounts = $query->select()->toArray();
 | 
						||
 | 
						||
        // 汇总统计数据
 | 
						||
        $total_spend           = array_sum(array_column($allAccounts, 'spend'));
 | 
						||
        $total_cost            = array_sum(array_column($allAccounts, 'total_cost'));
 | 
						||
        $total_impressions     = array_sum(array_column($allAccounts, 'impressions'));
 | 
						||
        $total_clicks          = array_sum(array_column($allAccounts, 'clicks'));
 | 
						||
        $total_purchases_value = array_sum(array_column($allAccounts, 'purchases_value'));
 | 
						||
        $total_revenue         = array_sum(array_column($allAccounts, 'revenue'));
 | 
						||
        $total_purchases       = array_sum(array_column($allAccounts, 'purchases'));
 | 
						||
        $cost_per_purchase     = $total_purchases == 0 ? 0 : round($total_spend / $total_purchases, 2);
 | 
						||
 | 
						||
        $statistics = [
 | 
						||
            'assisted_purchases' => array_sum(array_column($allAccounts, 'assisted_purchases')),
 | 
						||
            'last_clicked_purchases' => array_sum(array_column($allAccounts, 'last_clicked_purchases')),
 | 
						||
            'roas' => $total_spend == 0 ? '-' : round($total_purchases_value / $total_spend, 2),
 | 
						||
            'amount_spend' => '$' . number_format($total_spend, 2) ?: '$0.00', // 格式化支出
 | 
						||
            'clicks' => $total_clicks,
 | 
						||
            'impressions' => array_sum(array_column($allAccounts, 'impressions')),
 | 
						||
            'adds_to_cart' => array_sum(array_column($allAccounts, 'adds_to_cart')),
 | 
						||
            'cost_per_atc' => array_sum(array_column($allAccounts, 'cost_per_atc')),
 | 
						||
            'purchases' => array_sum(array_column($allAccounts, 'purchases')),
 | 
						||
            'purchases_value' => array_sum(array_column($allAccounts, 'purchases_value')),
 | 
						||
            'cost_per_purchase' => '$' . number_format($cost_per_purchase, 2) ?: '$0.00',
 | 
						||
            'revenue' => '$' . number_format(array_sum(array_column($allAccounts, 'revenue')), 2) ?: '$0.00', // 格式化收入
 | 
						||
            'total_cost' => '$' . number_format($total_cost, 2) ?: '$0.00', // 格式化总成本
 | 
						||
            'conversion_rate' => $total_clicks == 0 ? '-' : round(($total_purchases / $total_clicks) * 100, 2) . '%',  // 转换率
 | 
						||
            'net_profit' => ($total_revenue - $total_cost) >= 0 ? '+$' . number_format($total_revenue - $total_cost, 2) : '-$' . number_format(abs($total_revenue - $total_cost), 2),  // 净利润
 | 
						||
            'net_profit_margin' => $total_revenue == 0 ? '-' : round(($total_revenue - $total_cost) / $total_revenue, 2) * 100 . '%',  // 净利润率
 | 
						||
            'net_profit_on_ad_spend' => $total_spend == 0 ? '-' : round(($total_revenue - $total_cost) / $total_spend, 2) * 100 . '%',  // 平均广告花费的净利润
 | 
						||
            'ctr' => ($total_impressions > 0) ? number_format(($total_clicks / $total_impressions) * 100, 2) . '%' : '-',  // 格式化为百分比
 | 
						||
        ];
 | 
						||
 | 
						||
 | 
						||
        // 获取分页数据
 | 
						||
        $page = max(1, (int)$page); // 确保页码不小于 1
 | 
						||
//             $ads = $query->page($page, $pageSize)->select();
 | 
						||
        $accounts = $query->limit(($page - 1) * $pageSize, $pageSize)->select();
 | 
						||
//        dump($ads);
 | 
						||
 | 
						||
        // 确保数据格式统一
 | 
						||
        $result = array_map(function ($item) {
 | 
						||
            // CTR 的计算:点击率 = 点击数 / 展示数
 | 
						||
            $ctr = $item['impressions'] > 0 ? number_format(($item['clicks'] / $item['impressions']) * 100, 2) . '%' : '-';
 | 
						||
            // Conversion Rate 的计算:转换率 = 购买数 / 点击数
 | 
						||
            $conversion_rate = $item['clicks'] > 0 ? round(($item['purchases'] / $item['clicks']) * 100, 2) . '%' : '-';
 | 
						||
            // Net Profit 的计算:净利润 = 收入 - 总成本
 | 
						||
            $net_profit = ($item['revenue'] - $item['total_cost']) >= 0 ? '+$' . number_format($item['revenue'] - $item['total_cost'], 2) : '-$' . number_format(abs($item['revenue'] - $item['total_cost']), 2);
 | 
						||
            // Net Profit Margin 的计算:净利润率 = 净利润 / 收入
 | 
						||
            $net_profit_margin = $item['revenue'] > 0 ? round(($item['revenue'] - $item['total_cost']) / $item['revenue'], 2) * 100 . '%' : '-';
 | 
						||
            // Net Profit on Ad Spend 的计算:广告支出净利润 = (收入 - 总成本) / 广告支出
 | 
						||
            $net_profit_on_ad_spend = $item['spend'] > 0 ? round(($item['revenue'] - $item['total_cost']) / $item['spend'], 2) * 100 . '%' : '-';
 | 
						||
            $platformTypeIds        = ['facebook' => 1, 'google' => 2, 'tiktok' => 3];
 | 
						||
            return [
 | 
						||
                'user_id' => $item['advertiser_id'],
 | 
						||
                'platform_type' => $platformTypeIds[$item['third_type']],
 | 
						||
                'advertiser_name' => $item['advertiser_name'] ?: '-',  // 若 name 为空则显示 '-'
 | 
						||
//                'ad_set_name' => $item['ad_set_name'] ?: '-',  // 若 name 为空则显示 '-'
 | 
						||
//                'status' => $item['status'],
 | 
						||
                'assisted_purchases' => $item['assisted_purchases'],
 | 
						||
                'last_clicked_purchases' => $item['last_clicked_purchases'],
 | 
						||
                'roas' => $item['spend'] == 0 ? '-' : round($item['purchases_value'] / $item['spend'], 2),
 | 
						||
                'spend' => '$' . number_format($item['spend'], 2),  // 格式化支出
 | 
						||
                'amount_spend' => '$' . number_format($item['spend'], 2),  // 格式化支出
 | 
						||
                'impressions' => $item['impressions'],
 | 
						||
                'clicks' => $item['clicks'],
 | 
						||
                'ctr' => $ctr,  // CTR 字段
 | 
						||
                'adds_to_cart' => $item['adds_to_cart'],
 | 
						||
                'cost_per_atc' => $item['cost_per_atc'],
 | 
						||
                'purchases' => $item['purchases'],
 | 
						||
                'purchases_value' => '$' . number_format($item['purchases_value'], 2),  // 格式化购买金额
 | 
						||
                'cost_per_purchase' => $item['purchases'] > 0 ? '$' . number_format(($item['spend'] / $item['purchases']), 2) : '$0.00',
 | 
						||
                'revenue' => '$' . number_format($item['revenue'], 2),  // 格式化收入
 | 
						||
                'total_cost' => '$' . number_format($item['total_cost'], 2),  // 格式化总成本
 | 
						||
                'conversion_rate' => $conversion_rate,
 | 
						||
                'net_profit' => $net_profit,
 | 
						||
                'net_profit_margin' => $net_profit_margin,
 | 
						||
                'net_profit_on_ad_spend' => $net_profit_on_ad_spend,
 | 
						||
            ];
 | 
						||
        }, $accounts->toArray());
 | 
						||
 | 
						||
        // Pagination 数据
 | 
						||
        $pagination = [
 | 
						||
            'startIndex' => ($page - 1) * $pageSize + 1, // 确保索引从 1 开始
 | 
						||
            'maxResults' => count($accounts),               // 当前页实际返回数据数量
 | 
						||
            'count' => count($allAccounts),            // 符合条件的总记录数
 | 
						||
            'pageNo' => $page,                         // 当前页码
 | 
						||
            'pageSize' => $pageSize,                   // 每页条数
 | 
						||
            'pages' => (int)ceil(count($allAccounts) / $pageSize), // 总页数
 | 
						||
        ];
 | 
						||
 | 
						||
        return [
 | 
						||
            'pagination' => $pagination,
 | 
						||
            'statistics' => $statistics,
 | 
						||
            'data' => $result,
 | 
						||
        ];
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    public static function getAdList($platformType, $customerIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null, $status = 0, $countOnly = false)
 | 
						||
    {
 | 
						||
        // 检查 customerIds 是否为空,直接返回空结构
 | 
						||
        if (empty($customerIds)) {
 | 
						||
            return $countOnly ? 0 : [
 | 
						||
                'pagination' => [
 | 
						||
                    'startIndex' => 0,
 | 
						||
                    'maxResults' => 0,
 | 
						||
                    'count' => 0,
 | 
						||
                    'pageNo' => $page,
 | 
						||
                    'pageSize' => $pageSize,
 | 
						||
                    'pages' => 0,
 | 
						||
                ],
 | 
						||
                'statistics' => [],
 | 
						||
                'data' => [],
 | 
						||
            ];
 | 
						||
        }
 | 
						||
 | 
						||
        // 基础查询:广告活动和日数据表联接
 | 
						||
        $query = BpsAdAd::alias('a')
 | 
						||
            ->cache(false) // 强制不使用缓存
 | 
						||
            ->where('a.account_id', 'in', $customerIds);
 | 
						||
        // 如果只需要记录条数,执行计数查询
 | 
						||
        if ($countOnly) {
 | 
						||
            return $query->count();
 | 
						||
        }
 | 
						||
 | 
						||
        // 动态构建日期条件
 | 
						||
        $dateCondition = '';
 | 
						||
        if ($startDate && $endDate) {
 | 
						||
            $dateCondition = "d.date BETWEEN '{$startDate}' AND '{$endDate}'";
 | 
						||
            $query->leftJoin('bps.bps_ads_insights d', "a.ad_id = d.ad_id AND a.platform_type = d.platform AND {$dateCondition}");
 | 
						||
        }
 | 
						||
 | 
						||
        // 基础查询:广告和日数据表联接
 | 
						||
        $query->leftJoin('bps.bps_ads_set s', 'a.ad_set_id = s.ad_set_id')  // 联接广告组表,获取 ad_set_name
 | 
						||
        ->field('a.ad_id, a.status as status, a.name, a.account_id,a.platform_type,s.name as ad_set_name,
 | 
						||
        COALESCE(SUM(d.assisted_purchases), 0) as assisted_purchases,
 | 
						||
        COALESCE(SUM(d.last_clicked_purchases), 0) as last_clicked_purchases,
 | 
						||
        COALESCE(SUM(d.clicks), 0) as clicks,
 | 
						||
        COALESCE(SUM(d.spend) / 1000000, 0) as spend,
 | 
						||
        COALESCE(SUM(d.impressions), 0) as impressions,
 | 
						||
        COALESCE(SUM(d.adds_to_cart), 0) as adds_to_cart,
 | 
						||
        COALESCE(SUM(d.cost_per_atc), 0) as cost_per_atc,
 | 
						||
        COALESCE(SUM(d.purchases), 0) as purchases,
 | 
						||
        COALESCE(SUM(d.purchases_value) / 1000000, 0) as purchases_value,
 | 
						||
        COALESCE(SUM(d.revenue) / 1000000, 0) as revenue,
 | 
						||
        COALESCE(SUM(d.total_cost) / 1000000, 0) as total_cost,
 | 
						||
        -1 as conversion_rate, -1 as roas, -1 as ctr, -1 as net_profit, -1 as net_profit_margin, -1 as net_profit_on_ad_spend')
 | 
						||
            ->group('a.ad_id, a.status, a.account_id, a.name,a.platform_type, s.name')
 | 
						||
            ->where('a.account_id', 'in', $customerIds); // 添加 customerIds 条件
 | 
						||
        // 如果传入了 status 参数,按状态筛选
 | 
						||
        if ($status !== 0) {
 | 
						||
            $query->where('a.status', '=', $status);
 | 
						||
        }
 | 
						||
        // 添加关键字过滤条件
 | 
						||
        $query->where(function ($query) use ($keyword, $platformType) {
 | 
						||
            if ($keyword) {
 | 
						||
//                $query->where('a.name', 'like', '%' . $keyword . '%');
 | 
						||
                $query->whereRaw('LOWER(a.name) LIKE ?', ['%' . strtolower($keyword) . '%']);
 | 
						||
            }
 | 
						||
            if ($platformType) {
 | 
						||
                $platformType = (int)$platformType;
 | 
						||
                $query->where('a.platform_type', '=', $platformType);
 | 
						||
            }
 | 
						||
        });
 | 
						||
 | 
						||
        // 获取所有符合条件的数据(不分页)
 | 
						||
        $allAds = $query->select()->toArray();
 | 
						||
 | 
						||
        // 汇总统计数据
 | 
						||
        $total_spend           = array_sum(array_column($allAds, 'spend'));
 | 
						||
        $total_cost            = array_sum(array_column($allAds, 'total_cost'));
 | 
						||
        $total_impressions     = array_sum(array_column($allAds, 'impressions'));
 | 
						||
        $total_clicks          = array_sum(array_column($allAds, 'clicks'));
 | 
						||
        $total_purchases_value = array_sum(array_column($allAds, 'purchases_value'));
 | 
						||
        $total_revenue         = array_sum(array_column($allAds, 'revenue'));
 | 
						||
        $total_purchases       = array_sum(array_column($allAds, 'purchases'));
 | 
						||
        $cost_per_purchase     = $total_purchases == 0 ? 0 : round($total_spend / $total_purchases, 2);
 | 
						||
 | 
						||
        $statistics = [
 | 
						||
            'assisted_purchases' => array_sum(array_column($allAds, 'assisted_purchases')),
 | 
						||
            'last_clicked_purchases' => array_sum(array_column($allAds, 'last_clicked_purchases')),
 | 
						||
            'roas' => $total_spend == 0 ? '-' : round($total_purchases_value / $total_spend, 2),
 | 
						||
            'amount_spend' => '$' . number_format($total_spend, 2) ?: '$0.00', // 格式化支出
 | 
						||
            'clicks' => $total_clicks,
 | 
						||
            'impressions' => array_sum(array_column($allAds, 'impressions')),
 | 
						||
            'adds_to_cart' => array_sum(array_column($allAds, 'adds_to_cart')),
 | 
						||
            'cost_per_atc' => array_sum(array_column($allAds, 'cost_per_atc')),
 | 
						||
            'purchases' => array_sum(array_column($allAds, 'purchases')),
 | 
						||
            'purchases_value' => array_sum(array_column($allAds, 'purchases_value')),
 | 
						||
            'cost_per_purchase' => '$' . number_format($cost_per_purchase, 2) ?: '$0.00',
 | 
						||
            'revenue' => '$' . number_format(array_sum(array_column($allAds, 'revenue')), 2) ?: '$0.00', // 格式化收入
 | 
						||
            'total_cost' => '$' . number_format($total_cost, 2) ?: '$0.00', // 格式化总成本
 | 
						||
            'conversion_rate' => $total_clicks == 0 ? '-' : round(($total_purchases / $total_clicks) * 100, 2) . '%',  // 转换率
 | 
						||
            'net_profit' => ($total_revenue - $total_cost) >= 0 ? '+$' . number_format($total_revenue - $total_cost, 2) : '-$' . number_format(abs($total_revenue - $total_cost), 2),  // 净利润
 | 
						||
            'net_profit_margin' => $total_revenue == 0 ? '-' : round(($total_revenue - $total_cost) / $total_revenue, 2) * 100 . '%',  // 净利润率
 | 
						||
            'net_profit_on_ad_spend' => $total_spend == 0 ? '-' : round(($total_revenue - $total_cost) / $total_spend, 2) * 100 . '%',  // 平均广告花费的净利润
 | 
						||
            'ctr' => ($total_impressions > 0) ? number_format(($total_clicks / $total_impressions) * 100, 2) . '%' : '-',  // 格式化为百分比
 | 
						||
        ];
 | 
						||
 | 
						||
 | 
						||
        // 获取分页数据
 | 
						||
        $page = max(1, (int)$page); // 确保页码不小于 1
 | 
						||
//             $ads = $query->page($page, $pageSize)->select();
 | 
						||
        $ads = $query->limit(($page - 1) * $pageSize, $pageSize)->select();
 | 
						||
//        dump($ads);
 | 
						||
 | 
						||
        // 确保数据格式统一
 | 
						||
        $result = array_map(function ($item) {
 | 
						||
            // CTR 的计算:点击率 = 点击数 / 展示数
 | 
						||
            $ctr = $item['impressions'] > 0 ? number_format(($item['clicks'] / $item['impressions']) * 100, 2) . '%' : '-';
 | 
						||
            // Conversion Rate 的计算:转换率 = 购买数 / 点击数
 | 
						||
            $conversion_rate = $item['clicks'] > 0 ? round(($item['purchases'] / $item['clicks']) * 100, 2) . '%' : '-';
 | 
						||
            // Net Profit 的计算:净利润 = 收入 - 总成本
 | 
						||
            $net_profit = ($item['revenue'] - $item['total_cost']) >= 0 ? '+$' . number_format($item['revenue'] - $item['total_cost'], 2) : '-$' . number_format(abs($item['revenue'] - $item['total_cost']), 2);
 | 
						||
            // Net Profit Margin 的计算:净利润率 = 净利润 / 收入
 | 
						||
            $net_profit_margin = $item['revenue'] > 0 ? round(($item['revenue'] - $item['total_cost']) / $item['revenue'], 2) * 100 . '%' : '-';
 | 
						||
            // Net Profit on Ad Spend 的计算:广告支出净利润 = (收入 - 总成本) / 广告支出
 | 
						||
            $net_profit_on_ad_spend = $item['spend'] > 0 ? round(($item['revenue'] - $item['total_cost']) / $item['spend'], 2) * 100 . '%' : '-';
 | 
						||
 | 
						||
            return [
 | 
						||
                'id' => $item['ad_id'],
 | 
						||
                'platform_type' => $item['platform_type'],
 | 
						||
                'account_id' => $item['account_id'],  // 映射为 customer_id
 | 
						||
                'name' => $item['name'] ?: '-',  // 若 name 为空则显示 '-'
 | 
						||
                'ad_set_name' => $item['ad_set_name'] ?: '-',  // 若 name 为空则显示 '-'
 | 
						||
                'status' => $item['status'],
 | 
						||
                'assisted_purchases' => $item['assisted_purchases'],
 | 
						||
                'last_clicked_purchases' => $item['last_clicked_purchases'],
 | 
						||
                'roas' => $item['spend'] == 0 ? '-' : round($item['purchases_value'] / $item['spend'], 2),
 | 
						||
                'spend' => '$' . number_format($item['spend'], 2),  // 格式化支出
 | 
						||
                'impressions' => $item['impressions'],
 | 
						||
                'clicks' => $item['clicks'],
 | 
						||
                'ctr' => $ctr,  // CTR 字段
 | 
						||
                'adds_to_cart' => $item['adds_to_cart'],
 | 
						||
                'cost_per_atc' => $item['cost_per_atc'],
 | 
						||
                'purchases' => $item['purchases'],
 | 
						||
                'purchases_value' => '$' . number_format($item['purchases_value'], 2),  // 格式化购买金额
 | 
						||
                'cost_per_purchase' => $item['purchases'] > 0 ? '$' . number_format(($item['spend'] / $item['purchases']), 2) : '$0.00',
 | 
						||
                'revenue' => '$' . number_format($item['revenue'], 2),  // 格式化收入
 | 
						||
                'total_cost' => '$' . number_format($item['total_cost'], 2),  // 格式化总成本
 | 
						||
                'conversion_rate' => $conversion_rate,
 | 
						||
                'net_profit' => $net_profit,
 | 
						||
                'net_profit_margin' => $net_profit_margin,
 | 
						||
                'net_profit_on_ad_spend' => $net_profit_on_ad_spend,
 | 
						||
            ];
 | 
						||
        }, $ads->toArray());
 | 
						||
 | 
						||
        // Pagination 数据
 | 
						||
        $pagination = [
 | 
						||
            'startIndex' => ($page - 1) * $pageSize + 1, // 确保索引从 1 开始
 | 
						||
            'maxResults' => count($ads),               // 当前页实际返回数据数量
 | 
						||
            'count' => count($allAds),            // 符合条件的总记录数
 | 
						||
            'pageNo' => $page,                         // 当前页码
 | 
						||
            'pageSize' => $pageSize,                   // 每页条数
 | 
						||
            'pages' => (int)ceil(count($allAds) / $pageSize), // 总页数
 | 
						||
        ];
 | 
						||
 | 
						||
        return [
 | 
						||
            'pagination' => $pagination,
 | 
						||
            'statistics' => $statistics,
 | 
						||
            'data' => $result,
 | 
						||
        ];
 | 
						||
    }
 | 
						||
 | 
						||
    public static function getThirdUserList($platformType, $userIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null)
 | 
						||
    {
 | 
						||
        // 检查 userIds 是否为空,直接返回空结构
 | 
						||
        if (empty($userIds)) {
 | 
						||
            return [
 | 
						||
                'pagination' => [
 | 
						||
                    'startIndex' => 0,
 | 
						||
                    'maxResults' => $pageSize,
 | 
						||
                    'count' => 0,
 | 
						||
                    'pageNo' => $page,
 | 
						||
                    'pageSize' => $pageSize,
 | 
						||
                    'pages' => 0,
 | 
						||
                ],
 | 
						||
                'statistics' => [],
 | 
						||
                'data' => [],
 | 
						||
            ];
 | 
						||
        }
 | 
						||
        $userCount = count($userIds);
 | 
						||
//        dump($userIds);
 | 
						||
        // 动态构建日期条件
 | 
						||
        $dateCondition = '1=1'; // 默认没有日期限制
 | 
						||
        if ($startDate && $endDate) {
 | 
						||
            $dateCondition = "d.date BETWEEN '{$startDate}' AND '{$endDate}'";
 | 
						||
        }
 | 
						||
//            u.user_id as third_user_id, u.third_type, u.facebook_user_id,
 | 
						||
//            a.advertiser_id, a.advertiser_name, a.google_manager, a.google_test_account,
 | 
						||
        // 基础查询:第三方用户和广告商数据表联接
 | 
						||
        $query = ThirdUser::alias('u')
 | 
						||
            ->cache(false) // 强制不使用缓存
 | 
						||
            ->leftJoin('bps.bps_third_user_advertiser a', "u.id = a.doc_")
 | 
						||
            ->field('u.id as user_id,u.third_type,a.advertiser_name,
 | 
						||
 | 
						||
            COALESCE(SUM(d.assisted_purchases), 0) as assisted_purchases,
 | 
						||
            COALESCE(SUM(d.last_clicked_purchases), 0) as last_clicked_purchases,
 | 
						||
            COALESCE(SUM(d.spend) / 1000000, 0) as spend,
 | 
						||
            COALESCE(SUM(d.impressions), 0) as impressions,
 | 
						||
            COALESCE(SUM(d.clicks), 0) as clicks,
 | 
						||
            COALESCE(SUM(d.adds_to_cart), 0) as adds_to_cart,
 | 
						||
            COALESCE(SUM(d.cost_per_atc), 0) as cost_per_atc,
 | 
						||
            COALESCE(SUM(d.purchases), 0) as purchases,
 | 
						||
            COALESCE(SUM(d.purchases_value/1000000), 0) as purchases_value,
 | 
						||
            COALESCE(SUM(d.revenue/1000000), 0) as revenue,
 | 
						||
            COALESCE(SUM(d.total_cost)/1000000, 0) as total_cost')
 | 
						||
            ->leftJoin('bps.bps_ads_insights d', "a.advertiser_id = d.account_id AND {$dateCondition}")
 | 
						||
            ->where('u.id', 'in', $userIds); // 添加 userIds 条件
 | 
						||
 | 
						||
        // 添加关键字过滤条件
 | 
						||
        $query->where(function ($query) use ($keyword, $platformType) {
 | 
						||
            if ($keyword) {
 | 
						||
                $query->where('a.advertiser_name', 'like', '%' . $keyword . '%');
 | 
						||
            }
 | 
						||
            if ($platformType) {
 | 
						||
                $query->where('d.platform', '=', $platformType);
 | 
						||
            }
 | 
						||
        });
 | 
						||
 | 
						||
        // 添加 GROUP BY 子句
 | 
						||
//        $query->group('u.id, u.user_id, u.third_type, u.facebook_user_id,
 | 
						||
//              a.advertiser_id, a.advertiser_name, a.google_manager, a.google_test_account');
 | 
						||
        $query->group('u.id,u.third_type,a.advertiser_name');
 | 
						||
 | 
						||
        // 调试打印 SQL
 | 
						||
 | 
						||
 | 
						||
        // 获取所有符合条件的数据(不分页)
 | 
						||
        $allUsers = $query->select()->toArray();
 | 
						||
//        dump($query->getLastSql());
 | 
						||
//
 | 
						||
//        dump($allUsers);
 | 
						||
 | 
						||
        // 汇总统计数据
 | 
						||
        $total_spend           = array_sum(array_column($allUsers, 'spend'));
 | 
						||
        $total_impressions     = array_sum(array_column($allUsers, 'impressions'));
 | 
						||
        $total_clicks          = array_sum(array_column($allUsers, 'clicks'));
 | 
						||
        $total_adds_to_cart    = array_sum(array_column($allUsers, 'adds_to_cart'));
 | 
						||
        $total_cost_per_atc    = array_sum(array_column($allUsers, 'cost_per_atc'));
 | 
						||
        $total_purchases       = array_sum(array_column($allUsers, 'purchases'));
 | 
						||
        $total_purchases_value = array_sum(array_column($allUsers, 'purchases_value'));
 | 
						||
        $total_revenue         = array_sum(array_column($allUsers, 'revenue'));
 | 
						||
        $total_cost            = array_sum(array_column($allUsers, 'total_cost'));
 | 
						||
 | 
						||
        // 计算 ROAS
 | 
						||
        $roas              = $total_spend == 0 ? '-' : round($total_purchases_value / $total_spend, 2);
 | 
						||
        $cost_per_purchase = $total_purchases == 0 ? 0 : round($total_spend / $total_purchases, 2);
 | 
						||
        // 计算 CTR
 | 
						||
        $ctr = $total_impressions > 0 ? number_format(($total_clicks / $total_impressions) * 100, 2) . '%' : '-';
 | 
						||
 | 
						||
        // 汇总统计字段初始化
 | 
						||
        $statistics = [
 | 
						||
            'assisted_purchases' => 0,
 | 
						||
            'last_clicked_purchases' => 0,
 | 
						||
            'roas' => $total_spend == 0 ? '-' : round($total_purchases_value / $total_spend, 2),
 | 
						||
            'amount_spend' => '$' . number_format($total_spend, 2) ?: '$0.00', // 格式化支出
 | 
						||
            'clicks' => $total_clicks,
 | 
						||
            'impressions' => $total_impressions,
 | 
						||
            'adds_to_cart' => $total_adds_to_cart,
 | 
						||
            'cost_per_atc' => $total_cost_per_atc,
 | 
						||
            'purchases' => $total_purchases,
 | 
						||
            'purchases_value' => '$' . number_format($total_purchases_value, 2) ?: '$0.00', // 格式化销售额$total_purchases_value,
 | 
						||
            'cost_per_purchase' => '$' . number_format($cost_per_purchase, 2) ?: '$0.00', // 格式化销售额$total_purchases_value,
 | 
						||
            'revenue' => '$' . number_format($total_revenue, 2) ?: '$0.00', // 格式化收入
 | 
						||
            'total_cost' => '$' . number_format($total_cost, 2) ?: '$0.00', // 格式化总成本
 | 
						||
            'conversion_rate' => $total_clicks == 0 ? '-' : round(($total_purchases / $total_clicks) * 100, 2) . '%',  // 转换率
 | 
						||
            'net_profit' => ($total_revenue - $total_cost) >= 0 ? '+$' . number_format($total_revenue - $total_cost, 2) : '-$' . number_format(abs($total_revenue - $total_cost), 2),  // 净利润
 | 
						||
            'net_profit_margin' => $total_revenue == 0 ? '-' : round(($total_revenue - $total_cost) / $total_revenue, 2) * 100 . '%',  // 净利润率
 | 
						||
            'net_profit_on_ad_spend' => $total_spend == 0 ? '-' : round(($total_revenue - $total_cost) / $total_spend, 2) * 100 . '%', // 广告支出净利润
 | 
						||
            'ctr' => $ctr,  // CTR 字段
 | 
						||
        ];
 | 
						||
 | 
						||
        // 获取分页数据
 | 
						||
        $users = $query->paginate($pageSize, false, ['page' => $page]);
 | 
						||
 | 
						||
        // 按照 third_user_id 聚合统计字段
 | 
						||
        $aggregatedUsers = [];
 | 
						||
 | 
						||
// 遍历每个用户的统计数据
 | 
						||
        foreach ($users->items() as $item) {
 | 
						||
            $thirdUserId = $item['user_id'];
 | 
						||
 | 
						||
            if (!isset($aggregatedUsers[$thirdUserId])) {
 | 
						||
                $aggregatedUsers[$thirdUserId] = [
 | 
						||
                    'user_id' => $item['user_id'],
 | 
						||
                    'platform_type' => self::getPlatformType($item['third_type']),
 | 
						||
                    'advertiser_name' => $item['advertiser_name'],
 | 
						||
                    'assisted_purchases' => 0,
 | 
						||
                    'last_clicked_purchases' => 0,
 | 
						||
                    'roas' => 0,
 | 
						||
                    'spend' => 0,
 | 
						||
                    'impressions' => 0,
 | 
						||
                    'clicks' => 0,
 | 
						||
                    'adds_to_cart' => 0,
 | 
						||
                    'cost_per_atc' => 0,
 | 
						||
                    'purchases' => 0,
 | 
						||
                    'purchases_value' => 0,
 | 
						||
                    'cost_per_purchase' => 0,
 | 
						||
                    'revenue' => 0,
 | 
						||
                    'total_cost' => 0,
 | 
						||
                    'net_profit' => '-',  // 没有提供 net_profit,保持为 '-'
 | 
						||
                    'net_profit_margin' => '-',  // 没有提供 net_profit_margin,保持为 '-'
 | 
						||
                    'net_profit_on_ad_spend' => '-',  // 没有提供 net_profit_on_ad_spend,保持为 '-'
 | 
						||
 | 
						||
                ];
 | 
						||
            }
 | 
						||
 | 
						||
            // 汇总统计
 | 
						||
            $aggregatedUsers[$thirdUserId]['spend']                  += $item['spend'];
 | 
						||
            $aggregatedUsers[$thirdUserId]['impressions']            += $item['impressions'];
 | 
						||
            $aggregatedUsers[$thirdUserId]['clicks']                 += $item['clicks'];
 | 
						||
            $aggregatedUsers[$thirdUserId]['adds_to_cart']           += $item['adds_to_cart'];
 | 
						||
            $aggregatedUsers[$thirdUserId]['cost_per_atc']           += $item['cost_per_atc'];
 | 
						||
            $aggregatedUsers[$thirdUserId]['purchases']              += $item['purchases'];
 | 
						||
            $aggregatedUsers[$thirdUserId]['purchases_value']        += $item['purchases_value'];
 | 
						||
            $aggregatedUsers[$thirdUserId]['revenue']                += $item['revenue'];
 | 
						||
            $aggregatedUsers[$thirdUserId]['total_cost']             += $item['total_cost'];
 | 
						||
            $aggregatedUsers[$thirdUserId]['assisted_purchases']     += $item['assisted_purchases'];
 | 
						||
            $aggregatedUsers[$thirdUserId]['last_clicked_purchases'] += $item['last_clicked_purchases'];
 | 
						||
        }
 | 
						||
 | 
						||
// 计算统计口径字段:ROAS, CTR等
 | 
						||
        foreach ($aggregatedUsers as $userId => $data) {
 | 
						||
            $total_spend           = $data['spend'];
 | 
						||
            $total_purchases_value = $data['purchases_value'];
 | 
						||
            $total_revenue         = $data['revenue'];
 | 
						||
            $total_cost            = $data['total_cost'];
 | 
						||
            $total_clicks          = $data['clicks'];
 | 
						||
            $total_impressions     = $data['impressions'];
 | 
						||
 | 
						||
            // CTR 的计算:点击率 = 点击数 / 展示数
 | 
						||
            $ctr = $data['impressions'] > 0 ? number_format(($data['clicks'] / $data['impressions']) * 100, 2) . '%' : '-';
 | 
						||
            // Conversion Rate 的计算:转换率 = 购买数 / 点击数
 | 
						||
            $conversion_rate = $data['clicks'] > 0 ? round(($data['purchases'] / $data['clicks']) * 100, 2) . '%' : '-';
 | 
						||
            // Net Profit 的计算:净利润 = 收入 - 总成本
 | 
						||
            $net_profit = ($data['revenue'] - $data['total_cost']) >= 0 ? '+$' . number_format($data['revenue'] - $data['total_cost'], 2) : '-$' . number_format(abs($data['revenue'] - $data['total_cost']), 2);
 | 
						||
            // Net Profit Margin 的计算:净利润率 = 净利润 / 收入
 | 
						||
            $net_profit_margin = $data['revenue'] > 0 ? round(($data['revenue'] - $data['total_cost']) / $data['revenue'], 2) * 100 . '%' : '-';
 | 
						||
            // Net Profit on Ad Spend 的计算:广告支出净利润 = (收入 - 总成本) / 广告支出
 | 
						||
            $net_profit_on_ad_spend = $data['spend'] > 0 ? round(($data['revenue'] - $data['total_cost']) / $data['spend'], 2) * 100 . '%' : '-';
 | 
						||
 | 
						||
            // 计算 ROAS, CTR 和其他需要的字段
 | 
						||
            $aggregatedUsers[$userId]['roas']                   = $total_spend == 0 ? '-' : round($total_purchases_value / $total_spend, 2);
 | 
						||
            $aggregatedUsers[$userId]['amount_spend']           = '$' . number_format($total_spend, 2) ?: '$0.00';
 | 
						||
            $aggregatedUsers[$userId]['purchases_value']        = '$' . number_format($total_purchases_value, 2) ?: '$0.00';
 | 
						||
            $aggregatedUsers[$userId]['cost_per_purchase']      = $data['purchases'] == 0 ? '$0.00' : '$' . number_format($total_purchases_value / $data['purchases'], 2);
 | 
						||
            $aggregatedUsers[$userId]['revenue']                = '$' . number_format($total_revenue, 2) ?: '$0.00';
 | 
						||
            $aggregatedUsers[$userId]['total_cost']             = '$' . number_format($total_cost, 2) ?: '$0.00';
 | 
						||
            $aggregatedUsers[$userId]['conversion_rate']        = $conversion_rate;
 | 
						||
            $aggregatedUsers[$userId]['ctr']                    = $ctr;
 | 
						||
            $aggregatedUsers[$userId]['net_profit']             = $net_profit;
 | 
						||
            $aggregatedUsers[$userId]['net_profit_margin']      = $net_profit_margin;
 | 
						||
            $aggregatedUsers[$userId]['net_profit_on_ad_spend'] = $net_profit_on_ad_spend;
 | 
						||
        }
 | 
						||
        // 如果 aggregatedUsers 为空,返回默认的数据结构
 | 
						||
        if (empty($aggregatedUsers) && !$keyword) {
 | 
						||
            $emptyUser = [];
 | 
						||
            $query     = ThirdUser::alias('u')
 | 
						||
                ->cache(false) // 强制不使用缓存
 | 
						||
                ->leftJoin('bps.bps_third_user_advertiser a', "u.id = a.doc_")
 | 
						||
                ->field('u.id as user_id,u.third_type,a.advertiser_name');
 | 
						||
            // 添加关键字过滤条件
 | 
						||
            $query->where(function ($query) use ($platformType) {
 | 
						||
//                if ($keyword) {
 | 
						||
//                    $query->where('a.advertiser_name', 'like', '%' . $keyword . '%');
 | 
						||
//                }
 | 
						||
                if ($platformType) {
 | 
						||
                    $a                 = (int)$platformType;
 | 
						||
                    $platformTypeNames = [1 => 'facebook', 2 => 'google', 3 => 'tiktok'];
 | 
						||
                    $query->where('u.third_type', '=', $platformTypeNames[$a]);
 | 
						||
                }
 | 
						||
            });
 | 
						||
 | 
						||
            // 获取所有符合条件的数据(不分页)
 | 
						||
            $allUsers = $query->select()->toArray();
 | 
						||
            foreach ($allUsers as $user) {
 | 
						||
                if (in_array($user['user_id'], $userIds)) {
 | 
						||
                    $emptyUser[] = [
 | 
						||
                        'user_id' => $user['user_id'],
 | 
						||
                        'platform_type' => (int)$platformType,
 | 
						||
                        'advertiser_name' => $user['advertiser_name'],
 | 
						||
                        'assisted_purchases' => 0,
 | 
						||
                        'last_clicked_purchases' => 0,
 | 
						||
                        'spend' => 0,
 | 
						||
                        'impressions' => 0,
 | 
						||
                        'clicks' => 0,
 | 
						||
                        'adds_to_cart' => 0,
 | 
						||
                        'cost_per_atc' => 0,
 | 
						||
                        'purchases' => 0,
 | 
						||
                        'purchases_value' => 0,
 | 
						||
                        'revenue' => 0,
 | 
						||
                        'total_cost' => 0,
 | 
						||
                        'conversion_rate' => '-',
 | 
						||
                        'net_profit' => '-',
 | 
						||
                        'net_profit_margin' => '-',
 | 
						||
                        'net_profit_on_ad_spend' => '-',
 | 
						||
                        'ctr' => '-',
 | 
						||
                    ];
 | 
						||
                }
 | 
						||
            }
 | 
						||
//        dump($allUsers,'222');
 | 
						||
 | 
						||
            return [
 | 
						||
                'pagination' => [
 | 
						||
                    'startIndex' => ($page - 1) * $pageSize,
 | 
						||
                    'maxResults' => $pageSize,
 | 
						||
                    'count' => count($emptyUser),
 | 
						||
                    'pageNo' => $page,
 | 
						||
                    'pageSize' => $pageSize,
 | 
						||
                    'pages' => 0,
 | 
						||
                ],
 | 
						||
                'statistics' => $statistics,
 | 
						||
                'data' => $emptyUser
 | 
						||
            ];
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        // 使用 array_values 移除键名
 | 
						||
        $dataWithoutKeys = array_values($aggregatedUsers);
 | 
						||
        // 最终分页信息
 | 
						||
        $pagination = [
 | 
						||
//            'startIndex' => ($page - 1) * $pageSize,
 | 
						||
//            'maxResults' => $pageSize,
 | 
						||
////            'count' => $users->total(),
 | 
						||
//            'count' => $userCount,
 | 
						||
//            'pageNo' => $page,
 | 
						||
//            'pageSize' => $pageSize,
 | 
						||
//            'pages' => ceil($users->total() / $pageSize),
 | 
						||
 | 
						||
            'startIndex' => ($page - 1) * $pageSize + 1, // 确保索引从 1 开始
 | 
						||
            'maxResults' => count($dataWithoutKeys),               // 当前页实际返回数据数量
 | 
						||
            'count' => count($dataWithoutKeys),            // 符合条件的总记录数
 | 
						||
            'pageNo' => $page,                         // 当前页码
 | 
						||
            'pageSize' => $pageSize,                   // 每页条数
 | 
						||
            'pages' => (int)ceil(count($dataWithoutKeys) / $pageSize), // 总页数
 | 
						||
        ];
 | 
						||
 | 
						||
        return [
 | 
						||
            'pagination' => $pagination,
 | 
						||
            'statistics' => $statistics,
 | 
						||
            'data' => $dataWithoutKeys,
 | 
						||
        ];
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    public static function getCreativeInsightData($platformType, $customerIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null, $countOnly = false)
 | 
						||
    {
 | 
						||
        // 1. 创建查询对象,初始化 BpsAdCreativeInsight 查询
 | 
						||
        $creativeDataQuery = BpsAdCreativeInsight::alias('i')
 | 
						||
            ->join('bps.bps_ads_creative c', 'i.creative_id = c.creative_id', 'LEFT'); // 联接 bps_ads_creative 表
 | 
						||
        if ($platformType != 0) {
 | 
						||
            $creativeDataQuery->where('i.platform', $platformType); // 只有 platformType 不为 0 时才添加筛选
 | 
						||
        }
 | 
						||
 | 
						||
        // 2. 日期范围筛选
 | 
						||
        if ($startDate && $endDate) {
 | 
						||
            $creativeDataQuery->whereBetween('i.date', [$startDate, $endDate]);
 | 
						||
        }
 | 
						||
 | 
						||
        // 3. 客户 ID 过滤(如果提供了)
 | 
						||
        if (!empty($customerIds)) {
 | 
						||
            $creativeDataQuery->whereIn('i.account_id', $customerIds);
 | 
						||
        } else {
 | 
						||
            return $countOnly ? 0 :[
 | 
						||
                'data' => [],
 | 
						||
                'total' => 0,
 | 
						||
                'statistics' => [],
 | 
						||
                'pagination' => [
 | 
						||
                    'startIndex' => 0,
 | 
						||
                    'maxResults' => $pageSize,
 | 
						||
                    'count' => 0,
 | 
						||
                    'pageNo' => 1,
 | 
						||
                    'pageSize' => $pageSize
 | 
						||
                ]
 | 
						||
            ];
 | 
						||
        }
 | 
						||
        // 仅返回记录数时的逻辑
 | 
						||
        if ($countOnly) {
 | 
						||
            return $creativeDataQuery->count() ?: 0;
 | 
						||
        }
 | 
						||
 | 
						||
        // 4. 关键词过滤
 | 
						||
        if ($keyword) {
 | 
						||
//            $creativeDataQuery->where('c.name', 'like', '%' . $keyword . '%');  // 在 bps_ads_creative 表中查找关键词
 | 
						||
            $creativeDataQuery->whereRaw('LOWER(c.name) LIKE ?', ['%' . strtolower($keyword) . '%']);  // 在 bps_ads_creative 表中查找关键词
 | 
						||
        }
 | 
						||
 | 
						||
        // 5. 数据聚合(按 creative_id 和其他字段)
 | 
						||
        $creativeDataQuery->group('i.creative_id,  i.platform, i.account_id, c.name, c.type,c.url, c.thumbnail_url') // 按需要的字段分组
 | 
						||
        ->field([
 | 
						||
            'i.creative_id',
 | 
						||
            'i.platform',
 | 
						||
            'c.name AS creative_name',  // 从 bps_ads_creative 表中选择 name
 | 
						||
            'c.url AS creative_url',    // 从 bps_ads_creative 表中选择 url
 | 
						||
            'c.type AS creative_type',    // 从 bps_ads_creative 表中选择 url
 | 
						||
            'c.thumbnail_url',          // 从 bps_ads_creative 表中选择 thumbnail_url
 | 
						||
            ThinkDb::raw('COALESCE(SUM(i.spend) / 1000000, 0)  AS total_spend'),
 | 
						||
            ThinkDb::raw('COALESCE(SUM(i.purchases_value) / 1000000, 0) AS total_purchases_value'),
 | 
						||
            ThinkDb::raw('COALESCE(SUM(i.purchases), 0) AS total_purchases'),
 | 
						||
            ThinkDb::raw('COALESCE(SUM(i.revenue) / 1000000, 0) AS total_revenue'),
 | 
						||
            ThinkDb::raw('COALESCE(SUM(i.impressions), 0) AS total_impressions'),
 | 
						||
            ThinkDb::raw('COALESCE(SUM(i.clicks), 0) AS total_clicks'),
 | 
						||
            ThinkDb::raw('COALESCE(SUM(i.video_25),0) AS video_plays_25_rate'),
 | 
						||
            ThinkDb::raw('COALESCE(SUM(i.video_50),0) AS video_plays_50_rate'),
 | 
						||
            ThinkDb::raw('COALESCE(SUM(i.video_75),0) AS video_plays_75_rate'),
 | 
						||
            ThinkDb::raw('COALESCE(SUM(i.video_100),0) AS video_plays_100_rate'),
 | 
						||
            ThinkDb::raw('-1 AS hold_rate')
 | 
						||
        ]);
 | 
						||
 | 
						||
        // 6. 执行查询并获取聚合结果
 | 
						||
//        $aggregatedData = $creativeDataQuery->select();
 | 
						||
        // 6. 执行查询并获取聚合结果
 | 
						||
        $aggregatedData = $creativeDataQuery->select()->toArray();  // 转换为数组处理
 | 
						||
        $totalRecords   = count($aggregatedData);  // 总记录数
 | 
						||
 | 
						||
        // 计算分页起始索引
 | 
						||
        $startIndex = ($page - 1) * $pageSize;
 | 
						||
 | 
						||
 | 
						||
        // 打印调试 SQL 查询
 | 
						||
//$sql = $creativeDataQuery->getLastSql();
 | 
						||
//        dump($sql);
 | 
						||
 | 
						||
        // 7. 初始化广告创意的汇总数据和统计数据
 | 
						||
        $creativeSummaryData = [];
 | 
						||
//        $statisticsData      = $this->initializeStatistics();
 | 
						||
        $statisticsData = [];
 | 
						||
 | 
						||
        // 8. 遍历查询结果并计算每个 creative 的相关统计数据
 | 
						||
        foreach ($aggregatedData as $creativeData) {
 | 
						||
            // 初始化该 creative_id 的数据(如果不存在)
 | 
						||
            $creativeId = $creativeData['creative_id'];
 | 
						||
            if (!isset($creativeSummaryData[$creativeId])) {
 | 
						||
                $creativeSummaryData[$creativeId] = [
 | 
						||
                    'creative_id' => $creativeData['creative_id'],
 | 
						||
                    'platform' => $creativeData['platform'],
 | 
						||
                    'creative' => $creativeData['creative_name'],
 | 
						||
                    'creative_type' => $creativeData['creative_type'],
 | 
						||
                    'creative_url' => $creativeData['creative_url'] ?? '',
 | 
						||
                    'thumbnail_url' => $creativeData['thumbnail_url'] ?? '',
 | 
						||
                    'title' => $creativeData['title'] ?? '',
 | 
						||
                    'spend' => 0,
 | 
						||
                    'purchases_value' => 0,
 | 
						||
                    'roas' => 0,
 | 
						||
                    'cpa' => '-',
 | 
						||
                    'cpc_link_click' => '-',
 | 
						||
                    'cpm' => '-',
 | 
						||
                    'cpc_all' => '-',
 | 
						||
                    'aov' => '-',
 | 
						||
                    'click_to_atc_ratio' => '-',
 | 
						||
                    'atc_to_purchase_ratio' => '-',
 | 
						||
                    'purchases' => 0,
 | 
						||
                    'first_frame_retention' => '-',
 | 
						||
                    'thumbstop' => '-',
 | 
						||
                    'ctr_outbound' => '-',
 | 
						||
                    'click_to_purchase' => '-',
 | 
						||
                    'ctr_all' => '-',
 | 
						||
                    'video_plays_25_rate' => 0,
 | 
						||
                    'video_plays_50_rate' => 0,
 | 
						||
                    'video_plays_75_rate' => 0,
 | 
						||
                    'video_plays_100_rate' => 0,
 | 
						||
                    'hold_rate' => '-',
 | 
						||
                    'total_conversions_value' => 0,
 | 
						||
                    'total_conversions' => 0,
 | 
						||
                    'impressions' => 0,
 | 
						||
                    'clicks' => 0,
 | 
						||
                    'revenue' => 0,
 | 
						||
                    'ad_count' => 0
 | 
						||
                ];
 | 
						||
            }
 | 
						||
 | 
						||
            // 更新该 creative_id 的统计数据
 | 
						||
            $creativeSummaryData[$creativeId]['spend']                += $creativeData['total_spend'];
 | 
						||
            $creativeSummaryData[$creativeId]['purchases_value']      += $creativeData['total_purchases_value'];
 | 
						||
            $creativeSummaryData[$creativeId]['purchases']            += $creativeData['total_purchases'];
 | 
						||
            $creativeSummaryData[$creativeId]['impressions']          += $creativeData['total_impressions'];
 | 
						||
            $creativeSummaryData[$creativeId]['clicks']               += $creativeData['total_clicks'];
 | 
						||
            $creativeSummaryData[$creativeId]['revenue']              += $creativeData['total_revenue'];
 | 
						||
            $creativeSummaryData[$creativeId]['video_plays_25_rate']  += $creativeData['video_plays_25_rate'];
 | 
						||
            $creativeSummaryData[$creativeId]['video_plays_50_rate']  += $creativeData['video_plays_50_rate'];
 | 
						||
            $creativeSummaryData[$creativeId]['video_plays_75_rate']  += $creativeData['video_plays_75_rate'];
 | 
						||
            $creativeSummaryData[$creativeId]['video_plays_100_rate'] += $creativeData['video_plays_100_rate'];
 | 
						||
            // 计算 ROAS
 | 
						||
            $roas                                     = $creativeSummaryData[$creativeId]['spend'] > 0
 | 
						||
                ? $creativeSummaryData[$creativeId]['revenue'] / $creativeSummaryData[$creativeId]['spend']
 | 
						||
                : 0;
 | 
						||
            $creativeSummaryData[$creativeId]['roas'] = $roas > 0 ? number_format($roas, 2) . 'X' : '-';
 | 
						||
 | 
						||
            // 填充广告计数
 | 
						||
//            $creativeSummaryData[$creativeData->creative_id]['ad_count'] = rand(10, 200); // 每个 creative_id 对应一个广告
 | 
						||
        }
 | 
						||
//        dump($creativeSummaryData);
 | 
						||
 | 
						||
        // 汇总总体统计数据
 | 
						||
        $statisticsData['spend']           = array_sum(array_column($creativeSummaryData, 'spend'));
 | 
						||
        $statisticsData['purchases_value'] = array_sum(array_column($creativeSummaryData, 'purchases_value'));
 | 
						||
        $statisticsData['purchases']       = array_sum(array_column($creativeSummaryData, 'purchases'));
 | 
						||
        $statisticsData['impressions']     = array_sum(array_column($creativeSummaryData, 'impressions'));
 | 
						||
        $statisticsData['clicks']          = array_sum(array_column($creativeSummaryData, 'clicks'));
 | 
						||
        $statisticsData['revenue']         = array_sum(array_column($creativeSummaryData, 'revenue'));
 | 
						||
        // 汇总统计数据
 | 
						||
        $statistics = [
 | 
						||
            'spend' => '$' . number_format($statisticsData['spend'], 2),  // 格式化金额
 | 
						||
            'purchases_value' => '$' . number_format($statisticsData['purchases_value'], 2),  // 格式化金额
 | 
						||
            'roas' => $statisticsData['spend'] == 0 ? '-' : round($statisticsData['revenue'] / $statisticsData['spend'], 2) . 'X',
 | 
						||
            'cpa' => '-', // 格式化金额
 | 
						||
            'cpc_link_click' => '-', // 格式化金额
 | 
						||
            'cpm' => '-', // 格式化金额
 | 
						||
            'cpc_all' => '-', //格式化金额
 | 
						||
            'aov' => '-', // 格式化金额
 | 
						||
            'click_to_atc_ratio' => '-', // 格式化百分比
 | 
						||
            'atc_to_purchase_ratio' => '-',// 格式化百分比
 | 
						||
            'purchases' => $statisticsData['purchases'],
 | 
						||
            'first_frame_retention' => '-',
 | 
						||
            'thumbstop' => '-',
 | 
						||
            'ctr_outbound' => '-',
 | 
						||
            'click_to_purchase' => '-',
 | 
						||
            'ctr_all' => ($statisticsData['impressions'] > 0) ? number_format(($statisticsData['clicks'] / $statisticsData['impressions']) * 100, 2) . '%' : '-',  // 格式化为百分比
 | 
						||
            'video_plays_25_rate' => array_sum(array_column($creativeSummaryData, 'video_plays_25_rate')),
 | 
						||
            'video_plays_50_rate' => array_sum(array_column($creativeSummaryData, 'video_plays_50_rate')),
 | 
						||
            'video_plays_75_rate' => array_sum(array_column($creativeSummaryData, 'video_plays_75_rate')),
 | 
						||
            'video_plays_100_rate' => array_sum(array_column($creativeSummaryData, 'video_plays_100_rate')),
 | 
						||
            'hold_rate' => '-',// 格式化百分比
 | 
						||
        ];
 | 
						||
 | 
						||
        // 获取每个 creative_id 对应的广告数量
 | 
						||
        $creativeIds_from_google = array_keys(array_filter($creativeSummaryData, function ($item) {
 | 
						||
            return $item['platform'] == 2;
 | 
						||
        }));
 | 
						||
 | 
						||
        if (!empty($creativeIds_from_google)) {
 | 
						||
            // 将整数日期转为 Y-m-d 格式
 | 
						||
            $formattedStartDate = DateTime::createFromFormat('Ymd', $startDate)->format('Y-m-d');
 | 
						||
            $formattedEndDate   = DateTime::createFromFormat('Ymd', $endDate)->format('Y-m-d');
 | 
						||
            // 查询满足条件的 asset_id 和唯一 ad_id 计数
 | 
						||
            $ad_count_google = AssetRelation::whereIn('asset_id', $creativeIds_from_google)
 | 
						||
                ->whereBetween('date', [$formattedStartDate, $formattedEndDate])
 | 
						||
                ->group('asset_id')
 | 
						||
                ->column('COUNT(DISTINCT ad_id) AS ad_count', 'asset_id');
 | 
						||
        }
 | 
						||
        $creativeIds_from_fb_tk = array_keys(array_filter($creativeSummaryData, function ($item) {
 | 
						||
            return ($item['platform'] == 1 || $item['platform'] == 3);
 | 
						||
        }));
 | 
						||
        if (!empty($creativeIds_from_fb_tk)) {
 | 
						||
            $ad_count_fb_tk = BpsAdAd::whereIn('creative_id', $creativeIds_from_fb_tk)
 | 
						||
                ->group('creative_id')
 | 
						||
                ->column('COUNT(DISTINCT ad_id) as ad_count', 'creative_id');
 | 
						||
        }
 | 
						||
        // 确保变量存在,避免未定义错误
 | 
						||
        $ad_count_fb_tk  = $ad_count_fb_tk ?? [];
 | 
						||
        $ad_count_google = $ad_count_google ?? [];
 | 
						||
        // 合并数组
 | 
						||
        $ad_count_combined = $ad_count_fb_tk + $ad_count_google;
 | 
						||
//dump($ad_count_combined);
 | 
						||
//        dump($creativeIds_from_fb_tk);
 | 
						||
 | 
						||
        // 将广告数量填充到对应的 creativeSummaryData 中
 | 
						||
        foreach ($creativeSummaryData as $creativeId => &$creativeData) {
 | 
						||
            $creativeData['ad_count'] = $ad_count_combined[$creativeId] ?? 0;  // 如果没有匹配记录,默认填充 0
 | 
						||
//            dump($creativeData);
 | 
						||
        }
 | 
						||
        unset($creativeData);  // 解除引用
 | 
						||
//        dump($creativeSummaryData);
 | 
						||
 | 
						||
        // 格式化返回的创意数据
 | 
						||
        $formattedData = array_map(function ($item) {
 | 
						||
            return [
 | 
						||
                'creative_id' => $item['creative_id'],
 | 
						||
                'creative' => $item['creative'] ?: '-',
 | 
						||
                'creative_type' => $item['creative_type'],
 | 
						||
                'creative_url' => $item['creative_url'],
 | 
						||
                'thumbnail_url' => $item['thumbnail_url'],
 | 
						||
                'spend' => '$' . number_format($item['spend'], 2),
 | 
						||
                'purchases_value' => '$' . number_format($item['purchases_value'], 2),
 | 
						||
                'roas' => $item['roas'],
 | 
						||
                'cpa' => '-',
 | 
						||
                'cpc_link_click' => '-',
 | 
						||
                'cpm' => '-',
 | 
						||
                'cpc_all' => '-',
 | 
						||
                'aov' => '-',
 | 
						||
                'click_to_atc_ratio' => '-',
 | 
						||
                'atc_to_purchase_ratio' => '-',
 | 
						||
                'purchases' => $item['purchases'],
 | 
						||
                'first_frame_retention' => '-',
 | 
						||
                'thumbstop' => '-',
 | 
						||
                'ctr_outbound' => '-',
 | 
						||
                'click_to_purchase' => '-',
 | 
						||
                'ctr_all' => ($item['impressions'] > 0) ? number_format(($item['clicks'] / $item['impressions']) * 100, 2) . '%' : '-',
 | 
						||
                'total_conversions_value' => '$' . number_format($item['purchases_value'], 2), //准备删除
 | 
						||
                'impressions' => $item['impressions'],
 | 
						||
                'video_plays_25_rate' => $item['video_plays_25_rate'],
 | 
						||
                'video_plays_50_rate' => $item['video_plays_50_rate'],
 | 
						||
                'video_plays_75_rate' => $item['video_plays_75_rate'],
 | 
						||
                'video_plays_100_rate' => $item['video_plays_100_rate'],
 | 
						||
                'hold_rate' => '-',
 | 
						||
                'ad_count' => $item['ad_count'],
 | 
						||
                // 添加更多的格式化字段
 | 
						||
            ];
 | 
						||
        }, $creativeSummaryData);
 | 
						||
//        $formattedData = array_values($creativeSummaryData);  // 未分页处理
 | 
						||
        $pagedData = array_slice(array_values($formattedData), $startIndex, $pageSize);  // 分页处理
 | 
						||
        // 9. 返回分页数据
 | 
						||
        return [
 | 
						||
            'data' => $pagedData,
 | 
						||
            'total' => count($creativeSummaryData),
 | 
						||
            'statistics' => $statistics, // 汇总的统计数据
 | 
						||
            'pagination' => [
 | 
						||
                'startIndex' => ($page - 1) * $pageSize,
 | 
						||
                'maxResults' => $pageSize,
 | 
						||
                'count' => count($creativeSummaryData),
 | 
						||
                'pageNo' => $page,
 | 
						||
                'pageSize' => $pageSize,
 | 
						||
                'pages' => ceil(count($creativeSummaryData) / $pageSize)
 | 
						||
            ]
 | 
						||
        ];
 | 
						||
    }
 | 
						||
 | 
						||
 | 
						||
    /**
 | 
						||
     * 初始化统计数据
 | 
						||
     */
 | 
						||
    private function initializeStatistics()
 | 
						||
    {
 | 
						||
        return [
 | 
						||
            'impressions' => 0,
 | 
						||
            'clicks' => 0,
 | 
						||
            'revenue' => 0,
 | 
						||
            'spend' => 0,
 | 
						||
            'purchases_value' => 0,
 | 
						||
            'roas' => 0,
 | 
						||
            'cpa' => '-',
 | 
						||
            'cpc_link_click' => '-',
 | 
						||
            'cpm' => '-',
 | 
						||
            'cpc_all' => '-',
 | 
						||
            'aov' => '-',
 | 
						||
            'click_to_atc_ratio' => '-',
 | 
						||
            'atc_to_purchase_ratio' => '-',
 | 
						||
            'purchases' => 0,
 | 
						||
            'first_frame_retention' => '-',
 | 
						||
            'thumbstop' => '-',
 | 
						||
            'ctr_outbound' => '-',
 | 
						||
            'click_to_purchase' => '-',
 | 
						||
            'ctr_all' => '-',
 | 
						||
            'video_plays_25_rate' => 0,
 | 
						||
            'video_plays_50_rate' => 0,
 | 
						||
            'video_plays_75_rate' => 0,
 | 
						||
            'video_plays_100_rate' => 0,
 | 
						||
            'hold_rate' => '-',
 | 
						||
            // Add other stats as necessary
 | 
						||
        ];
 | 
						||
    }
 | 
						||
 | 
						||
    public function getAdcycleInsight($platformType, $customerIds, $cycle, $startDate = null, $endDate = null)
 | 
						||
    {
 | 
						||
        // 1. 查询全部数据集
 | 
						||
        $adcycleDataQuery = BpsAdInsight::alias('i');
 | 
						||
        if ($platformType != 0) {
 | 
						||
            $adcycleDataQuery->where('i.platform', $platformType); // 只有 platformType 不为 0 时才添加筛选
 | 
						||
        }
 | 
						||
//dump($customerIds);
 | 
						||
        // 2. 客户 ID 过滤(如果提供了)
 | 
						||
        if (!empty($customerIds)) {
 | 
						||
            $adcycleDataQuery->whereIn('i.account_id', $customerIds);
 | 
						||
        } else {
 | 
						||
            return [
 | 
						||
                'data' => [],
 | 
						||
                'total' => 0
 | 
						||
            ];
 | 
						||
        }
 | 
						||
 | 
						||
        // 3. 时间范围筛选
 | 
						||
        if ($startDate && $endDate) {
 | 
						||
            $adcycleDataQuery->whereBetween('i.date', [$startDate, $endDate]);
 | 
						||
        }
 | 
						||
 | 
						||
        // 4. 获取数据并按日期聚合
 | 
						||
        $adcycleData = $adcycleDataQuery->field([
 | 
						||
            'i.date',
 | 
						||
            ThinkDb::raw('COALESCE(SUM(i.spend) / 1000000, 0) as spend'),
 | 
						||
            ThinkDb::raw('COALESCE(SUM(i.revenue), 0) as revenue')
 | 
						||
        ])
 | 
						||
            ->group('i.date') // 按日期进行分组
 | 
						||
            ->select();
 | 
						||
 | 
						||
//        dump(ThinkDb::getLastSql());
 | 
						||
 | 
						||
        // 5. 处理数据,按照周期进行分组
 | 
						||
        $processedData = $this->processDataByCycle($adcycleData->toArray(), $cycle);
 | 
						||
 | 
						||
        // 6. 返回处理后的数据
 | 
						||
        return $processedData;
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 按周期处理数据
 | 
						||
     *
 | 
						||
     * @param array $adcycleData 原始数据
 | 
						||
     * @param string $cycle 周期类型(daily, weekly, monthly)
 | 
						||
     * @return array 按照周期分组后的数据
 | 
						||
     */
 | 
						||
    private function processDataByCycle($adcycleData, $cycle)
 | 
						||
    {
 | 
						||
        // 排序 adcycleData 数组,确保按照日期升序排列
 | 
						||
        usort($adcycleData, function ($a, $b) {
 | 
						||
            return $a['date'] <=> $b['date'];  // 按照 'YYYYMMDD' 字符顺序排序
 | 
						||
        });
 | 
						||
        $groupedData = [];
 | 
						||
 | 
						||
        foreach ($adcycleData as $data) {
 | 
						||
            // 根据周期类型,调整日期分组
 | 
						||
            switch ($cycle) {
 | 
						||
                case 1:
 | 
						||
                    // 将 'YYYYMMDD' 格式的日期转换为 'YYYY-MM-DD'
 | 
						||
                    $date = DateTime::createFromFormat('Ymd', $data['date']);  // 转换为 DateTime 对象
 | 
						||
                    $key  = $date ? $date->format('Y-m-d') : '';  // 格式化为 'YYYY-MM-DD'
 | 
						||
                    break;
 | 
						||
                case 2:
 | 
						||
                    // 使用 ISO 周格式来分组
 | 
						||
                    $key = $this->getWeekFromDate($data['date']);
 | 
						||
                    break;
 | 
						||
                case 3:
 | 
						||
                    // 按年-月格式分组
 | 
						||
                    $key = $this->getMonthFromDate($data['date']);
 | 
						||
                    break;
 | 
						||
                default:
 | 
						||
                    throw new \InvalidArgumentException("Invalid cycle value. Use 'daily', 'weekly' or 'monthly'.");
 | 
						||
            }
 | 
						||
 | 
						||
            // 汇总数据
 | 
						||
            if (!isset($groupedData[$key])) {
 | 
						||
                $groupedData[$key] = [
 | 
						||
                    'spend' => 0,
 | 
						||
                    'revenue' => 0,
 | 
						||
//                    'conversions_value' => 0,
 | 
						||
//                    'conversions' => 0,
 | 
						||
//                    'impressions' => 0,
 | 
						||
//                    'clicks' => 0
 | 
						||
                ];
 | 
						||
            }
 | 
						||
 | 
						||
            // 累加数据
 | 
						||
            $groupedData[$key]['spend']   += $data['spend'];
 | 
						||
            $groupedData[$key]['revenue'] += $data['revenue'];
 | 
						||
//            $groupedData[$key]['conversions_value'] += $data->purchases_value;
 | 
						||
//            $groupedData[$key]['conversions']       += $data->purchases;
 | 
						||
//            $groupedData[$key]['impressions']       += $data->impressions;
 | 
						||
//            $groupedData[$key]['clicks']            += $data->clicks;
 | 
						||
        }
 | 
						||
 | 
						||
        // 格式化返回数据
 | 
						||
        $formattedData = [];
 | 
						||
        foreach ($groupedData as $key => $values) {
 | 
						||
            $roas            = $values['spend'] > 0 ? $values['revenue'] / $values['spend'] : 0;
 | 
						||
            $formattedData[] = [
 | 
						||
                'date' => $key,
 | 
						||
                'spend' => round($values['spend'], 2),
 | 
						||
                'roas' => $roas > 0 ? round($roas, 2) : 0
 | 
						||
            ];
 | 
						||
        }
 | 
						||
        // 如果没有数据,返回空数组并提供默认的分页信息
 | 
						||
        if (empty($formattedData)) {
 | 
						||
            return [
 | 
						||
                'data' => [],
 | 
						||
                'total' => 0,
 | 
						||
            ];
 | 
						||
        }
 | 
						||
 | 
						||
// 返回格式化后的数据
 | 
						||
        return [
 | 
						||
            'data' => $formattedData,
 | 
						||
            'total' => count($formattedData),
 | 
						||
        ];
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 获取周数(基于 ISO 周格式)
 | 
						||
     *
 | 
						||
     * @param int $date 日期(格式:YYYYMMDD)
 | 
						||
     * @return string ISO 周格式(YYYY-Www)
 | 
						||
     */
 | 
						||
    private function getWeekFromDate($date)
 | 
						||
    {
 | 
						||
        // 将日期转换为 PHP DateTime 对象
 | 
						||
        $dateStr = (string)$date;
 | 
						||
        $dateObj = \DateTime::createFromFormat('Ymd', $dateStr);
 | 
						||
 | 
						||
        // 获取 ISO 周格式
 | 
						||
        return $dateObj->format('o-W') . 'W';
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * 获取月分(格式:YYYY-MM)
 | 
						||
     *
 | 
						||
     * @param int $date 日期(格式:YYYYMMDD)
 | 
						||
     * @return string 月份格式(YYYY-MM)
 | 
						||
     */
 | 
						||
    private function getMonthFromDate($date)
 | 
						||
    {
 | 
						||
        // 将日期转换为 PHP DateTime 对象
 | 
						||
        $dateStr = (string)$date;
 | 
						||
        $dateObj = \DateTime::createFromFormat('Ymd', $dateStr);
 | 
						||
 | 
						||
        // 获取年-月格式
 | 
						||
        return $dateObj->format('Y-m');
 | 
						||
    }
 | 
						||
 | 
						||
    public static function getPlatformType($thirdType)
 | 
						||
    {
 | 
						||
        $platformMapping = [
 | 
						||
            'facebook' => 1,
 | 
						||
            'google' => 2,
 | 
						||
            'tiktok' => 3,
 | 
						||
        ];
 | 
						||
 | 
						||
        return $platformMapping[$thirdType] ?? null;  // 如果不存在的第三方类型,返回 null
 | 
						||
    }
 | 
						||
 | 
						||
}
 |