作者 赵彬吉

rank_data

@@ -2,9 +2,8 @@ @@ -2,9 +2,8 @@
2 2
3 namespace App\Console\Commands\RankData; 3 namespace App\Console\Commands\RankData;
4 4
5 -use App\Helper\Arr;  
6 use App\Helper\QuanqiusouApi; 5 use App\Helper\QuanqiusouApi;
7 -use App\Models\Project\DeployBuild; 6 +use App\Http\Logic\Bside\RankData\RankDataLogic;
8 use App\Models\Project\DeployOptimize; 7 use App\Models\Project\DeployOptimize;
9 use App\Models\Project\Project; 8 use App\Models\Project\Project;
10 use App\Models\RankData\RankData as GoogleRankModel; 9 use App\Models\RankData\RankData as GoogleRankModel;
@@ -39,6 +38,9 @@ class RankData extends BaseCommands @@ -39,6 +38,9 @@ class RankData extends BaseCommands
39 */ 38 */
40 public function do() 39 public function do()
41 { 40 {
  41 + //所有项目 今日是否达标 重置
  42 + Project::where('is_remain_today', 1)->update(['is_remain_today' => 0]);
  43 +
42 $error = 0; 44 $error = 0;
43 $api = new QuanqiusouApi(); 45 $api = new QuanqiusouApi();
44 //有排名api编号的项目 46 //有排名api编号的项目
@@ -50,122 +52,14 @@ class RankData extends BaseCommands @@ -50,122 +52,14 @@ class RankData extends BaseCommands
50 return false; 52 return false;
51 } 53 }
52 foreach ($list as $item){ 54 foreach ($list as $item){
53 - $model = GoogleRankModel::where('project_id', $item['project_id'])->where('lang', '')->first();  
54 - if (!$model || $model->updated_date != date('Y-m-d')) {  
55 - $res = $api->getGoogleRank($item['api_no']);  
56 - if(!$res){  
57 - $error++;  
58 - continue;  
59 - }  
60 - //收录数  
61 - $indexed_pages_num = $site_res[$item['api_no']] ?? 0;  
62 - $this->save_rank($item['project_id'], $res, $indexed_pages_num);  
63 - }  
64 - //有小语种的  
65 - $lang_list = $api->getLangList();  
66 - if(!empty($lang_list[$item['api_no']])){  
67 - $model = GoogleRankModel::where('project_id', $item['project_id'])->where('lang', '<>', '')->first();  
68 - if (!$model || $model->updated_date != date('Y-m-d')) {  
69 - $res = $api->getGoogleRank($item['api_no'], 1);  
70 - if(!$res){  
71 - $error++;  
72 - continue;  
73 - }  
74 - $data = [];  
75 - //不同的小语种取出来  
76 - foreach ($res as $keyword => $v){  
77 - $data[Arr::last($v)['lang']][$keyword] = $v;  
78 - }  
79 - foreach ($data as $lang => $rank){  
80 - $this->save_rank($item['project_id'], $rank, 0, $lang);  
81 - }  
82 - } 55 + try {
  56 + (new RankDataLogic())->syncRankData($item['api_no']);
  57 + }catch (\Exception $e){
  58 + LogUtils::info('rank_data error:' . $e->getMessage());
  59 + $error++;
  60 + continue;
83 } 61 }
84 } 62 }
85 return !$error; 63 return !$error;
86 } 64 }
87 -  
88 - /**  
89 - * @param $project_id  
90 - * @param int $indexed_pages_num  
91 - * @param $data  
92 - * @param string $lang  
93 - * @author zbj  
94 - * @date 2023/5/8  
95 - */  
96 - public function save_rank($project_id, $data, int $indexed_pages_num = 0, string $lang = ''){  
97 - $without_project_ids = []; //不用处理排名的项目  
98 -  
99 - $first_num = $first_page_num = $first_three_pages_num = $first_five_pages_num = $first_ten_pages_num = 0;  
100 -  
101 - if(!$lang){  
102 - foreach ($data as &$ranks){  
103 - ksort($ranks);  
104 - foreach ($ranks as &$rank){  
105 - //处理排名  
106 - if(!in_array($project_id, $without_project_ids)){  
107 - if($rank['position'] >= 10){  
108 - $rank['position'] -= 5;  
109 - }  
110 - //todo 需要特殊处理排名的项目  
111 - }  
112 - }  
113 - $last = Arr::last($ranks);  
114 - //第一名  
115 - if($last['position'] == 1){  
116 - $first_num ++;  
117 - }  
118 - //排名第一页  
119 - if($last['position'] > 0 && $last['position'] <= 10){  
120 - $first_page_num ++;  
121 - }  
122 - //排名前三页  
123 - if($last['position'] > 0 && $last['position'] <= 30){  
124 - $first_three_pages_num ++;  
125 - }  
126 - //排名前五页  
127 - if($last['position'] > 0 && $last['position'] <= 50){  
128 - $first_five_pages_num ++;  
129 - }  
130 - //排名前十页  
131 - if($last['position'] > 0 && $last['position'] <= 100){  
132 - $first_ten_pages_num ++;  
133 - }  
134 - }  
135 - }  
136 -  
137 - $where = [  
138 - 'project_id' => $project_id,  
139 - 'lang' => $lang  
140 - ];  
141 - $model = GoogleRankModel::where($where)->first();  
142 - if(!$model){  
143 - $model = new GoogleRankModel();  
144 - }  
145 -  
146 - //关键词达标天数  
147 - $model->is_compliance = 0;  
148 - if($model->updated_date != date('Y-m-d')){  
149 - //保证关键词数  
150 - $keyword_num = DeployBuild::where('project_id', $project_id)->value('keyword_num');  
151 - $type = Project::where('id', $project_id)->value('type');  
152 - if($keyword_num && $type == 2 && $first_page_num >= $keyword_num){  
153 - $model->compliance_day = $model->compliance_day + 1;  
154 - $model->is_compliance = 1;  
155 - }  
156 - }  
157 -  
158 - $model->project_id = $project_id;  
159 - $model->first_num = $first_num;  
160 - $model->first_page_num = $first_page_num;  
161 - $model->first_three_pages_num = $first_three_pages_num;  
162 - $model->first_five_pages_num = $first_five_pages_num;  
163 - $model->first_ten_pages_num = $first_ten_pages_num;  
164 - $model->indexed_pages_num = $indexed_pages_num;  
165 - $model->lang = $lang;  
166 - $model->data = $data;  
167 - $model->updated_date = date('Y-m-d');  
168 - @file_put_contents(storage_path('logs/lyh_error.log'), var_export($model, true) . PHP_EOL, FILE_APPEND);  
169 - $model->save();  
170 - }  
171 } 65 }
  1 +<?php
  2 +
  3 +namespace App\Console\Commands\RankData;
  4 +
  5 +use App\Helper\QuanqiusouApi;
  6 +use App\Http\Logic\Bside\RankData\RankDataLogic;
  7 +use App\Models\Com\NoticeLog;
  8 +use App\Models\Project\DeployOptimize;
  9 +use App\Models\Project\Project;
  10 +use App\Models\RankData\RankData as GoogleRankModel;
  11 +use App\Utils\LogUtils;
  12 +use Illuminate\Console\Command;
  13 +
  14 +/**
  15 + * Class GoogleRank
  16 + * @package App\Console\Commands
  17 + * @author zbj
  18 + * @date 2023/5/6
  19 + */
  20 +class RankDataTask extends Command
  21 +{
  22 + /**
  23 + * The name and signature of the console command.
  24 + *
  25 + * @var string
  26 + */
  27 + protected $signature = 'rank_data_task';
  28 +
  29 + /**
  30 + * The console command description.
  31 + * The console command description.
  32 + *
  33 + * @var string
  34 + */
  35 + protected $description = '谷歌排名数据';
  36 +
  37 +
  38 + /**
  39 + * Create a new command instance.
  40 + *
  41 + * @return void
  42 + */
  43 + public function __construct()
  44 + {
  45 + parent::__construct();
  46 + }
  47 +
  48 +
  49 + /**
  50 + * @author zbj
  51 + * @date 2023/5/6
  52 + */
  53 + public function handle()
  54 + {
  55 + $list = NoticeLog::where('type', NoticeLog::TYPE_RANK_DATA)->where('status', NoticeLog::STATUS_PENDING)->get();
  56 + foreach ($list as $item){
  57 + try {
  58 + (new RankDataLogic())->syncRankData($item['data']['api_no']);
  59 +
  60 + $item->status = NoticeLog::STATUS_SUCCESS;
  61 + $item->save();
  62 + }catch (\Exception $e){
  63 + errorLog('排名数据更新失败', $item, $e);
  64 + $this->retry($item);
  65 + }
  66 + }
  67 + }
  68 +
  69 + /**
  70 + * @param NoticeLog $log
  71 + */
  72 + public function retry($log){
  73 + if($log->retry >= 3){
  74 + $log->status = NoticeLog::STATUS_FAIL;
  75 + }else{
  76 + $log->retry = $log->retry + 1;
  77 + }
  78 + $log->save();
  79 + }
  80 +}
