作者 刘锟

Merge remote-tracking branch 'origin/master' into akun

@@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
10 namespace App\Console\Commands\Ai; 10 namespace App\Console\Commands\Ai;
11 11
12 use App\Models\Ai\AiVideo; 12 use App\Models\Ai\AiVideo;
  13 +use App\Models\AyrShare\AyrShare;
13 use App\Models\Domain\DomainInfo; 14 use App\Models\Domain\DomainInfo;
14 use App\Models\Product\Keyword; 15 use App\Models\Product\Keyword;
15 use App\Models\Product\Product; 16 use App\Models\Product\Product;
@@ -241,7 +242,15 @@ class AiVideoAutoPublish extends Command @@ -241,7 +242,15 @@ class AiVideoAutoPublish extends Command
241 $storage = $aiVideoTaskModel->videoSetting()[$video_setting ?? 1]; 242 $storage = $aiVideoTaskModel->videoSetting()[$video_setting ?? 1];
242 $frequency = $aiVideoTaskModel->videoFrequency()[$frequency_setting ?? 1]; 243 $frequency = $aiVideoTaskModel->videoFrequency()[$frequency_setting ?? 1];
243 $frequencyArr = explode('-',$frequency); 244 $frequencyArr = explode('-',$frequency);
244 - $result = $aiVideoService->createTask($info['title'],$info['remark'],array_slice($info['images'], 0, 8),[],$storage); 245 + if($storage == 'YOUTUBE'){
  246 + //查看是否有ayr账号
  247 + $ayrModel = new AyrShare();
  248 + $ayrInfo = $ayrModel->read(['project_id'=>$this->param['project_id'],'bind_platforms'=>['like','%"youtube"%'],'profile_key'=>['!=',null]]);
  249 + if($ayrInfo !== false){
  250 + $ayrshare_profile_key = $ayrInfo['profile_key'];
  251 + }
  252 + }
  253 + $result = $aiVideoService->createTask($info['title'],$info['remark'],array_slice($info['images'], 0, 8),[],$storage,$ayrshare_profile_key ?? '');
