model = new AgentSite(); $this->gameLogic = new GameLogic(); $this->mediaListLogic = new MediaListLogic(); } /** * 获取广告位options */ public function getAgentSiteOptions() { $data = $this->model->select()->toArray(); return $data; } /** * 获取头条账号列表 */ public function getTtAccountList() { $where = [ 'media_id' => 1, 'status' => 1, ]; return Db::connect('db_advert') ->table('ad_advertiser_list') ->where($where)->select()->toArray(); } /** * 导出分包标识数据 */ public function exportGamePackageKs($data = []) { $file_name = $data['title'].'_标识数据_'.date('YmdHis').'.xlsx'; $header = $data['title']=='快手分包' ? ['渠道','备注'] : ['备注','渠道']; $data = array_map(function($item){ return [ 'agent_id' => explode(',', $item)[0], 'remark' => explode(',', $item)[1] ]; }, $data['data']); $writer = new OpenSpoutWriter($file_name); $writer->setWidth([15, 15]); $writer->setHeader($header); $writer->setData($data); $file_path = $writer->returnFile(); return response()->download($file_path, urlencode($file_name)); } /** * 获取头条推送的access_token */ public function getTtAccessToken($advertiserId) { $where = [ 'a.media_id' => 1, 'a.advertiser_id' => $advertiserId, ]; return Db::connect('db_advert') ->table('ad_advertiser_list')->alias('a') ->join('ad_advertiser_bm b', 'a.bmid=b.id', 'left') ->where($where) ->value('access_token'); } /** * 新增广告位 */ public function add($data): mixed { $insertData = []; for($i=0;$i<$data['num'];$i++){ $insertData[] = [ 'media_id' => $data['media_id'], 'agent_id' => $data['agent_id'], 'auth_id' => $data['auth_id'], 'name' => $data['name'].$i, ]; } $this->model->insertAll($insertData); return true; } /** * 获取头条媒体配置 */ public function getTtMediaConfig() { return Db::connect('db_advert')->table('media_list')->where('id', 1)->find(); } /** * 获取头条媒体配置 */ public function getTtAssetId($data = []) { return Db::connect('db_advert_log')->table('ad_jrtt_asset')->where('game_id', $data['game_id'])->where('advertiser_id', $data['advertiser_id'])->value('assets_id'); } /** * 头条推送事件 */ public function ttPushNewEvent($data = []): void { // 检查广告位是否传入 if(empty($data['site_ids'])){ throw new ApiException('请选择广告位'); } // 获取头条的游戏 $toutiaoGameData = (new GamePackageLogic())->getToutiaoGames(); // 广告位ID集合 $siteIds = explode(",", $data['site_ids']); $gamePackageId = $data['game_package_id']; $fb = $data['fb']; // 分包标识 $zh = $data['zh']; // 推送转化跟踪 $advertiserId = $data['advertiser_id']; // 头条广告主ID // 检查游戏是否为头条媒体的母包 if(!$gamePackageId || empty($toutiaoGameData[$gamePackageId])){ throw new ApiException('请选择推送的头条母包'); } $gameId = $toutiaoGameData[$gamePackageId]['game_id'] ?? 0; $appId = $toutiaoGameData[$gamePackageId]['tt_appid'] ?? 0; if(!$appId){ throw new ApiException('母包管理没有设置头条APPID'); } $packageId = $toutiaoGameData[$gamePackageId]['tt_package_id'] ?? ""; if(!$packageId){ throw new ApiException('母包管理没有设置对应的主包名'); } // 获取广告位数据 $agentSiteMap = $this->model->where(['id'=>$siteIds, 'media_id'=>1])->column('agent_id', 'id'); if(count($agentSiteMap) != count($siteIds)){ throw new ApiException('请选择头条媒体的广告位'); } // 获取头条的access_token $accessToken = $this->getTtAccessToken($advertiserId); if(!$accessToken){ throw new ApiException('推送头条的-access_token获取失败'); } $getTtAssetAppMap = $this->getTtAssetMap($advertiserId, $accessToken); $assetId = $getTtAssetAppMap[$appId] ?? 0; if(!$assetId){ throw new ApiException('媒体账户后台没有设置对应APP资产'); } // 推送头条分包 if($fb){ // 头条游戏平台 $os = $toutiaoGameData[$gamePackageId]['game_os']; if($os!=1){ throw new ApiException('只有安卓可以推送分包'); } $channelList = []; $channelListLog = []; foreach ($siteIds as $siteId) { $agentId = $agentSiteMap[$siteId] ?? 0; $channelId = $gameId.'_'.$agentId.'_'.$siteId; $channelList[] = [ 'channel_id' => $channelId, 'remark' => $toutiaoGameData[$gamePackageId]['name'].'-'.$siteId, ]; //记录提交信息 $channelListLog[] = [ 'game_id' => $gameId, 'agent_id' => $agentId, 'site_id' => $siteId, 'advertiser_id' => $advertiserId, 'package_id' => $toutiaoGameData[$gamePackageId]['tt_package_id'], 'remark' => $toutiaoGameData[$gamePackageId]['name'].'-'.$siteId, ]; } Db::connect('db_advert_log')->table('ad_jrtt_channel_package')->insertAll($channelListLog); // Todo 推送分包 $result = $this->sendTtPushPackage($advertiserId, $accessToken, $packageId, $channelList); if($result['message']!='OK'){ throw new ApiException('推送头条分包失败'); } } // 推送转化跟踪 if($zh){ $mediaInfo = $this->getTtMediaConfig(); foreach ($siteIds as $siteId) { $agentId = $agentSiteMap[$siteId] ?? 0; $channelId = $gameId.'_'.$agentId.'_'.$siteId; $groupName = $toutiaoGameData[$gamePackageId]['name'].'_'.$siteId; if($toutiaoGameData[$gamePackageId]['ios_appid']>0){ $clickUrl = $mediaInfo['iosurl']; $downloadUrl = 'https://itunes.apple.com/cn/app/id'.$toutiaoGameData[$gamePackageId]['ios_appid']; } else { $clickUrl = $mediaInfo['andurl']; $downloadUrl = 'https://apps.bytesfield.com/download/extend/cur/'.$toutiaoGameData[$gamePackageId]['tt_package_id'].'/'.$channelId; } $clickUrl = str_replace('__SITE__', $channelId, $clickUrl); $apiResponse = $this->sendTtPushTrackUrl($advertiserId, $accessToken, $assetId, $downloadUrl, $clickUrl, $groupName); $log = [ 'game_package_id' => $gamePackageId, 'game_id' => $gameId, 'agent_id' => $agentId, 'site_id' => $siteId, 'advertiser_id' => $advertiserId, 'assets_id' => $getTtAssetAppMap['assets_id'], 'download_url' => $downloadUrl, 'click_url' => $clickUrl, 'group_name' => $groupName, 'api_response' => $apiResponse, ]; Db::connect('db_advert_log')->table('ad_jrtt_track_list')->save($log); } } } // 推送分包 protected function sendTtPushPackage($advertiserId, $accessToken, $packageId, $channelList) { // 推送给头条数据 $pushData = [ 'account_id' => $advertiserId, 'package_id' => $packageId, 'channel_list' => $channelList, 'mode' => 'Manual', ]; $url = 'https://ad.oceanengine.com/open_api/2/tools/app_management/extend_package/create/'; // 发送请求 $client = new Client(); $headers = [ 'Access-Token' => $accessToken, ]; // 发起 POST 请求 $response = $client->post($url, [ 'headers' => $headers, 'json' => $pushData, // 如果是 application/json ]); // 获取响应内容 $body = $response->getBody()->getContents(); return json_decode($body, true); } // 推送监测链接 protected function sendTtPushTrackUrl($advertiserId, $accessToken, $assetId, $downloadUrl, $clickUrl, $groupName): string { $pushData = json_encode([ 'advertiser_id' => $advertiserId, 'assets_id' => $assetId + 0, 'download_url' => $downloadUrl, 'track_url_groups' => [ [ 'action_track_url' => $clickUrl, 'track_url' => $clickUrl, 'track_url_group_name' => $groupName, ], ], ]); $url = "https://ad.oceanengine.com/open_api/2/event_manager/track_url/create/"; // 发送请求 $client = new Client(); $headers = [ 'Access-Token' => $accessToken, ]; // 发起 POST 请求 $response = $client->post($url, [ 'headers' => $headers, 'json' => $pushData, // 如果是 application/json ]); // 获取响应内容 return $response->getBody()->getContents(); } // 获取广告账户资产信息 protected function getTtAssetMap($advertiserId, $accessToken): array { $headers = [ 'Access-Token' => $accessToken, 'Content-Type' => 'application/json' ]; $url = "https://api.oceanengine.com/open_api/2/tools/event/all_assets/list/?advertiser_id={$advertiserId}"; $client = new Client(); // 发起 POST 请求 $response = $client->get($url, [ 'headers' => $headers, ]); // 获取响应内容 $result = $response->getBody()->getContents(); $result = json_decode($result, true); $appMap = []; if($result['message']=='OK'){ $assetIds = array_column($result['data']['asset_list'], "asset_id"); // Todo 获取资产详情 $url = "https://api.oceanengine.com/open_api/2/tools/event/all_assets/detail/?advertiser_id={$advertiserId}&asset_ids=".json_encode($assetIds); $client = new Client(); // 发起 POST 请求 $response = $client->get($url, [ 'headers' => $headers, ]); // 获取响应内容 $result = $response->getBody()->getContents(); $result = json_decode($result, true); $assetList = $result['data']['asset_list'] ?? []; $appMap = array_column($assetList, null, 'app_id'); } return $appMap; } /** * 联调生成参数 */ public function linkDebugGenerateParams($game,$data) { // .env中获取 $baseUrl = env('WATCH_LINK_BASE_API'); // 广告位信息:游戏ID_渠道ID_广告位ID $siteInfo = $game['id'].'_'.$data['agent_id'].'_'.$data['site_id']; // 包名 $package_name = $game['package_name']; // 根据媒体ID读取监测链接 $media_info = $this->mediaListLogic->read($data['media_id']); // 点击监测链接 $clickUrl = ''; if($media_info && $game['os'] ==1){ $clickUrl = $media_info['andurl']; } else if($media_info && $game['os'] ==2){ $clickUrl = $media_info['iosurl']; // appid $appid = $game['ios_appid']; $download_url = 'https://itunes.apple.com/cn/app/id'.$game['ios_appid']; } else if($media_info && ($game['os'] ==3 || $game['os'] ==4)){ $clickUrl = $media_info['xyxurl']; // 小游戏路径参数 $wxgamepro ="?track_id=".$siteInfo."&ext_channel=".$media_info['channel_name'].$media_info['appleturl']; } $clickUrl = str_replace('__SITE__', $siteInfo, $clickUrl); return [ 'site_info' => $siteInfo, 'appid' => $appid??'', 'download_url' => $download_url??'', 'package_name' => $package_name, 'click_url' => $baseUrl.$clickUrl, 'wxgamepro' => $wxgamepro ?? "", ]; } public function getSiteAuth(): array { $siteList = $this->model->select(); $siteMap = []; foreach ($siteList as $site) { $siteMap[$site['id']] = $site; } return $siteMap; } }