@@ -17,6 +17,7 @@ class Kernel extends ConsoleKernel @@ -17,6 +17,7 @@ class Kernel extends ConsoleKernel
17 { 17 {
18 // $schedule->command('inspire')->hourly(); 18 // $schedule->command('inspire')->hourly();
19 $schedule->command('remain_day')->dailyAt('03:00')->withoutOverlapping(1); // 项目剩余服务时长 19 $schedule->command('remain_day')->dailyAt('03:00')->withoutOverlapping(1); // 项目剩余服务时长
  20 + $schedule->command('rank_data_task')->everyMinute()->withoutOverlapping(1); // 排名数据更新任务
20 $schedule->command('rank_data')->dailyAt('01:00')->withoutOverlapping(1); // 排名数据,每天凌晨执行一次 21 $schedule->command('rank_data')->dailyAt('01:00')->withoutOverlapping(1); // 排名数据,每天凌晨执行一次
21 $schedule->command('rank_data_speed')->weeklyOn(1, '01:00')->withoutOverlapping(1); // 排名数据-测速数据,每周一凌晨执行一次 22 $schedule->command('rank_data_speed')->weeklyOn(1, '01:00')->withoutOverlapping(1); // 排名数据-测速数据,每周一凌晨执行一次
22 $schedule->command('rank_data_external_links')->weeklyOn(1, '01:00')->withoutOverlapping(1); // 排名数据-外链,每周一凌晨执行一次 23 $schedule->command('rank_data_external_links')->weeklyOn(1, '01:00')->withoutOverlapping(1); // 排名数据-外链,每周一凌晨执行一次
@@ -17,13 +17,10 @@ class NoticeController extends BaseController @@ -17,13 +17,10 @@ class NoticeController extends BaseController
17 { 17 {
18 /** 18 /**
19 * 项目通知 19 * 项目通知
20 - * @return \Illuminate\Http\JsonResponse  
21 - * @throws \Psr\Container\ContainerExceptionInterface  
22 - * @throws \Psr\Container\NotFoundExceptionInterface  
23 * @author zbj 20 * @author zbj
24 * @date 2023/6/26 21 * @date 2023/6/26
25 */ 22 */
26 - public function project(ProjectLogic $logic) 23 + public function project()
27 { 24 {
28 //首次 续费 25 //首次 续费
29 LogUtils::info('notice project', $this->param); 26 LogUtils::info('notice project', $this->param);
@@ -31,4 +28,18 @@ class NoticeController extends BaseController @@ -31,4 +28,18 @@ class NoticeController extends BaseController
31 $this->response('success'); 28 $this->response('success');
32 } 29 }
33 30
  31 +
  32 + /**
  33 + *
  34 + * 更新排名数据通知
  35 + * @author zbj
  36 + * @date 2023/9/20
  37 + */
  38 + public function rank_data()
  39 + {
  40 + LogUtils::info('notice rank_data', $this->param);
  41 + NoticeLog::createLog(NoticeLog::TYPE_RANK_DATA, $this->param);
  42 + $this->response('success');
  43 + }
  44 +
34 } 45 }
@@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
2 2
3 namespace App\Http\Logic\Aside\Project; 3 namespace App\Http\Logic\Aside\Project;
4 4
  5 +use App\Models\Com\NoticeLog;
5 use App\Models\Devops\ServerConfig; 6 use App\Models\Devops\ServerConfig;
6 use App\Models\Project\ProjectRenew; 7 use App\Models\Project\ProjectRenew;
7 use App\Models\User\ProjectMenu; 8 use App\Models\User\ProjectMenu;
@@ -212,6 +213,13 @@ class ProjectLogic extends BaseLogic @@ -212,6 +213,13 @@ class ProjectLogic extends BaseLogic
212 if(isset($deploy_optimize['minor_keywords']) && !empty($deploy_optimize['minor_keywords'])){ 213 if(isset($deploy_optimize['minor_keywords']) && !empty($deploy_optimize['minor_keywords'])){
213 $deploy_optimize['minor_keywords'] = Arr::a2s($deploy_optimize['minor_keywords']); 214 $deploy_optimize['minor_keywords'] = Arr::a2s($deploy_optimize['minor_keywords']);
214 } 215 }
  216 +
  217 + //是否更新了api_no
  218 + $api_no = DeployOptimize::where('id', $deploy_optimize['id'])->value('api_no');
  219 + if($api_no != $deploy_optimize['api_no']){
  220 + NoticeLog::createLog(NoticeLog::TYPE_RANK_DATA, ['api_no' => $deploy_optimize['api_no']]);
  221 + }
  222 +
215 $deployOptimizeModel->edit($deploy_optimize,['id'=>$deploy_optimize['id']]); 223 $deployOptimizeModel->edit($deploy_optimize,['id'=>$deploy_optimize['id']]);
216 return $this->success(); 224 return $this->success();
217 } 225 }
@@ -9,6 +9,8 @@ use App\Helper\Translate; @@ -9,6 +9,8 @@ use App\Helper\Translate;
9 use App\Http\Logic\Aside\Project\DomainInfoLogic; 9 use App\Http\Logic\Aside\Project\DomainInfoLogic;
10 use App\Http\Logic\Aside\Project\ProjectLogic; 10 use App\Http\Logic\Aside\Project\ProjectLogic;
11 use App\Http\Logic\Bside\BaseLogic; 11 use App\Http\Logic\Bside\BaseLogic;
  12 +use App\Models\Project\DeployBuild;
  13 +use App\Models\Project\DeployOptimize;