245 if($result['status'] == 200){ 254 if($result['status'] == 200){
246 $next_auto_date = date('Y-m-d', strtotime('+' . mt_rand($frequencyArr[0] ?? 5,$frequencyArr[1] ?? 7) . 'days')); //每5-7天自动发布 255 $next_auto_date = date('Y-m-d', strtotime('+' . mt_rand($frequencyArr[0] ?? 5,$frequencyArr[1] ?? 7) . 'days')); //每5-7天自动发布
247 $aiVideoTaskModel->addReturnId(['next_auto_date'=>$next_auto_date,'task_id'=>$result['data']['task_id'],'project_id'=>$info['project_id'],'storage'=>$storage]); 256 $aiVideoTaskModel->addReturnId(['next_auto_date'=>$next_auto_date,'task_id'=>$result['data']['task_id'],'project_id'=>$info['project_id'],'storage'=>$storage]);
  1 +<?php
  2 +/**
  3 + * @remark :
  4 + * @name :GeoCount.php
  5 + * @author :lyh
  6 + * @method :post
  7 + * @time :2025/10/13 16:05
  8 + */
  9 +
  10 +namespace App\Console\Commands\Geo;
  11 +
  12 +use App\Models\Geo\GeoQuestionLog;
  13 +use App\Models\Geo\GeoQuestionResult;
  14 +use Illuminate\Console\Command;
  15 +use Illuminate\Support\Carbon;
  16 +use App\Models\Geo\GeoCount as GeoCountModel;
  17 +
  18 +class GeoCount extends Command
  19 +{
  20 + /**
  21 + * The name and signature of the console command.
  22 + *
  23 + * @var string
  24 + */
  25 + protected $signature = 'geo_count';
  26 +
  27 + public $porject_id;//记录当时执行的project_id
  28 +
  29 + /**
  30 + * The console command description.
  31 + *
  32 + * @var string
  33 + */
  34 + protected $description = 'geo统计数据';
  35 +
  36 +
  37 +
  38 + public function handle(){
  39 + $this->output('start');
  40 + $this->_action();
  41 + $this->output('end');
  42 + return true;
  43 + }
  44 +
  45 + /**
  46 + * @remark :方法
  47 + * @name :_action
  48 + * @author :lyh
  49 + * @method :post
  50 + * @time :2025/10/13 16:20
  51 + */
  52 + public function _action()
  53 + {
  54 + $geoCountModel = new GeoCountModel();
  55 + //获取前一天的项目id
  56 + $date = Carbon::yesterday()->format('Y-m-d');
  57 + $start = $date.' 00:00:00';
  58 + $end = $date.' 23:59:59';
  59 + $geoLogModel = new GeoQuestionLog();
  60 + $project_id = $geoLogModel->formatQuery(['created_at' => ['between',[$start,$end]]])->distinct()->pluck('project_id');
  61 + if(empty($project_id)){
  62 + return true;
  63 + }
  64 + $geoQuestionResModel = new GeoQuestionResult();
  65 + $platforms = ['gemini','openai','deepseek','poe','perplexity','google_ai_overview','openai-not-network','claude'];
  66 + foreach ($project_id as $item){
  67 + $this->output('执行的项目ID----'.$item);
  68 + //收录总数
  69 + $total = $geoQuestionResModel->counts(['project_id' => $item,'hit'=>['!=',0],'created_at' => ['between',[$start,$end]]]);
  70 + $data = [
  71 + 'project_id' => $item,
  72 + 'date' => $date,
  73 + 'created_at' => Carbon::now()->format('Y-m-d H:i:s'),
  74 + 'updated_at' => Carbon::now()->format('Y-m-d H:i:s'),
  75 + 'total'=>$total,//收录总数
  76 + ];
  77 + foreach ($platforms as $platform){
  78 + if($platform == 'openai-not-network'){
  79 + $data['openai_not_network'] = $geoQuestionResModel->counts(['project_id' => $item,'hit'=>['!=',0],'platform'=>$platform,'created_at' => ['between',[$start,$end]]]);
  80 + }else{
  81 + $data[$platform] = $geoQuestionResModel->counts(['project_id' => $item,'hit'=>['!=',0],'platform'=>$platform,'created_at' => ['between',[$start,$end]]]);
  82 + }
  83 + }
  84 + //新增一条数据
  85 + $geoCountModel->addReturnId($data);
  86 + }
  87 + return true;
  88 + }
  89 +
  90 + /**
  91 + * 输出日志
  92 + * @param $message
  93 + * @return bool
  94 + */
  95 + public function output($message)
  96 + {
  97 + echo date('Y-m-d H:i:s') . ' ' . $message . PHP_EOL;
  98 + return true;
  99 + }
  100 +}
  1 +<?php
  2 +/**
  3 + * @remark :
  4 + * @name :GeoCount.php
  5 + * @author :lyh
  6 + * @method :post
  7 + * @time :2025/10/13 16:05
  8 + */
  9 +
  10 +namespace App\Console\Commands\Geo;
  11 +
  12 +use App\Models\Geo\GeoQuestionLog;
  13 +use App\Models\Geo\GeoQuestionResult;
  14 +use Illuminate\Console\Command;
  15 +use Illuminate\Support\Carbon;
  16 +use App\Models\Geo\GeoCount as GeoCountModel;
  17 +
  18 +class GeoCountAll extends Command
  19 +{
  20 + /**
  21 + * The name and signature of the console command.
  22 + *
  23 + * @var string
  24 + */
  25 + protected $signature = 'geo_count_all';
  26 +
  27 + public $porject_id;//记录当时执行的project_id
  28 +
  29 + /**
  30 + * The console command description.
  31 + *
  32 + * @var string
  33 + */
  34 + protected $description = 'geo统计数据';
  35 +
  36 +
  37 +
  38 + public function handle(){
  39 + $this->output('start');
  40 + $this->_action();
  41 + $this->output('end');
  42 + return true;
  43 + }
  44 +
  45 + /**
  46 + * @remark :方法
  47 + * @name :_action
  48 + * @author :lyh
  49 + * @method :post
  50 + * @time :2025/10/13 16:20
  51 + */
  52 + public function _action()
  53 + {
  54 + $geoCountModel = new GeoCountModel();
  55 + //获取前一天的项目id
  56 + $dates = [];
  57 + for ($i = 0; $i < 100; $i++) {
  58 + $dates[] = date('Y-m-d', strtotime("-{$i} days"));
  59 + }
  60 + foreach ($dates as $date) {
  61 + $start = $date.' 00:00:00';
  62 + $end = $date.' 23:59:59';
  63 + $geoLogModel = new GeoQuestionLog();
  64 + $project_id = $geoLogModel->formatQuery(['created_at' => ['between',[$start,$end]]])->distinct()->pluck('project_id');
  65 + if(empty($project_id)){
  66 + return true;
  67 + }
  68 + $geoQuestionResModel = new GeoQuestionLog();
  69 + $platforms = ['gemini','openai','deepseek','poe','perplexity','google_ai_overview','openai-not-network','claude'];
  70 + foreach ($project_id as $item){
  71 + $this->output('执行的项目ID----'.$item);
  72 + //收录总数
  73 + $total = $geoQuestionResModel->counts(['project_id' => $item,'hit'=>['!=',0],'created_at' => ['between',[$start,$end]]]);
  74 + $data = [
  75 + 'project_id' => $item,
  76 + 'date' => $date,
  77 + 'created_at' => Carbon::now()->format('Y-m-d H:i:s'),
  78 + 'updated_at' => Carbon::now()->format('Y-m-d H:i:s'),
  79 + 'total'=>$total,//收录总数
  80 + ];
  81 + foreach ($platforms as $platform){
  82 + if($platform == 'openai-not-network'){
  83 + $data['openai_not_network'] = $geoQuestionResModel->counts(['project_id' => $item,'hit'=>['!=',0],'platform'=>$platform,'created_at' => ['between',[$start,$end]]]);
  84 + }else{
  85 + $data[$platform] = $geoQuestionResModel->counts(['project_id' => $item,'hit'=>['!=',0],'platform'=>$platform,'created_at' => ['between',[$start,$end]]]);
  86 + }
  87 + }
  88 + $info = $geoCountModel->read(['project_id' => $item,'date'=>$date]);
  89 + if($info === false){
  90 + //新增一条数据
  91 + $geoCountModel->addReturnId($data);
  92 + }else{
  93 + $geoCountModel->edit($data,['id'=>$info['id']]);
  94 + }
  95 + }
  96 + }
  97 +
  98 + return true;
  99 + }
  100 +
  101 + /**
  102 + * 输出日志
  103 + * @param $message
  104 + * @return bool
  105 + */
  106 + public function output($message)
  107 + {
  108 + echo date('Y-m-d H:i:s') . ' ' . $message . PHP_EOL;
  109 + return true;
  110 + }
  111 +}
@@ -30,6 +30,8 @@ class GeoQuestionRes extends Command @@ -30,6 +30,8 @@ class GeoQuestionRes extends Command
30 */ 30 */
31 protected $signature = 'geo_question_result'; 31 protected $signature = 'geo_question_result';
32 32
  33 + public $porject_id;//记录当时执行的project_id
  34 +
33 /** 35 /**
34 * The console command description. 36 * The console command description.
35 * 37 *
@@ -337,15 +339,18 @@ class GeoQuestionRes extends Command @@ -337,15 +339,18 @@ class GeoQuestionRes extends Command
337 $key = 'geo_task_list'; 339 $key = 'geo_task_list';
338 $task_id = Redis::rpop($key); 340 $task_id = Redis::rpop($key);
339 if(empty($task_id)){ 341 if(empty($task_id)){
  342 + //todo::这里需要执行统计一次,统计当前项目当前日期的统计
  343 +
340 # TODO 按照项目进行获取, 一个项目当天需要将所有跑完 344 # TODO 按照项目进行获取, 一个项目当天需要将所有跑完
341 $project_id = GeoQuestion::where('status', GeoQuestion::STATUS_OPEN)->where('next_time', '<=', date('Y-m-d'))->value('project_id'); 345 $project_id = GeoQuestion::where('status', GeoQuestion::STATUS_OPEN)->where('next_time', '<=', date('Y-m-d'))->value('project_id');
342 - if (empty($project_id))  
343 - return $task_id;  
344 - $ids = GeoQuestion::where(['project_id' => $project_id, 'status' => GeoQuestion::STATUS_OPEN])->where('current_time', '<>', date('Y-m-d'))->pluck('id');  
345 - foreach ($ids as $id) {  
346 - Redis::lpush($key, $id); 346 + if (!empty($project_id)){
  347 + $this->project_id = $project_id;
  348 + $ids = GeoQuestion::where(['project_id' => $project_id, 'status' => GeoQuestion::STATUS_OPEN])->where('current_time', '<>', date('Y-m-d'))->pluck('id');
  349 + foreach ($ids as $id) {
  350 + Redis::lpush($key, $id);
  351 + }
  352 + $task_id = Redis::rpop($key);
347 } 353 }
348 - $task_id = Redis::rpop($key);  
349 } 354 }
350 return $task_id; 355 return $task_id;
351 } 356 }
@@ -979,14 +979,13 @@ class RelayInquiry extends Command @@ -979,14 +979,13 @@ class RelayInquiry extends Command
979 */ 979 */
980 public function delay_seconds($inquiry_date, $domain, $task) 980 public function delay_seconds($inquiry_date, $domain, $task)
981 { 981 {
982 - $inquiry_date = Carbon::make($inquiry_date);  
983 //当天的 982 //当天的
984 - if($inquiry_date->isToday()){ 983 + if(date('Y-m-d', strtotime($inquiry_date)) == date('Y-m-d')){
985 //广告投放日(周一、二、三、四) 第一封询盘100%及时推送 984 //广告投放日(周一、二、三、四) 第一封询盘100%及时推送
986 $is_timely = true; //是否及时推送 985 $is_timely = true; //是否及时推送
987 - if(in_array($inquiry_date->weekday(), [1,2,3,4])) { 986 + if(in_array(date('w'), [1,2,3,4])) {
988 //是否今天的第一封询盘 987 //是否今天的第一封询盘
989 - $detail = ReInquiryDetail::where('re_website', $domain)->where('start_at', '>=', $inquiry_date->startOfDay()->toDatetimeString())->first(); 988 + $detail = ReInquiryDetail::where('re_website', $domain)->where('start_at', '>=', date('Y-m-d 00:00:00'))->first();
990 if($detail){ 989 if($detail){
991 $is_timely = false; //只有周一到周四的非第一封询盘 根据概率及时推送 990 $is_timely = false; //只有周一到周四的非第一封询盘 根据概率及时推送
992 } 991 }
@@ -997,15 +996,17 @@ class RelayInquiry extends Command @@ -997,15 +996,17 @@ class RelayInquiry extends Command
997 $res = $this->get_rand([$task->second_push_rate, 100 - $task->second_push_rate]); 996 $res = $this->get_rand([$task->second_push_rate, 100 - $task->second_push_rate]);
998 if($res == 1){ 997 if($res == 1){
999 //随机分配到未投放广告日期 998 //随机分配到未投放广告日期
1000 - $now = Carbon::now(); 999 + $now = time();
1001 // 随机开始时间(本周四或现在) 1000 // 随机开始时间(本周四或现在)
1002 - $startTime = max($now->timestamp, $now->startOfWeek(4)->timestamp); 1001 + $startTime = max($now, strtotime('this thursday'));
1003 1002
1004 - $random = mt_rand($startTime, $now->endOfWeek()->timestamp); 1003 + $random = mt_rand($startTime, strtotime('next monday'));
1005 1004
1006 - $delay = $random - time(); 1005 + $delay = $random - $now;
1007 $this->output('非广告投放日第一封询盘 概率' . (100 - $task->second_push_rate) . '%延迟推送' . $delay); 1006 $this->output('非广告投放日第一封询盘 概率' . (100 - $task->second_push_rate) . '%延迟推送' . $delay);
1008 return $delay; 1007 return $delay;
  1008 + }else{
  1009 + $this->output('非广告投放日第一封询盘 概率' . $task->second_push_rate . '%即时推送');
1009 } 1010 }
1010 } 1011 }
1011 } 1012 }
@@ -64,50 +64,74 @@ class CopyOldProject extends Command @@ -64,50 +64,74 @@ class CopyOldProject extends Command
64 { 64 {
65 // 设置源数据库 65 // 设置源数据库
66 config(['database.connections.custom_tmp_mysql_copy.database' => 'gl_data_' . $project_id]); 66 config(['database.connections.custom_tmp_mysql_copy.database' => 'gl_data_' . $project_id]);
  67 + DB::purge('custom_tmp_mysql_copy');
  68 + DB::reconnect('custom_tmp_mysql_copy');
67 $database_name = DB::connection('custom_tmp_mysql_copy')->getDatabaseName(); 69 $database_name = DB::connection('custom_tmp_mysql_copy')->getDatabaseName();
68 // 获取源数据库的所有表 70 // 获取源数据库的所有表
69 $tables = Schema::connection('custom_tmp_mysql_copy')->getAllTables(); 71 $tables = Schema::connection('custom_tmp_mysql_copy')->getAllTables();
70 $tables = array_column($tables, 'Tables_in_' . $database_name); 72 $tables = array_column($tables, 'Tables_in_' . $database_name);
71 foreach ($tables as $table) { 73 foreach ($tables as $table) {
72 - // 目标数据库是否存在该表  
73 - $has_table = Schema::connection('custom_mysql')->hasTable($table);  
74 - if ($has_table) {  
75 - // 1. 删除目标数据库中的表  
76 - DB::connection('custom_mysql')->statement("DROP TABLE IF EXISTS {$table}");  
77 - }  
78 - // 2. 重新创建表  
79 - $sql = DB::connection('custom_tmp_mysql_copy')->select("SHOW CREATE TABLE {$table}");  
80 - DB::connection('custom_mysql')->statement(get_object_vars($sql[0])['Create Table']);  
81 - // 3. 跳过指定的表  
82 - if (in_array($table, [  
83 - 'gl_customer_visit',  
84 - 'gl_customer_visit_item',  
85 - 'gl_inquiry_other',  
86 - 'gl_inquiry_form_data',  
87 - 'gl_inquiry_form',  
88 - 'gl_ai_blog',  
89 - 'gl_ai_blog_author',  
90 - 'gl_ai_blog_list',  
91 - 'gl_ai_blog_log',  
92 - ])) {  
93 - continue;  
94 - }  
95 - // 4. 重新插入数据  
96 - DB::connection('custom_mysql')->table($table)->insertUsing(  
97 - [], // 插入所有列  
98 - function ($query) use ($table, $project_id) {  
99 - $name = 'gl_data_' . $project_id . '.' . $table;  
100 - $query->select('*')->from("{$name}"); 74 + try {
  75 + // 1. 检查源表是否存在(防止 gl_data_{$project_id} 下缺表)
  76 + $exists = Schema::connection('custom_tmp_mysql_copy')->hasTable($table);
  77 + if (!$exists) {
  78 + @file_put_contents(
  79 + storage_path('logs/copy_mysql_error.log'),
  80 + "源库中不存在表:{$table}" . PHP_EOL,
  81 + FILE_APPEND
  82 + );
  83 + continue;
  84 + }
  85 + // 2. 删除目标数据库中的表
  86 + $result = DB::connection('custom_mysql')->statement("DROP TABLE IF EXISTS `{$table}`");
  87 + @file_put_contents(storage_path('logs/copy_mysql_error.log'), "删除旧表:{$table} => {$result}" . PHP_EOL, FILE_APPEND);
  88 + // 3. 复制建表 SQL
  89 + $sql = DB::connection('custom_tmp_mysql_copy')->select("SHOW CREATE TABLE `{$table}`");
  90 + $createSql = get_object_vars($sql[0])['Create Table'];
  91 + $result1 = DB::connection('custom_mysql')->statement($createSql);
  92 + @file_put_contents(storage_path('logs/copy_mysql_error.log'), "创建表:{$table} => {$result1}" . PHP_EOL, FILE_APPEND);
  93 + // 4. 跳过指定表
  94 + if (in_array($table, [
  95 + 'gl_customer_visit', 'gl_customer_visit_item',
  96 + 'gl_inquiry_other', 'gl_inquiry_form_data', 'gl_inquiry_form',
  97 + 'gl_ai_blog', 'gl_ai_blog_author', 'gl_ai_blog_list', 'gl_ai_blog_log'
  98 + ])) {
  99 + continue;
  100 + }
  101 + // 5. 插入数据前,再次确认源表存在(双保险)
  102 + if (!Schema::connection('custom_tmp_mysql_copy')->hasTable($table)) {
  103 + @file_put_contents(storage_path('logs/copy_mysql_error.log'), "插入数据前发现表不存在:{$table}" . PHP_EOL, FILE_APPEND);
  104 + continue;
101 } 105 }
102 - );  
103 - // 5. 更新 project_id(如果存在)  
104 - if (Schema::connection('custom_mysql')->hasColumn($table, 'project_id')) {  
105 - DB::connection('custom_mysql')->table($table)->update(['project_id' => $news_project_id]); 106 + // 6. 原生 SQL 插入数据(完全复制)
  107 + $insert_sql = "INSERT INTO `{$table}` SELECT * FROM `gl_data_{$project_id}`.`{$table}`";
  108 + try {
  109 + $result2 = DB::connection('custom_mysql')->statement($insert_sql);
  110 + @file_put_contents(storage_path('logs/copy_mysql_error.log'), "插入数据成功:{$table} => {$result2}" . PHP_EOL, FILE_APPEND);
  111 + } catch (\Exception $e) {
  112 + @file_put_contents(storage_path('logs/copy_mysql_error.log'),
  113 + "插入数据失败:{$table} => " . $e->getMessage() . PHP_EOL,
  114 + FILE_APPEND
  115 + );
  116 + continue; // 跳过这个表,不中断整个流程
  117 + }
  118 + // 7. 更新 project_id(如果存在)
  119 + if (Schema::connection('custom_mysql')->hasColumn($table, 'project_id')) {
  120 + DB::connection('custom_mysql')->table($table)->update(['project_id' => $news_project_id]);
  121 + }
  122 + } catch (\Exception $e) {
  123 + @file_put_contents(
  124 + storage_path('logs/copy_mysql_error.log'),
  125 + "处理表 {$table} 出错:" . $e->getMessage() . PHP_EOL,
  126 + FILE_APPEND
  127 + );
  128 + continue;
106 } 129 }
107 } 130 }
108 return true; 131 return true;
109 } 132 }
110 133
  134 +
111 /** 135 /**
112 * @param $message 136 * @param $message
113 * @return bool 137 * @return bool
@@ -234,33 +234,75 @@ class CopyProject extends Command @@ -234,33 +234,75 @@ class CopyProject extends Command
234 { 234 {
235 // 设置源数据库 235 // 设置源数据库
236 config(['database.connections.custom_tmp_mysql_copy.database' => 'gl_data_' . $project_id]); 236 config(['database.connections.custom_tmp_mysql_copy.database' => 'gl_data_' . $project_id]);
  237 + DB::purge('custom_tmp_mysql_copy');
  238 + DB::reconnect('custom_tmp_mysql_copy');
237 $database_name = DB::connection('custom_tmp_mysql_copy')->getDatabaseName(); 239 $database_name = DB::connection('custom_tmp_mysql_copy')->getDatabaseName();
238 // 获取源数据库的所有表 240 // 获取源数据库的所有表
239 $tables = Schema::connection('custom_tmp_mysql_copy')->getAllTables(); 241 $tables = Schema::connection('custom_tmp_mysql_copy')->getAllTables();
240 $tables = array_column($tables, 'Tables_in_' . $database_name); 242 $tables = array_column($tables, 'Tables_in_' . $database_name);
241 foreach ($tables as $table) { 243 foreach ($tables as $table) {
242 - // 1. 删除目标数据库中的表  
243 - $result = DB::connection('custom_mysql')->statement("DROP TABLE IF EXISTS {$table}");  
244 - @file_put_contents(storage_path('logs/copy_mysql_error.log'), var_export('先删除对应数据库的对应表返回结果:'.$result, true) . PHP_EOL, FILE_APPEND);  
245 - // 2. 复制建表 SQL  
246 - $sql = DB::connection('custom_tmp_mysql_copy')->select("SHOW CREATE TABLE `{$table}`");  
247 - $result1 = DB::connection('custom_mysql')->statement(get_object_vars($sql[0])['Create Table']);  
248 - @file_put_contents(storage_path('logs/copy_mysql_error.log'), var_export('创建对应表数据:'.$result1, true) . PHP_EOL, FILE_APPEND);  
249 - // 3. 跳过指定的表  
250 - if (in_array($table, ['gl_customer_visit', 'gl_customer_visit_item', 'gl_inquiry_other', 'gl_inquiry_form_data', 'gl_inquiry_form','gl_ai_blog', 'gl_ai_blog_author', 'gl_ai_blog_list','gl_ai_blog_log'])) { 244 + try {
  245 + // 1. 检查源表是否存在(防止 gl_data_{$project_id} 下缺表)
  246 + $exists = Schema::connection('custom_tmp_mysql_copy')->hasTable($table);
  247 + if (!$exists) {
  248 + @file_put_contents(
  249 + storage_path('logs/copy_mysql_error.log'),
  250 + "源库中不存在表:{$table}" . PHP_EOL,
  251 + FILE_APPEND
  252 + );
  253 + continue;
  254 + }
  255 + // 2. 删除目标数据库中的表
  256 + $result = DB::connection('custom_mysql')->statement("DROP TABLE IF EXISTS `{$table}`");
  257 + @file_put_contents(storage_path('logs/copy_mysql_error.log'), "删除旧表:{$table} => {$result}" . PHP_EOL, FILE_APPEND);
  258 + // 3. 复制建表 SQL
  259 + $sql = DB::connection('custom_tmp_mysql_copy')->select("SHOW CREATE TABLE `{$table}`");
  260 + $createSql = get_object_vars($sql[0])['Create Table'];
  261 + $result1 = DB::connection('custom_mysql')->statement($createSql);
  262 + @file_put_contents(storage_path('logs/copy_mysql_error.log'), "创建表:{$table} => {$result1}" . PHP_EOL, FILE_APPEND);
  263 +
  264 + // 4. 跳过指定表
  265 + if (in_array($table, [
  266 + 'gl_customer_visit', 'gl_customer_visit_item',
  267 + 'gl_inquiry_other', 'gl_inquiry_form_data', 'gl_inquiry_form',
  268 + 'gl_ai_blog', 'gl_ai_blog_author', 'gl_ai_blog_list', 'gl_ai_blog_log'
  269 + ])) {
  270 + continue;
  271 + }
  272 + // 5. 插入数据前,再次确认源表存在(双保险)
  273 + if (!Schema::connection('custom_tmp_mysql_copy')->hasTable($table)) {
  274 + @file_put_contents(storage_path('logs/copy_mysql_error.log'), "插入数据前发现表不存在:{$table}" . PHP_EOL, FILE_APPEND);
  275 + continue;
  276 + }
  277 + // 6. 原生 SQL 插入数据(完全复制)
  278 + $insert_sql = "INSERT INTO `{$table}` SELECT * FROM `gl_data_{$project_id}`.`{$table}`";
  279 + try {
  280 + $result2 = DB::connection('custom_mysql')->statement($insert_sql);
  281 + @file_put_contents(storage_path('logs/copy_mysql_error.log'), "插入数据成功:{$table} => {$result2}" . PHP_EOL, FILE_APPEND);
  282 + } catch (\Exception $e) {
  283 + @file_put_contents(storage_path('logs/copy_mysql_error.log'),
  284 + "插入数据失败:{$table} => " . $e->getMessage() . PHP_EOL,
  285 + FILE_APPEND
  286 + );
  287 + continue; // 跳过这个表,不中断整个流程
  288 + }
  289 + // 7. 更新 project_id(如果存在)
  290 + if (Schema::connection('custom_mysql')->hasColumn($table, 'project_id')) {
  291 + DB::connection('custom_mysql')->table($table)->update(['project_id' => $news_project_id]);
  292 + }
  293 + } catch (\Exception $e) {
  294 + @file_put_contents(
  295 + storage_path('logs/copy_mysql_error.log'),
  296 + "处理表 {$table} 出错:" . $e->getMessage() . PHP_EOL,
  297 + FILE_APPEND
  298 + );
251 continue; 299 continue;
252 } 300 }
253 - // 4. 原生 SQL 插入数据(完全复制)  
254 - $insert_sql = "INSERT INTO `{$table}` SELECT * FROM `gl_data_{$project_id}`.`{$table}`";  
255 - $result2 = DB::connection('custom_mysql')->statement($insert_sql);  
256 - @file_put_contents(storage_path('logs/copy_mysql_error.log'), var_export('对应表插入数据:'.$result2, true) . PHP_EOL, FILE_APPEND);  
257 - // 5. 更新 project_id(如果存在)  
258 - if (Schema::connection('custom_mysql')->hasColumn($table, 'project_id')) {  
259 - DB::connection('custom_mysql')->table($table)->update(['project_id' => $news_project_id]);  
260 - }  
261 } 301 }
  302 +
262 return true; 303 return true;
263 } 304 }
  305 +
264 /** 306 /**
265 * @param $message 307 * @param $message
266 * @return bool 308 * @return bool
@@ -166,11 +166,8 @@ class SyncProject extends Command @@ -166,11 +166,8 @@ class SyncProject extends Command
166 ]; 166 ];
167 $data['deploy_build']['plan'] = $this->versionData($param['plan_marketing'] ?? ''); 167 $data['deploy_build']['plan'] = $this->versionData($param['plan_marketing'] ?? '');
168 $data['deploy_build']['seo_plan'] = $this->versionSeoData($param['geo_plan'] ?? ''); 168 $data['deploy_build']['seo_plan'] = $this->versionSeoData($param['geo_plan'] ?? '');
169 - if(!empty($data['deploy_build']['plan'])){  
170 - $data['deploy_build']['service_duration'] = $param['years'] ?? 0;  
171 - }else{  
172 - $data['deploy_build']['seo_service_duration'] = $param['years'] ?? 0;  
173 - } 169 + $data['deploy_build']['service_duration'] = $param['years'] ?? 0;
  170 + $data['deploy_build']['seo_service_duration'] = $param['geo_plan_day'] ?? 0;
174 $renewModel = new ProjectRenew(); 171 $renewModel = new ProjectRenew();
175 $rs = $renewModel->add($data); 172 $rs = $renewModel->add($data);
176 if($rs === false){ 173 if($rs === false){
@@ -256,11 +253,8 @@ class SyncProject extends Command @@ -256,11 +253,8 @@ class SyncProject extends Command
256 ]; 253 ];
257 $data['deploy_build']['plan'] = $this->versionData($param['plan_marketing'] ?? ''); 254 $data['deploy_build']['plan'] = $this->versionData($param['plan_marketing'] ?? '');
258 $data['deploy_build']['seo_plan'] = $this->versionSeoData($param['geo_plan'] ?? ''); 255 $data['deploy_build']['seo_plan'] = $this->versionSeoData($param['geo_plan'] ?? '');
259 - if(!empty($data['deploy_build']['plan'])){  
260 - $data['deploy_build']['service_duration'] = $param['years'] ?? 0;  
261 - }else{  
262 - $data['deploy_build']['seo_service_duration'] = $param['years'] ?? 0;  
263 - } 256 + $data['deploy_build']['service_duration'] = $param['years'] ?? 0;
  257 + $data['deploy_build']['seo_service_duration'] = $param['geo_plan_day'] ?? 0;
264 DB::beginTransaction(); 258 DB::beginTransaction();
265 try { 259 try {
266 if(isset($data['deploy_build']['plan']) && in_array($data['deploy_build']['plan'],[4,5,15,16,17])){ 260 if(isset($data['deploy_build']['plan']) && in_array($data['deploy_build']['plan'],[4,5,15,16,17])){
@@ -374,7 +374,7 @@ class UpdateSeoTdk extends Command @@ -374,7 +374,7 @@ class UpdateSeoTdk extends Command
374 $seo_title = $v[$this->topic_fields[$table]];; 374 $seo_title = $v[$this->topic_fields[$table]];;
375 //只有推广项目 才加 前后缀 375 //只有推广项目 才加 前后缀
376 if($project->type == Project::TYPE_TWO) { 376 if($project->type == Project::TYPE_TWO) {
377 - $prefix = $this->getPrefixKeyword($project_id, 'prefix', 1, $seo_title); 377 + $prefix = $this->getPrefixKeyword($project_id, 'prefix', 2, $seo_title);
378 $suffix = $this->getPrefixKeyword($project_id, 'suffix', 2, trim($prefix . ' ' . $seo_title)); 378 $suffix = $this->getPrefixKeyword($project_id, 'suffix', 2, trim($prefix . ' ' . $seo_title));
379 if(Str::startsWith($suffix, ', ')){ 379 if(Str::startsWith($suffix, ', ')){
380 $seo_title = $prefix . ' ' . $seo_title . $suffix; 380 $seo_title = $prefix . ' ' . $seo_title . $suffix;
@@ -574,7 +574,7 @@ class UpdateSeoTdk extends Command @@ -574,7 +574,7 @@ class UpdateSeoTdk extends Command
574 return $str; 574 return $str;
575 } 575 }
576 576
577 - //前后缀(包括自定义前后缀)如果已经存在,就不在拼接当前类型 后缀只包含了一个,要再拼一个(需去重) 577 + //前后缀(包括自定义前后缀)如果已经存在,就不在拼接当前类型 前、后缀只包含了一个,要再拼一个(需去重)
578 $all_prefixes = $this->getAllPrefix(1, $project_id); 578 $all_prefixes = $this->getAllPrefix(1, $project_id);
579 $all_prefixes = array_map('strtolower', $all_prefixes); 579 $all_prefixes = array_map('strtolower', $all_prefixes);
580 580
@@ -595,8 +595,14 @@ class UpdateSeoTdk extends Command @@ -595,8 +595,14 @@ class UpdateSeoTdk extends Command
595 $i= 0; 595 $i= 0;
596 foreach ($topic_words as $topic_word){ 596 foreach ($topic_words as $topic_word){
597 //关键词本身包含了前缀就不拼前缀,只拼后缀 597 //关键词本身包含了前缀就不拼前缀,只拼后缀
  598 + //关键词本身包含了前缀,可拼后缀,也可以再拼一个不重复的前缀,包含两个前缀就不拼前缀了 2025-10-14 zhl
598 if(in_array($topic_word, $all_prefixes) && $type == 'prefix'){ 599 if(in_array($topic_word, $all_prefixes) && $type == 'prefix'){
599 - return $str; 600 + if($i == $num - 1){
  601 + return $str;
  602 + }
  603 + $ban[] = $topic_word;
  604 + $i++;
  605 + $num--;
600 } 606 }
601 //关键词本身包含了后缀,可拼前缀,也可以再拼一个不重复的后缀,包含两个后缀就不拼后缀了 607 //关键词本身包含了后缀,可拼前缀,也可以再拼一个不重复的后缀,包含两个后缀就不拼后缀了
602 if(in_array($topic_word, $all_suffixes) && $type == 'suffix'){ 608 if(in_array($topic_word, $all_suffixes) && $type == 'suffix'){
@@ -683,6 +689,11 @@ class UpdateSeoTdk extends Command @@ -683,6 +689,11 @@ class UpdateSeoTdk extends Command
683 if ($type == 'suffix' && count($keywords) == 1 && in_array(Arr::last($topic_words), $all_suffixes)) { 689 if ($type == 'suffix' && count($keywords) == 1 && in_array(Arr::last($topic_words), $all_suffixes)) {
684 return ', ' . $keywords[0]; 690 return ', ' . $keywords[0];
685 } 691 }
  692 +
  693 + //前缀空格隔开
  694 + if($type == 'prefix'){
  695 + return implode(' ', $keywords);
  696 + }
686 return implode(', ', $keywords); 697 return implode(', ', $keywords);
687 } 698 }
688 699
@@ -190,9 +190,9 @@ class WorkOrderDing extends Command @@ -190,9 +190,9 @@ class WorkOrderDing extends Command
190 } 190 }
191 }catch (\Exception $exception){ 191 }catch (\Exception $exception){
192 echo now() . " | ERROR | gl_ticket_dings ID {$tickDing->id} {$exception->getMessage()} {$exception->getTraceAsString()} \n"; 192 echo now() . " | ERROR | gl_ticket_dings ID {$tickDing->id} {$exception->getMessage()} {$exception->getTraceAsString()} \n";
193 - $ding->status = 2; // 标记为失败  
194 - $ding->errorMsg = $exception->getMessage();  
195 - $ding->save(); 193 + $tickDing->status = 2; // 标记为失败
  194 + $tickDing->errorMsg = $exception->getMessage();
  195 + $tickDing->save();
196 } 196 }
197 } 197 }
198 } 198 }
@@ -93,8 +93,9 @@ class AsideTicketLogController extends BaseController @@ -93,8 +93,9 @@ class AsideTicketLogController extends BaseController
93 $ticket->end_at = now(); 93 $ticket->end_at = now();
94 $ticket->end_time = diffInHours($ticket->created_at,$ticket->end_at); 94 $ticket->end_time = diffInHours($ticket->created_at,$ticket->end_at);
95 $project = $ticket->project; 95 $project = $ticket->project;
96 - if ($project->wechat_switch && !$ticket->close_wechat) 96 + if ($project->wechat_switch && !$ticket->close_wechat){
97 $project->pushWechatGroupMsg("工单(ID:{$ticket->id})已全部完成,请访问查看详情!"); 97 $project->pushWechatGroupMsg("工单(ID:{$ticket->id})已全部完成,请访问查看详情!");
  98 + }
98 $ticket->pushDing('finish'); 99 $ticket->pushDing('finish');
99 }else{ 100 }else{
100 $ticket->status = Tickets::STATUS_YANSHOU; 101 $ticket->status = Tickets::STATUS_YANSHOU;
@@ -77,7 +77,7 @@ class GeoQuestionResController extends BaseController @@ -77,7 +77,7 @@ class GeoQuestionResController extends BaseController
77 } 77 }
78 78
79 /** 79 /**
80 - * @remark : 80 + * @remark :获取详情
81 * @name :getInfo 81 * @name :getInfo
82 * @author :lyh 82 * @author :lyh
83 * @method :post 83 * @method :post
@@ -129,4 +129,16 @@ class GeoQuestionResController extends BaseController @@ -129,4 +129,16 @@ class GeoQuestionResController extends BaseController
129 $data = $this->logic->getLabelData(); 129 $data = $this->logic->getLabelData();
130 $this->response('success',Code::SUCCESS,$data); 130 $this->response('success',Code::SUCCESS,$data);
131 } 131 }
  132 +
  133 + /**
  134 + * @remark :根据项目获取
  135 + * @name :getPlatformCount
  136 + * @author :lyh
  137 + * @method :post
  138 + * @time :2025/10/14 10:43
  139 + */
  140 + public function getPlatformCount(){
  141 + $data = $this->logic->getPlatformCount();
  142 + $this->response('success',Code::SUCCESS,$data);
  143 + }
132 } 144 }
@@ -177,7 +177,7 @@ class LoginController extends BaseController @@ -177,7 +177,7 @@ class LoginController extends BaseController
177 } 177 }
178 $wechat = new Wechat(); 178 $wechat = new Wechat();
179 $accessToken = $wechat->getAccessToken(); 179 $accessToken = $wechat->getAccessToken();
180 - $data = $wechat->setQrcode('global-v6_'.$this->param['type'].'_'.$this->param['id'],$accessToken); 180 + $data = $wechat->setQrcode('global-v6_'.$this->param['type'].'_'.$this->param['id'].'_'.($this->param['project_id'] ?? 0),$accessToken);
181 if(!empty($data) && isset($data['ticket'])){ 181 if(!empty($data) && isset($data['ticket'])){
182 $data['url'] = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=".$data['ticket']; 182 $data['url'] = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=".$data['ticket'];
183 } 183 }
@@ -313,7 +313,7 @@ class LoginController extends BaseController @@ -313,7 +313,7 @@ class LoginController extends BaseController
313 if($key[1] == 'login'){ 313 if($key[1] == 'login'){
314 $data = $userLoginLogic->wechatLogin($wechat); 314 $data = $userLoginLogic->wechatLogin($wechat);
315 }elseif($key[1] == 'bind'){ 315 }elseif($key[1] == 'bind'){
316 - $data = $userLoginLogic->wechatBind($wechat,$key[2]); 316 + $data = $userLoginLogic->wechatBind($wechat,$key[2],$key[3] ?? 0);
317 }else{ 317 }else{
318 $data = [ 318 $data = [
319 'code'=>0, 319 'code'=>0,
@@ -6,6 +6,7 @@ use App\Helper\Translate; @@ -6,6 +6,7 @@ use App\Helper\Translate;
6 use App\Http\Logic\Bside\BaseLogic; 6 use App\Http\Logic\Bside\BaseLogic;
7 use App\Models\Ai\AiBlogAuthor; 7 use App\Models\Ai\AiBlogAuthor;
8 use App\Models\Ai\AiVideo; 8 use App\Models\Ai\AiVideo;
  9 +use App\Models\AyrShare\AyrShare;
9 use App\Models\Project\AiBlogTask; 10 use App\Models\Project\AiBlogTask;
10 use App\Models\Project\AiVideoTask; 11 use App\Models\Project\AiVideoTask;
11 use App\Models\Project\ProjectAiSetting; 12 use App\Models\Project\ProjectAiSetting;
@@ -66,8 +67,16 @@ class AiVideoLogic extends BaseLogic @@ -66,8 +67,16 @@ class AiVideoLogic extends BaseLogic
66 $aiVideoTaskModel = new AiVideoTask(); 67 $aiVideoTaskModel = new AiVideoTask();
67 $aiVideoService = new AiVideoService($this->user['project_id']); 68 $aiVideoService = new AiVideoService($this->user['project_id']);
68 $storage = $aiVideoTaskModel->videoSetting()[$this->user['video_setting'] ?? 1]; 69 $storage = $aiVideoTaskModel->videoSetting()[$this->user['video_setting'] ?? 1];
  70 + if($storage == 'YOUTUBE'){
  71 + //查看是否有ayr账号
  72 + $ayrModel = new AyrShare();
  73 + $ayrInfo = $ayrModel->read(['project_id'=>$this->param['project_id'],'bind_platforms'=>['like','%"youtube"%'],'profile_key'=>['!=',null]]);
  74 + if($ayrInfo !== false){
  75 + $ayrshare_profile_key = $ayrInfo['profile_key'];
  76 + }
  77 + }
69 //todo::获取ayr的key 78 //todo::获取ayr的key
70 - $result = $aiVideoService->createTask($this->param['title'],$this->param['description'],$this->param['images'],$this->param['anchor'] ?? [],$storage); 79 + $result = $aiVideoService->createTask($this->param['title'],$this->param['description'],$this->param['images'],$this->param['anchor'] ?? [],$storage,$ayrshare_profile_key ?? '');
71 if($result['status'] == 200){ 80 if($result['status'] == 200){
72 $aiVideoTaskModel->addReturnId(['task_id'=>$result['data']['task_id'],'project_id'=>$this->user['project_id'],'storage'=>$storage]); 81 $aiVideoTaskModel->addReturnId(['task_id'=>$result['data']['task_id'],'project_id'=>$this->user['project_id'],'storage'=>$storage]);
73 $id = $this->model->addReturnId(['title'=>$this->param['title'],'task_id'=>$result['data']['task_id'],'description'=>$this->param['description'],'project_id'=>$this->user['project_id'],'images'=>json_encode($this->param['images'],true),'anchor'=>json_encode($this->param['anchor'] ?? [],true)]); 82 $id = $this->model->addReturnId(['title'=>$this->param['title'],'task_id'=>$result['data']['task_id'],'description'=>$this->param['description'],'project_id'=>$this->user['project_id'],'images'=>json_encode($this->param['images'],true),'anchor'=>json_encode($this->param['anchor'] ?? [],true)]);
@@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
10 namespace App\Http\Logic\Bside\Geo; 10 namespace App\Http\Logic\Bside\Geo;
11 11
12 use App\Http\Logic\Bside\BaseLogic; 12 use App\Http\Logic\Bside\BaseLogic;
  13 +use App\Models\Geo\GeoCount;
13 use App\Models\Geo\GeoPlatform; 14 use App\Models\Geo\GeoPlatform;
14 use App\Models\Geo\GeoQuestion; 15 use App\Models\Geo\GeoQuestion;
15 use App\Models\Geo\GeoQuestionLog; 16 use App\Models\Geo\GeoQuestionLog;
@@ -98,7 +99,7 @@ class GeoQuestionResLogic extends BaseLogic @@ -98,7 +99,7 @@ class GeoQuestionResLogic extends BaseLogic
98 $list = $questionModel->list(['project_id'=>$this->user['project_id']],['question','keywords','url']); 99 $list = $questionModel->list(['project_id'=>$this->user['project_id']],['question','keywords','url']);
99 $core_question_count = $questionTotalCount = $urlTotalCount = $keywordsTotalCount = 0; 100 $core_question_count = $questionTotalCount = $urlTotalCount = $keywordsTotalCount = 0;
100 $keywordArr = []; 101 $keywordArr = [];
101 - $questionLogModel = new GeoQuestionLog(); 102 + $questionLogModel = new GeoQuestionResult();
102 if($this->user['project_id'] == 4533){ 103 if($this->user['project_id'] == 4533){
103 $keywordUrlCount = $questionLogModel->counts(['project_id'=>$this->user['project_id'],'is_match'=>1,'hit'=>['!=',0]]); 104 $keywordUrlCount = $questionLogModel->counts(['project_id'=>$this->user['project_id'],'is_match'=>1,'hit'=>['!=',0]]);
104 foreach ($list as $item){ 105 foreach ($list as $item){
@@ -119,9 +120,8 @@ class GeoQuestionResLogic extends BaseLogic @@ -119,9 +120,8 @@ class GeoQuestionResLogic extends BaseLogic
119 'core_question_count'=>$core_question_count,//核心问题总数 120 'core_question_count'=>$core_question_count,//核心问题总数
120 'keywords_url_count'=>$keywordUrlCount, 121 'keywords_url_count'=>$keywordUrlCount,
121 'keywords_arr' => $keywordArr, 122 'keywords_arr' => $keywordArr,
122 - 'core_keyword_url_count'=>$coreKeywordUrlCount ?? 0 123 + 'core_keyword_url_count'=>$coreKeywordUrlCount ?? 0,
123 ]; 124 ];
124 - return $this->success($data);  
125 }else{ 125 }else{
126 $keywordUrlCount = $questionLogModel->counts(['project_id'=>$this->user['project_id'],'hit'=>['!=',0]]); 126 $keywordUrlCount = $questionLogModel->counts(['project_id'=>$this->user['project_id'],'hit'=>['!=',0]]);
127 foreach ($list as $item){ 127 foreach ($list as $item){
@@ -141,8 +141,18 @@ class GeoQuestionResLogic extends BaseLogic @@ -141,8 +141,18 @@ class GeoQuestionResLogic extends BaseLogic
141 'keywords_url_count'=>$keywordUrlCount, 141 'keywords_url_count'=>$keywordUrlCount,
142 'keywords_arr' => $keywordArr, 142 'keywords_arr' => $keywordArr,
143 ]; 143 ];
144 - return $this->success($data);  
145 } 144 }
  145 + //问题达标数据
  146 + $data['question_qualify_count'] = $questionLogModel->where('project_id', $this->user['project_id'])
  147 + ->where('hit','!=',0)->whereIn('platform',['openai', 'gemini','google_ai_overview'])
  148 + ->select(DB::raw('COUNT(DISTINCT question) as total'))
  149 + ->value('total');
  150 + $latestCreatedAt = $questionLogModel
  151 + ->where('project_id', $this->user['project_id'])
  152 + ->orderBy('id', 'desc')
  153 + ->value('created_at');
  154 + $data['date'] = $latestCreatedAt ? date('Y-m-d', strtotime($latestCreatedAt)) : null;
  155 + return $this->success($data);
146 } 156 }
147 157
148 /** 158 /**
@@ -156,7 +166,7 @@ class GeoQuestionResLogic extends BaseLogic @@ -156,7 +166,7 @@ class GeoQuestionResLogic extends BaseLogic
156 $data = []; 166 $data = [];
157 $platformModel = new GeoPlatform(); 167 $platformModel = new GeoPlatform();
158 $list = $platformModel->list(['status'=>1],'id',['name','en_name']); 168 $list = $platformModel->list(['status'=>1],'id',['name','en_name']);
159 - $questionResModel = new GeoQuestionLog(); 169 + $questionResModel = new GeoQuestionResult();
160 foreach ($list as $item){ 170 foreach ($list as $item){
161 if($this->user['project_id'] == 4533){ 171 if($this->user['project_id'] == 4533){
162 $data[$item['name']] = $questionResModel->counts(['project_id'=>$this->user['project_id'],'is_match'=>1,'hit'=>['!=',0],'platform'=>$item['en_name']]); 172 $data[$item['name']] = $questionResModel->counts(['project_id'=>$this->user['project_id'],'is_match'=>1,'hit'=>['!=',0],'platform'=>$item['en_name']]);
@@ -196,4 +206,18 @@ class GeoQuestionResLogic extends BaseLogic @@ -196,4 +206,18 @@ class GeoQuestionResLogic extends BaseLogic
196 } 206 }
197 return $this->success($data); 207 return $this->success($data);
198 } 208 }
  209 +
  210 + /**
  211 + * @remark :获取图标数据
  212 + * @name :getPlatformCount
  213 + * @author :lyh
  214 + * @method :post
  215 + * @time :2025/10/14 10:45
  216 + */
  217 + public function getPlatformCount()
  218 + {
  219 + $geoCountModel = new GeoCount();
  220 + $lists = $geoCountModel->list(['project_id'=>$this->user['project_id']],'date',['*'],'desc',30);
  221 + return $this->success($lists);
  222 + }
199 } 223 }
@@ -394,7 +394,7 @@ class UserLoginLogic @@ -394,7 +394,7 @@ class UserLoginLogic
394 * @method :post 394 * @method :post
395 * @time :2023/9/1 11:43 395 * @time :2023/9/1 11:43
396 */ 396 */
397 - public function wechatBind($wechat,$id){ 397 + public function wechatBind($wechat,$id,$project_id = 0){
398 $info = $this->model->read(['wechat'=>$wechat]); 398 $info = $this->model->read(['wechat'=>$wechat]);
399 if($info !== false){ 399 if($info !== false){
400 $data = [ 400 $data = [
  1 +<?php
  2 +/**
  3 + * @remark :
  4 + * @name :GeoCount.php
  5 + * @author :lyh
  6 + * @method :post
  7 + * @time :2025/10/14 10:23
  8 + */
  9 +
  10 +namespace App\Models\Geo;
  11 +
  12 +use App\Models\Base;
  13 +
  14 +class GeoCount extends Base
  15 +{
  16 + protected $table = 'gl_geo_count';
  17 +}
@@ -453,33 +453,50 @@ class SyncSubmitTaskService @@ -453,33 +453,50 @@ class SyncSubmitTaskService
453 453
454 //关杰 全局过滤 满足 name、message 8-16 纯字母不含空格 ip 荷兰 mobile 10位纯数字 过滤 454 //关杰 全局过滤 满足 name、message 8-16 纯字母不含空格 ip 荷兰 mobile 10位纯数字 过滤
455 if( 455 if(
456 - strlen($data['data']['name']) <= 16 && strlen($data['data']['name']) >= 8 &&  
457 - strlen($data['data']['message']) <= 16 && strlen($data['data']['message']) >= 8 &&  
458 - preg_match('/^[a-zA-Z]+$/', $data['data']['name']) &&  
459 - preg_match('/^[a-zA-Z]+$/', $data['data']['message']) &&  
460 - preg_match('/^\d+$/', $data['data']['phone']) &&  
461 - strlen($data['data']['phone']) == 10 &&  
462 - in_array($data['country'], ['荷兰', '俄罗斯']) 456 + strlen($data['data']['name']??'') <= 16 && strlen($data['data']['name']??'') >= 8 &&
  457 + strlen($data['data']['message']??'') <= 16 && strlen($data['data']['message']??'') >= 8 &&
  458 + preg_match('/^[a-zA-Z]+$/', $data['data']['name']??'') &&
  459 + preg_match('/^[a-zA-Z]+$/', $data['data']['message']??'') &&
  460 + preg_match('/^\d+$/', $data['data']['phone']??'') &&
  461 + strlen($data['data']['phone']??'') == 10 &&
  462 + in_array($data['country']??'', ['荷兰', '俄罗斯'])
  463 + ){
  464 + throw new InquiryFilterException( '全局过滤');
  465 + }
  466 + if(
  467 + strlen($data['data']['name']??'') <= 16 && strlen($data['data']['name']??'') >= 8 &&
  468 + strlen($data['data']['message']??'') <= 16 && strlen($data['data']['message']??'') >= 8 &&
  469 + preg_match('/^[a-zA-Z]+$/', $data['data']['name']??'') &&
  470 + preg_match('/^[a-zA-Z]+$/', $data['data']['message']??'') &&
  471 + in_array($data['country']??'', ['荷兰', '俄罗斯'])
463 ){ 472 ){
464 throw new InquiryFilterException( '全局过滤'); 473 throw new InquiryFilterException( '全局过滤');
465 } 474 }
466 //全局过滤 ip 荷兰 有name、phone、email字段,但都是空 475 //全局过滤 ip 荷兰 有name、phone、email字段,但都是空
467 if( 476 if(
468 - in_array($data['country'], ['荷兰', '俄罗斯']) &&  
469 - isset($data['data']['name']) &&  
470 - isset($data['data']['phone']) &&  
471 - isset($data['data']['email']) && 477 + in_array($data['country']??'', ['荷兰', '俄罗斯']) &&
  478 + array_key_exists('name', $data['data']) &&
  479 + array_key_exists('phone', $data['data']) &&
  480 + array_key_exists('email', $data['data']) &&
472 empty($data['data']['name']) && 481 empty($data['data']['name']) &&
473 empty($data['data']['phone']) && 482 empty($data['data']['phone']) &&
474 empty($data['data']['email']) 483 empty($data['data']['email'])
475 ){ 484 ){
476 - throw new InquiryFilterException( '全局过滤'); 485 + throw new InquiryFilterException( '全局过滤2');
  486 + }
  487 +
  488 + //1913宁波市鄞州永鑫 ip荷兰 message 8-16 纯字母不含空格
  489 + if($project_id == 1913 && in_array($data['country']??'', ['荷兰', '俄罗斯'])
  490 + && strlen($data['data']['message']??'') <= 16 && strlen($data['data']['message']??"") >= 8
  491 + && preg_match('/^[a-zA-Z]+$/', $data['data']['message']??'')
  492 + ){
  493 + throw new InquiryFilterException( '被刷数据');
477 } 494 }
478 495
479 //数据都是空的 496 //数据都是空的
480 $is_all_empty = true; 497 $is_all_empty = true;
481 foreach ($data['data'] as $item){ 498 foreach ($data['data'] as $item){
482 - if(Str::startsWith(strtolower($item),'globalso-')){ 499 + if(is_string($item) && Str::startsWith(strtolower($item),'globalso-')){
483 continue; 500 continue;
484 } 501 }
485 if(!empty($item)){ 502 if(!empty($item)){
@@ -766,6 +766,7 @@ Route::middleware(['bloginauth'])->group(function () { @@ -766,6 +766,7 @@ Route::middleware(['bloginauth'])->group(function () {
766 Route::any('/getCount', [\App\Http\Controllers\Bside\Geo\GeoQuestionResController::class, 'getCount'])->name('geo_result_getCount');//geo设置类型统计数量 766 Route::any('/getCount', [\App\Http\Controllers\Bside\Geo\GeoQuestionResController::class, 'getCount'])->name('geo_result_getCount');//geo设置类型统计数量
767 Route::any('/countQuantity', [\App\Http\Controllers\Bside\Geo\GeoQuestionResController::class, 'countQuantity'])->name('geo_result_countQuantity');//geo统计 767 Route::any('/countQuantity', [\App\Http\Controllers\Bside\Geo\GeoQuestionResController::class, 'countQuantity'])->name('geo_result_countQuantity');//geo统计
768 Route::any('/getSearchDate', [\App\Http\Controllers\Bside\Geo\GeoQuestionResController::class, 'getSearchDate'])->name('geo_result_getSearchDate');//搜索记录时间 768 Route::any('/getSearchDate', [\App\Http\Controllers\Bside\Geo\GeoQuestionResController::class, 'getSearchDate'])->name('geo_result_getSearchDate');//搜索记录时间
  769 + Route::any('/getPlatformCount', [\App\Http\Controllers\Bside\Geo\GeoQuestionResController::class, 'getPlatformCount'])->name('geo_result_getPlatformCount');//搜索记录时间
769 }); 770 });
770 }); 771 });
771 //无需登录验证的路由组 772 //无需登录验证的路由组