diff --git a/app/controller/BpsAdController.php b/app/controller/BpsAdController.php index c532025..00f0ea4 100644 --- a/app/controller/BpsAdController.php +++ b/app/controller/BpsAdController.php @@ -97,6 +97,15 @@ class BpsAdController // 获取客户ID数组 $accountIds = array_unique(array_column($accounts, 'account_id')); + $endDateLastWeek = (int)date('Ymd'); + $startDateLastWeek = (int)date('Ymd', strtotime('-6 days')); +// dump($startDateLastWeek, $endDateLastWeek); + if ($startDateLastWeek === $startDate && $endDateLastWeek === $endDate) { + $ad_data_count = $this->adsInsightService::getAdCountData($accountIds,$startDate, $endDate); + } else { + $ad_data_count = []; + } + // 调用 Service 层查询广告列表 $result = $this->adsInsightService::getAccountList( $platformType, // 平台类型 @@ -108,6 +117,8 @@ class BpsAdController $endDate, // 结束日期 ); + $result['ad_data_count'] = $ad_data_count; + // 返回结果 return $this->successResponse($result, $request); } @@ -382,7 +393,7 @@ class BpsAdController $accountIds = array_unique(array_column($accounts, 'account_id')); // dump($accountIds); // 调用 Service 层查询广告组列表 - $result = $this->adsInsightService->getCreativeInsightData( + $result = $this->adsInsightService::getCreativeInsightData( $platformType, $accountIds, // 客户 ID 数组 $page, // 页码 diff --git a/app/service/AdsInsightService.php b/app/service/AdsInsightService.php index ffe26ee..767e5d4 100644 --- a/app/service/AdsInsightService.php +++ b/app/service/AdsInsightService.php @@ -19,6 +19,7 @@ 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 { @@ -29,38 +30,155 @@ class AdsInsightService // 其他状态可以继续添加 ]; + // 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) + public static function getCampaignList($platformType, $customerIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null, $status = 0, $countOnly = false) { // 检查 customerIds 是否为空,直接返回空结构 if (empty($customerIds)) { - return [ + return $countOnly ? 0 : [ 'pagination' => [ 'startIndex' => 0, - 'maxResults' => $pageSize, + 'maxResults' => 0, 'count' => 0, 'pageNo' => $page, 'pageSize' => $pageSize, 'pages' => 0, ], - 'statistics' => [ - ], + 'statistics' => [], 'data' => [], ]; } - // 动态构建日期条件 - $dateCondition = ''; - if ($startDate && $endDate) { - $dateCondition = "d.date BETWEEN '{$startDate}' AND '{$endDate}'"; - } else { - } // 基础查询:广告活动和日数据表联接 $query = BpsAdCampaign::alias('c') ->cache(false) // 强制不使用缓存 - ->leftJoin('bps.bps_ads_insights d', "c.campaign_id = d.ad_campaign_id AND c.platform_type = d.platform AND {$dateCondition}") + ->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, @@ -190,37 +308,45 @@ class AdsInsightService /** * 获取广告组列表 */ - public static function getAdsetList($platformType, $customerIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null, $status = 0) + public static function getAdsetList($platformType, $customerIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null, $status = 0, $countOnly = false) { // 检查 customerIds 是否为空,直接返回空结构 if (empty($customerIds)) { - return [ + return $countOnly ? 0 : [ 'pagination' => [ 'startIndex' => 0, - 'maxResults' => $pageSize, + 'maxResults' => 0, 'count' => 0, 'pageNo' => $page, 'pageSize' => $pageSize, 'pages' => 0, ], - 'statistics' => [ - ], + '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 = BpsAdSet::alias('s') - ->cache(false) // 强制不使用缓存 - ->leftJoin('bps.bps_ads_insights d', "s.ad_set_id = d.ad_set_id AND s.platform_type = d.platform AND {$dateCondition}") - ->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, + + $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, @@ -243,7 +369,7 @@ class AdsInsightService $query->where(function ($query) use ($keyword, $platformType) { if ($keyword) { // $query->where('s.name', 'like', '%' . $keyword . '%'); - $query->whereRaw('LOWER(s.name) LIKE ?', ['%' . strtolower($keyword) . '%']); + $query->whereRaw('LOWER(s.name) LIKE ?', ['%' . strtolower($keyword) . '%']); } if ($platformType) { $platformType = (int)$platformType; @@ -348,12 +474,11 @@ class AdsInsightService ]; } - public static function getAccountList($platformType, $customerIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null) + public static function getAccountList($platformType, $customerIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null, $countOnly = false) { - - // 检查 customerIds 是否为空,直接返回空结构 + // 检查 customerIds 是否为空,直接返回计数为 0 if (empty($customerIds)) { - return [ + return $countOnly ? 0 : [ 'pagination' => [ 'startIndex' => 0, 'maxResults' => $pageSize, @@ -366,18 +491,25 @@ class AdsInsightService '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 = ThirdUserAdvertiser::alias('a') - ->cache(false) // 强制不使用缓存 - ->leftJoin('bps.bps_ads_insights d', "a.advertiser_id = d.account_id AND {$dateCondition}") - ->leftJoin('bps.bps_third_user u', 'a.doc_ = u.id') // 联接广告组表,获取 ad_set_name + // 其他联表及字段计算 + $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, @@ -403,7 +535,7 @@ class AdsInsightService $query->whereRaw('LOWER(a.advertiser_name) LIKE ?', ['%' . strtolower($keyword) . '%']); } if ($platformType) { - $a = (int)$platformType; + $a = (int)$platformType; $platformTypeNames = [1 => 'facebook', 2 => 'google', 3 => 'tiktok']; $query->where('u.third_type', '=', $platformTypeNames[$a]); } @@ -463,7 +595,7 @@ class AdsInsightService $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]; + $platformTypeIds = ['facebook' => 1, 'google' => 2, 'tiktok' => 3]; return [ 'user_id' => $item['advertiser_id'], 'platform_type' => $platformTypeIds[$item['third_type']], @@ -510,14 +642,14 @@ class AdsInsightService } - public static function getAdList($platformType, $customerIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null, $status = 0) + public static function getAdList($platformType, $customerIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null, $status = 0, $countOnly = false) { // 检查 customerIds 是否为空,直接返回空结构 if (empty($customerIds)) { - return [ + return $countOnly ? 0 : [ 'pagination' => [ 'startIndex' => 0, - 'maxResults' => $pageSize, + 'maxResults' => 0, 'count' => 0, 'pageNo' => $page, 'pageSize' => $pageSize, @@ -528,18 +660,25 @@ class AdsInsightService ]; } + // 基础查询:广告活动和日数据表联接 + $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 = BpsAdAd::alias('a') - ->cache(false) // 强制不使用缓存 - ->leftJoin('bps.bps_ads_insights d', "a.ad_id = d.ad_id AND a.platform_type = d.platform AND {$dateCondition}") - ->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, + $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, @@ -951,7 +1090,7 @@ class AdsInsightService } - public function getCreativeInsightData($platformType, $customerIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null) + public static function getCreativeInsightData($platformType, $customerIds, $page, $pageSize, $keyword, $startDate = null, $endDate = null, $countOnly = false) { // 1. 创建查询对象,初始化 BpsAdCreativeInsight 查询 $creativeDataQuery = BpsAdCreativeInsight::alias('i') @@ -969,7 +1108,7 @@ class AdsInsightService if (!empty($customerIds)) { $creativeDataQuery->whereIn('i.account_id', $customerIds); } else { - return [ + return $countOnly ? 0 :[ 'data' => [], 'total' => 0, 'statistics' => [], @@ -982,6 +1121,10 @@ class AdsInsightService ] ]; } + // 仅返回记录数时的逻辑 + if ($countOnly) { + return $creativeDataQuery->count() ?: 0; + } // 4. 关键词过滤 if ($keyword) {