12 use App\Models\Project\Project; 14 use App\Models\Project\Project;
13 use App\Models\RankData\ExternalLinks; 15 use App\Models\RankData\ExternalLinks;
14 use App\Models\RankData\IndexedPages; 16 use App\Models\RankData\IndexedPages;
@@ -347,4 +349,137 @@ class RankDataLogic extends BaseLogic @@ -347,4 +349,137 @@ class RankDataLogic extends BaseLogic
347 } 349 }
348 return $flg_ai; 350 return $flg_ai;
349 } 351 }
  352 +
  353 + /**
  354 + * 同步排名信息
  355 + * @throws \Exception
  356 + * @author zbj
  357 + * @date 2023/9/20
  358 + */
  359 + public function syncRankData($api_no){
  360 + $project_id = DeployOptimize::where('api_no', $api_no)->value('project_id');
  361 + $project = Project::find($project_id);
  362 + if(!$project){
  363 + throw new \Exception($api_no . '关联的项目不存在');
  364 + }
  365 +
  366 + $api = new QuanqiusouApi();
  367 +
  368 + $model = RankData::where('project_id', $project_id)->where('lang', '')->first();
  369 + if (!$model || $model->updated_date != date('Y-m-d')) {
  370 + $res = $api->getGoogleRank($api_no);
  371 + if(!$res){
  372 + throw new \Exception('接口数据获取失败');
  373 + }
  374 + //收录数
  375 + $indexed_pages_num = $site_res[$api_no] ?? 0;
  376 + $this->save_rank($project_id, $res, $indexed_pages_num);
  377 + }
  378 + //有小语种的
  379 + $lang_list = $api->getLangList();
  380 + if(!empty($lang_list[$api_no])){
  381 + $model = RankData::where('project_id', $project_id)->where('lang', '<>', '')->first();
  382 + if (!$model || $model->updated_date != date('Y-m-d')) {
  383 + $res = $api->getGoogleRank($api_no, 1);
  384 + if(!$res){
  385 + throw new \Exception('接口数据获取失败');
  386 + }
  387 + $data = [];
  388 + //不同的小语种取出来
  389 + foreach ($res as $keyword => $v){
  390 + $data[Arr::last($v)['lang']][$keyword] = $v;
  391 + }
  392 + foreach ($data as $lang => $rank){
  393 + $this->save_rank($project_id, $rank, 0, $lang);
  394 + }
  395 + }
  396 + }
  397 + }
  398 +
  399 + /**
  400 + * @param $project_id
  401 + * @param int $indexed_pages_num
  402 + * @param $data
  403 + * @param string $lang
  404 + * @author zbj
  405 + * @date 2023/5/8
  406 + */
  407 + public function save_rank($project_id, $data, int $indexed_pages_num = 0, string $lang = ''){
  408 + $without_project_ids = []; //不用处理排名的项目
  409 +
  410 + $first_num = $first_page_num = $first_three_pages_num = $first_five_pages_num = $first_ten_pages_num = 0;
  411 +
  412 + if(!$lang){
  413 + foreach ($data as &$ranks){
  414 + ksort($ranks);
  415 + foreach ($ranks as &$rank){
  416 + //处理排名
  417 + if(!in_array($project_id, $without_project_ids)){
  418 + if($rank['position'] >= 10){
  419 + $rank['position'] -= 5;
  420 + }
  421 + //todo 需要特殊处理排名的项目
  422 + }
  423 + }
  424 + $last = Arr::last($ranks);
  425 + //第一名
  426 + if($last['position'] == 1){
  427 + $first_num ++;
  428 + }
  429 + //排名第一页
  430 + if($last['position'] > 0 && $last['position'] <= 10){
  431 + $first_page_num ++;
  432 + }
  433 + //排名前三页
  434 + if($last['position'] > 0 && $last['position'] <= 30){
  435 + $first_three_pages_num ++;
  436 + }
  437 + //排名前五页
  438 + if($last['position'] > 0 && $last['position'] <= 50){
  439 + $first_five_pages_num ++;
  440 + }
  441 + //排名前十页
  442 + if($last['position'] > 0 && $last['position'] <= 100){
  443 + $first_ten_pages_num ++;
  444 + }
  445 + }
  446 + }
  447 +
  448 + $where = [
  449 + 'project_id' => $project_id,
  450 + 'lang' => $lang
  451 + ];
  452 + $model = RankData::where($where)->first();
  453 + if(!$model){
  454 + $model = new RankData();
  455 + }
  456 +
  457 + //关键词达标天数
  458 + $model->is_compliance = 0;
  459 + if($model->updated_date != date('Y-m-d')){
  460 + //保证关键词数
  461 + $keyword_num = DeployBuild::where('project_id', $project_id)->value('keyword_num');
  462 + $type = Project::where('id', $project_id)->value('type');
  463 + if($keyword_num && $type == 2 && $first_page_num >= $keyword_num){
  464 + $model->compliance_day = $model->compliance_day + 1;
  465 + $model->is_compliance = 1;
  466 +
  467 + //项目表更新
  468 + Project::where('id', $project_id)->update(['is_remain_today' => 1, 'finish_remain_day' => $model->compliance_day]);
  469 + }
  470 + }
  471 +
  472 + $model->project_id = $project_id;
  473 + $model->first_num = $first_num;
  474 + $model->first_page_num = $first_page_num;
  475 + $model->first_three_pages_num = $first_three_pages_num;
  476 + $model->first_five_pages_num = $first_five_pages_num;
  477 + $model->first_ten_pages_num = $first_ten_pages_num;
  478 + $model->indexed_pages_num = $indexed_pages_num;
  479 + $model->lang = $lang;
  480 + $model->data = $data;
  481 + $model->updated_date = date('Y-m-d');
  482 + @file_put_contents(storage_path('logs/lyh_error.log'), var_export($model, true) . PHP_EOL, FILE_APPEND);
  483 + $model->save();
  484 + }
350 } 485 }
@@ -10,6 +10,7 @@ class NoticeLog extends Model @@ -10,6 +10,7 @@ class NoticeLog extends Model
10 protected $table = 'gl_notice_log'; 10 protected $table = 'gl_notice_log';
11 11
12 const TYPE_PROJECT = 'project'; 12 const TYPE_PROJECT = 'project';
  13 + const TYPE_RANK_DATA = 'rank_data';
13 14
14 const STATUS_PENDING = 0; 15 const STATUS_PENDING = 0;
15 const STATUS_SUCCESS = 1; 16 const STATUS_SUCCESS = 1;
@@ -322,6 +322,7 @@ Route::group([], function () { @@ -322,6 +322,7 @@ Route::group([], function () {
322 Route::any('/download_images', [\App\Http\Controllers\File\ImageController::class, 'downLoad'])->name('admin.images_downLoad');//导出图片 322 Route::any('/download_images', [\App\Http\Controllers\File\ImageController::class, 'downLoad'])->name('admin.images_downLoad');//导出图片
323 Route::any('/domain/exportData', [Aside\Domain\DomainInfoController::class, 'exportData'])->name('admin.domain_exportData');//导出数据 323 Route::any('/domain/exportData', [Aside\Domain\DomainInfoController::class, 'exportData'])->name('admin.domain_exportData');//导出数据
324 Route::any('/notice/project', [Aside\Notice\NoticeController::class, 'project'])->name('admin.notice.project'); 324 Route::any('/notice/project', [Aside\Notice\NoticeController::class, 'project'])->name('admin.notice.project');
  325 + Route::any('/notice/rank_data', [Aside\Notice\NoticeController::class, 'rank_data'])->name('admin.notice.rank_data');
325 Route::any('/sendLoginSms', [Aside\LoginController::class, 'sendLoginSms'])->name('admin.sendLoginSms');//发送验证码 326 Route::any('/sendLoginSms', [Aside\LoginController::class, 'sendLoginSms'])->name('admin.sendLoginSms');//发送验证码
326 Route::any('/getProjectInService', [Aside\Project\ProjectController::class, 'getProjectInService'])->name('admin.getProjectInService');//获取项目服务状态 327 Route::any('/getProjectInService', [Aside\Project\ProjectController::class, 'getProjectInService'])->name('admin.getProjectInService');//获取项目服务状态
327 Route::any('/getProjectByChannel', [Aside\Project\ProjectController::class, 'getProjectByChannel'])->name('admin.getProjectByChannel');//获取渠道商的项目 328 Route::any('/getProjectByChannel', [Aside\Project\ProjectController::class, 'getProjectByChannel'])->name('admin.getProjectByChannel');//获取渠道商的项目