作者 刘锟

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

... ... @@ -10,6 +10,7 @@
namespace App\Console\Commands\Ai;
use App\Models\Ai\AiVideo;
use App\Models\AyrShare\AyrShare;
use App\Models\Domain\DomainInfo;
use App\Models\Product\Keyword;
use App\Models\Product\Product;
... ... @@ -241,7 +242,15 @@ class AiVideoAutoPublish extends Command
$storage = $aiVideoTaskModel->videoSetting()[$video_setting ?? 1];
$frequency = $aiVideoTaskModel->videoFrequency()[$frequency_setting ?? 1];
$frequencyArr = explode('-',$frequency);
$result = $aiVideoService->createTask($info['title'],$info['remark'],array_slice($info['images'], 0, 8),[],$storage);
if($storage == 'YOUTUBE'){
//查看是否有ayr账号
$ayrModel = new AyrShare();
$ayrInfo = $ayrModel->read(['project_id'=>$this->param['project_id'],'bind_platforms'=>['like','%"youtube"%'],'profile_key'=>['!=',null]]);
if($ayrInfo !== false){
$ayrshare_profile_key = $ayrInfo['profile_key'];
}
}
$result = $aiVideoService->createTask($info['title'],$info['remark'],array_slice($info['images'], 0, 8),[],$storage,$ayrshare_profile_key ?? '');
if($result['status'] == 200){
$next_auto_date = date('Y-m-d', strtotime('+' . mt_rand($frequencyArr[0] ?? 5,$frequencyArr[1] ?? 7) . 'days')); //每5-7天自动发布
$aiVideoTaskModel->addReturnId(['next_auto_date'=>$next_auto_date,'task_id'=>$result['data']['task_id'],'project_id'=>$info['project_id'],'storage'=>$storage]);
... ...
<?php
/**
* @remark :
* @name :GeoCount.php
* @author :lyh
* @method :post
* @time :2025/10/13 16:05
*/
namespace App\Console\Commands\Geo;
use App\Models\Geo\GeoQuestionLog;
use App\Models\Geo\GeoQuestionResult;
use Illuminate\Console\Command;
use Illuminate\Support\Carbon;
use App\Models\Geo\GeoCount as GeoCountModel;
class GeoCount extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'geo_count';
public $porject_id;//记录当时执行的project_id
/**
* The console command description.
*
* @var string
*/
protected $description = 'geo统计数据';
public function handle(){
$this->output('start');
$this->_action();
$this->output('end');
return true;
}
/**
* @remark :方法
* @name :_action
* @author :lyh
* @method :post
* @time :2025/10/13 16:20
*/
public function _action()
{
$geoCountModel = new GeoCountModel();
//获取前一天的项目id
$date = Carbon::yesterday()->format('Y-m-d');
$start = $date.' 00:00:00';
$end = $date.' 23:59:59';
$geoLogModel = new GeoQuestionLog();
$project_id = $geoLogModel->formatQuery(['created_at' => ['between',[$start,$end]]])->distinct()->pluck('project_id');
if(empty($project_id)){
return true;
}
$geoQuestionResModel = new GeoQuestionResult();
$platforms = ['gemini','openai','deepseek','poe','perplexity','google_ai_overview','openai-not-network','claude'];
foreach ($project_id as $item){
$this->output('执行的项目ID----'.$item);
//收录总数
$total = $geoQuestionResModel->counts(['project_id' => $item,'hit'=>['!=',0],'created_at' => ['between',[$start,$end]]]);
$data = [
'project_id' => $item,
'date' => $date,
'created_at' => Carbon::now()->format('Y-m-d H:i:s'),
'updated_at' => Carbon::now()->format('Y-m-d H:i:s'),
'total'=>$total,//收录总数
];
foreach ($platforms as $platform){
if($platform == 'openai-not-network'){
$data['openai_not_network'] = $geoQuestionResModel->counts(['project_id' => $item,'hit'=>['!=',0],'platform'=>$platform,'created_at' => ['between',[$start,$end]]]);
}else{
$data[$platform] = $geoQuestionResModel->counts(['project_id' => $item,'hit'=>['!=',0],'platform'=>$platform,'created_at' => ['between',[$start,$end]]]);
}
}
//新增一条数据
$geoCountModel->addReturnId($data);
}
return true;
}
/**
* 输出日志
* @param $message
* @return bool
*/
public function output($message)
{
echo date('Y-m-d H:i:s') . ' ' . $message . PHP_EOL;
return true;
}
}
... ...
<?php
/**
* @remark :
* @name :GeoCount.php
* @author :lyh
* @method :post
* @time :2025/10/13 16:05
*/
namespace App\Console\Commands\Geo;
use App\Models\Geo\GeoQuestionLog;
use App\Models\Geo\GeoQuestionResult;
use Illuminate\Console\Command;
use Illuminate\Support\Carbon;
use App\Models\Geo\GeoCount as GeoCountModel;
class GeoCountAll extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'geo_count_all';
public $porject_id;//记录当时执行的project_id
/**
* The console command description.
*
* @var string
*/
protected $description = 'geo统计数据';
public function handle(){
$this->output('start');
$this->_action();
$this->output('end');
return true;
}
/**
* @remark :方法
* @name :_action
* @author :lyh
* @method :post
* @time :2025/10/13 16:20
*/
public function _action()
{
$geoCountModel = new GeoCountModel();
//获取前一天的项目id
$dates = [];
for ($i = 0; $i < 100; $i++) {
$dates[] = date('Y-m-d', strtotime("-{$i} days"));
}
foreach ($dates as $date) {
$start = $date.' 00:00:00';
$end = $date.' 23:59:59';
$geoLogModel = new GeoQuestionLog();
$project_id = $geoLogModel->formatQuery(['created_at' => ['between',[$start,$end]]])->distinct()->pluck('project_id');
if(empty($project_id)){
return true;
}
$geoQuestionResModel = new GeoQuestionLog();
$platforms = ['gemini','openai','deepseek','poe','perplexity','google_ai_overview','openai-not-network','claude'];
foreach ($project_id as $item){
$this->output('执行的项目ID----'.$item);
//收录总数
$total = $geoQuestionResModel->counts(['project_id' => $item,'hit'=>['!=',0],'created_at' => ['between',[$start,$end]]]);
$data = [
'project_id' => $item,
'date' => $date,
'created_at' => Carbon::now()->format('Y-m-d H:i:s'),
'updated_at' => Carbon::now()->format('Y-m-d H:i:s'),
'total'=>$total,//收录总数
];
foreach ($platforms as $platform){
if($platform == 'openai-not-network'){
$data['openai_not_network'] = $geoQuestionResModel->counts(['project_id' => $item,'hit'=>['!=',0],'platform'=>$platform,'created_at' => ['between',[$start,$end]]]);
}else{
$data[$platform] = $geoQuestionResModel->counts(['project_id' => $item,'hit'=>['!=',0],'platform'=>$platform,'created_at' => ['between',[$start,$end]]]);
}
}
$info = $geoCountModel->read(['project_id' => $item,'date'=>$date]);
if($info === false){
//新增一条数据
$geoCountModel->addReturnId($data);
}else{
$geoCountModel->edit($data,['id'=>$info['id']]);
}
}
}
return true;
}
/**
* 输出日志
* @param $message
* @return bool
*/
public function output($message)
{
echo date('Y-m-d H:i:s') . ' ' . $message . PHP_EOL;
return true;
}
}
... ...
... ... @@ -30,6 +30,8 @@ class GeoQuestionRes extends Command
*/
protected $signature = 'geo_question_result';
public $porject_id;//记录当时执行的project_id
/**
* The console command description.
*
... ... @@ -337,15 +339,18 @@ class GeoQuestionRes extends Command
$key = 'geo_task_list';
$task_id = Redis::rpop($key);
if(empty($task_id)){
//todo::这里需要执行统计一次,统计当前项目当前日期的统计
# TODO 按照项目进行获取, 一个项目当天需要将所有跑完
$project_id = GeoQuestion::where('status', GeoQuestion::STATUS_OPEN)->where('next_time', '<=', date('Y-m-d'))->value('project_id');
if (empty($project_id))
return $task_id;
$ids = GeoQuestion::where(['project_id' => $project_id, 'status' => GeoQuestion::STATUS_OPEN])->where('current_time', '<>', date('Y-m-d'))->pluck('id');
foreach ($ids as $id) {
Redis::lpush($key, $id);
if (!empty($project_id)){
$this->project_id = $project_id;
$ids = GeoQuestion::where(['project_id' => $project_id, 'status' => GeoQuestion::STATUS_OPEN])->where('current_time', '<>', date('Y-m-d'))->pluck('id');
foreach ($ids as $id) {
Redis::lpush($key, $id);
}
$task_id = Redis::rpop($key);
}
$task_id = Redis::rpop($key);
}
return $task_id;
}
... ...
... ... @@ -979,14 +979,13 @@ class RelayInquiry extends Command
*/
public function delay_seconds($inquiry_date, $domain, $task)
{
$inquiry_date = Carbon::make($inquiry_date);
//当天的
if($inquiry_date->isToday()){
if(date('Y-m-d', strtotime($inquiry_date)) == date('Y-m-d')){
//广告投放日(周一、二、三、四) 第一封询盘100%及时推送
$is_timely = true; //是否及时推送
if(in_array($inquiry_date->weekday(), [1,2,3,4])) {
if(in_array(date('w'), [1,2,3,4])) {
//是否今天的第一封询盘
$detail = ReInquiryDetail::where('re_website', $domain)->where('start_at', '>=', $inquiry_date->startOfDay()->toDatetimeString())->first();
$detail = ReInquiryDetail::where('re_website', $domain)->where('start_at', '>=', date('Y-m-d 00:00:00'))->first();
if($detail){
$is_timely = false; //只有周一到周四的非第一封询盘 根据概率及时推送
}
... ... @@ -997,15 +996,17 @@ class RelayInquiry extends Command
$res = $this->get_rand([$task->second_push_rate, 100 - $task->second_push_rate]);
if($res == 1){
//随机分配到未投放广告日期
$now = Carbon::now();
$now = time();
// 随机开始时间(本周四或现在)
$startTime = max($now->timestamp, $now->startOfWeek(4)->timestamp);
$startTime = max($now, strtotime('this thursday'));
$random = mt_rand($startTime, $now->endOfWeek()->timestamp);
$random = mt_rand($startTime, strtotime('next monday'));
$delay = $random - time();
$delay = $random - $now;
$this->output('非广告投放日第一封询盘 概率' . (100 - $task->second_push_rate) . '%延迟推送' . $delay);
return $delay;
}else{
$this->output('非广告投放日第一封询盘 概率' . $task->second_push_rate . '%即时推送');
}
}
}
... ...
... ... @@ -64,50 +64,74 @@ class CopyOldProject extends Command
{
// 设置源数据库
config(['database.connections.custom_tmp_mysql_copy.database' => 'gl_data_' . $project_id]);
DB::purge('custom_tmp_mysql_copy');
DB::reconnect('custom_tmp_mysql_copy');
$database_name = DB::connection('custom_tmp_mysql_copy')->getDatabaseName();
// 获取源数据库的所有表
$tables = Schema::connection('custom_tmp_mysql_copy')->getAllTables();
$tables = array_column($tables, 'Tables_in_' . $database_name);
foreach ($tables as $table) {
// 目标数据库是否存在该表
$has_table = Schema::connection('custom_mysql')->hasTable($table);
if ($has_table) {
// 1. 删除目标数据库中的表
DB::connection('custom_mysql')->statement("DROP TABLE IF EXISTS {$table}");
}
// 2. 重新创建表
$sql = DB::connection('custom_tmp_mysql_copy')->select("SHOW CREATE TABLE {$table}");
DB::connection('custom_mysql')->statement(get_object_vars($sql[0])['Create Table']);
// 3. 跳过指定的表
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',
])) {
continue;
}
// 4. 重新插入数据
DB::connection('custom_mysql')->table($table)->insertUsing(
[], // 插入所有列
function ($query) use ($table, $project_id) {
$name = 'gl_data_' . $project_id . '.' . $table;
$query->select('*')->from("{$name}");
try {
// 1. 检查源表是否存在(防止 gl_data_{$project_id} 下缺表)
$exists = Schema::connection('custom_tmp_mysql_copy')->hasTable($table);
if (!$exists) {
@file_put_contents(
storage_path('logs/copy_mysql_error.log'),
"源库中不存在表:{$table}" . PHP_EOL,
FILE_APPEND
);
continue;
}
// 2. 删除目标数据库中的表
$result = DB::connection('custom_mysql')->statement("DROP TABLE IF EXISTS `{$table}`");
@file_put_contents(storage_path('logs/copy_mysql_error.log'), "删除旧表:{$table} => {$result}" . PHP_EOL, FILE_APPEND);
// 3. 复制建表 SQL
$sql = DB::connection('custom_tmp_mysql_copy')->select("SHOW CREATE TABLE `{$table}`");
$createSql = get_object_vars($sql[0])['Create Table'];
$result1 = DB::connection('custom_mysql')->statement($createSql);
@file_put_contents(storage_path('logs/copy_mysql_error.log'), "创建表:{$table} => {$result1}" . PHP_EOL, FILE_APPEND);
// 4. 跳过指定表
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'
])) {
continue;
}
// 5. 插入数据前,再次确认源表存在(双保险)
if (!Schema::connection('custom_tmp_mysql_copy')->hasTable($table)) {
@file_put_contents(storage_path('logs/copy_mysql_error.log'), "插入数据前发现表不存在:{$table}" . PHP_EOL, FILE_APPEND);
continue;
}
);
// 5. 更新 project_id(如果存在)
if (Schema::connection('custom_mysql')->hasColumn($table, 'project_id')) {
DB::connection('custom_mysql')->table($table)->update(['project_id' => $news_project_id]);
// 6. 原生 SQL 插入数据(完全复制)
$insert_sql = "INSERT INTO `{$table}` SELECT * FROM `gl_data_{$project_id}`.`{$table}`";
try {
$result2 = DB::connection('custom_mysql')->statement($insert_sql);
@file_put_contents(storage_path('logs/copy_mysql_error.log'), "插入数据成功:{$table} => {$result2}" . PHP_EOL, FILE_APPEND);
} catch (\Exception $e) {
@file_put_contents(storage_path('logs/copy_mysql_error.log'),
"插入数据失败:{$table} => " . $e->getMessage() . PHP_EOL,
FILE_APPEND
);
continue; // 跳过这个表,不中断整个流程
}
// 7. 更新 project_id(如果存在)
if (Schema::connection('custom_mysql')->hasColumn($table, 'project_id')) {
DB::connection('custom_mysql')->table($table)->update(['project_id' => $news_project_id]);
}
} catch (\Exception $e) {
@file_put_contents(
storage_path('logs/copy_mysql_error.log'),
"处理表 {$table} 出错:" . $e->getMessage() . PHP_EOL,
FILE_APPEND
);
continue;
}
}
return true;
}
/**
* @param $message
* @return bool
... ...
... ... @@ -234,33 +234,75 @@ class CopyProject extends Command
{
// 设置源数据库
config(['database.connections.custom_tmp_mysql_copy.database' => 'gl_data_' . $project_id]);
DB::purge('custom_tmp_mysql_copy');
DB::reconnect('custom_tmp_mysql_copy');
$database_name = DB::connection('custom_tmp_mysql_copy')->getDatabaseName();
// 获取源数据库的所有表
$tables = Schema::connection('custom_tmp_mysql_copy')->getAllTables();
$tables = array_column($tables, 'Tables_in_' . $database_name);
foreach ($tables as $table) {
// 1. 删除目标数据库中的表
$result = DB::connection('custom_mysql')->statement("DROP TABLE IF EXISTS {$table}");
@file_put_contents(storage_path('logs/copy_mysql_error.log'), var_export('先删除对应数据库的对应表返回结果:'.$result, true) . PHP_EOL, FILE_APPEND);
// 2. 复制建表 SQL
$sql = DB::connection('custom_tmp_mysql_copy')->select("SHOW CREATE TABLE `{$table}`");
$result1 = DB::connection('custom_mysql')->statement(get_object_vars($sql[0])['Create Table']);
@file_put_contents(storage_path('logs/copy_mysql_error.log'), var_export('创建对应表数据:'.$result1, true) . PHP_EOL, FILE_APPEND);
// 3. 跳过指定的表
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'])) {
try {
// 1. 检查源表是否存在(防止 gl_data_{$project_id} 下缺表)
$exists = Schema::connection('custom_tmp_mysql_copy')->hasTable($table);
if (!$exists) {
@file_put_contents(
storage_path('logs/copy_mysql_error.log'),
"源库中不存在表:{$table}" . PHP_EOL,
FILE_APPEND
);
continue;
}
// 2. 删除目标数据库中的表
$result = DB::connection('custom_mysql')->statement("DROP TABLE IF EXISTS `{$table}`");
@file_put_contents(storage_path('logs/copy_mysql_error.log'), "删除旧表:{$table} => {$result}" . PHP_EOL, FILE_APPEND);
// 3. 复制建表 SQL
$sql = DB::connection('custom_tmp_mysql_copy')->select("SHOW CREATE TABLE `{$table}`");
$createSql = get_object_vars($sql[0])['Create Table'];
$result1 = DB::connection('custom_mysql')->statement($createSql);
@file_put_contents(storage_path('logs/copy_mysql_error.log'), "创建表:{$table} => {$result1}" . PHP_EOL, FILE_APPEND);
// 4. 跳过指定表
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'
])) {
continue;
}
// 5. 插入数据前,再次确认源表存在(双保险)
if (!Schema::connection('custom_tmp_mysql_copy')->hasTable($table)) {
@file_put_contents(storage_path('logs/copy_mysql_error.log'), "插入数据前发现表不存在:{$table}" . PHP_EOL, FILE_APPEND);
continue;
}
// 6. 原生 SQL 插入数据(完全复制)
$insert_sql = "INSERT INTO `{$table}` SELECT * FROM `gl_data_{$project_id}`.`{$table}`";
try {
$result2 = DB::connection('custom_mysql')->statement($insert_sql);
@file_put_contents(storage_path('logs/copy_mysql_error.log'), "插入数据成功:{$table} => {$result2}" . PHP_EOL, FILE_APPEND);
} catch (\Exception $e) {
@file_put_contents(storage_path('logs/copy_mysql_error.log'),
"插入数据失败:{$table} => " . $e->getMessage() . PHP_EOL,
FILE_APPEND
);
continue; // 跳过这个表,不中断整个流程
}
// 7. 更新 project_id(如果存在)
if (Schema::connection('custom_mysql')->hasColumn($table, 'project_id')) {
DB::connection('custom_mysql')->table($table)->update(['project_id' => $news_project_id]);
}
} catch (\Exception $e) {
@file_put_contents(
storage_path('logs/copy_mysql_error.log'),
"处理表 {$table} 出错:" . $e->getMessage() . PHP_EOL,
FILE_APPEND
);
continue;
}
// 4. 原生 SQL 插入数据(完全复制)
$insert_sql = "INSERT INTO `{$table}` SELECT * FROM `gl_data_{$project_id}`.`{$table}`";
$result2 = DB::connection('custom_mysql')->statement($insert_sql);
@file_put_contents(storage_path('logs/copy_mysql_error.log'), var_export('对应表插入数据:'.$result2, true) . PHP_EOL, FILE_APPEND);
// 5. 更新 project_id(如果存在)
if (Schema::connection('custom_mysql')->hasColumn($table, 'project_id')) {
DB::connection('custom_mysql')->table($table)->update(['project_id' => $news_project_id]);
}
}
return true;
}
/**
* @param $message
* @return bool
... ...
... ... @@ -166,11 +166,8 @@ class SyncProject extends Command
];
$data['deploy_build']['plan'] = $this->versionData($param['plan_marketing'] ?? '');
$data['deploy_build']['seo_plan'] = $this->versionSeoData($param['geo_plan'] ?? '');
if(!empty($data['deploy_build']['plan'])){
$data['deploy_build']['service_duration'] = $param['years'] ?? 0;
}else{
$data['deploy_build']['seo_service_duration'] = $param['years'] ?? 0;
}
$data['deploy_build']['service_duration'] = $param['years'] ?? 0;
$data['deploy_build']['seo_service_duration'] = $param['geo_plan_day'] ?? 0;
$renewModel = new ProjectRenew();
$rs = $renewModel->add($data);
if($rs === false){
... ... @@ -256,11 +253,8 @@ class SyncProject extends Command
];
$data['deploy_build']['plan'] = $this->versionData($param['plan_marketing'] ?? '');
$data['deploy_build']['seo_plan'] = $this->versionSeoData($param['geo_plan'] ?? '');
if(!empty($data['deploy_build']['plan'])){
$data['deploy_build']['service_duration'] = $param['years'] ?? 0;
}else{
$data['deploy_build']['seo_service_duration'] = $param['years'] ?? 0;
}
$data['deploy_build']['service_duration'] = $param['years'] ?? 0;
$data['deploy_build']['seo_service_duration'] = $param['geo_plan_day'] ?? 0;
DB::beginTransaction();
try {
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
$seo_title = $v[$this->topic_fields[$table]];;
//只有推广项目 才加 前后缀
if($project->type == Project::TYPE_TWO) {
$prefix = $this->getPrefixKeyword($project_id, 'prefix', 1, $seo_title);
$prefix = $this->getPrefixKeyword($project_id, 'prefix', 2, $seo_title);
$suffix = $this->getPrefixKeyword($project_id, 'suffix', 2, trim($prefix . ' ' . $seo_title));
if(Str::startsWith($suffix, ', ')){
$seo_title = $prefix . ' ' . $seo_title . $suffix;
... ... @@ -574,7 +574,7 @@ class UpdateSeoTdk extends Command
return $str;
}
//前后缀(包括自定义前后缀)如果已经存在,就不在拼接当前类型 后缀只包含了一个,要再拼一个(需去重)
//前后缀(包括自定义前后缀)如果已经存在,就不在拼接当前类型 前、后缀只包含了一个,要再拼一个(需去重)
$all_prefixes = $this->getAllPrefix(1, $project_id);
$all_prefixes = array_map('strtolower', $all_prefixes);
... ... @@ -595,8 +595,14 @@ class UpdateSeoTdk extends Command
$i= 0;
foreach ($topic_words as $topic_word){
//关键词本身包含了前缀就不拼前缀,只拼后缀
//关键词本身包含了前缀,可拼后缀,也可以再拼一个不重复的前缀,包含两个前缀就不拼前缀了 2025-10-14 zhl
if(in_array($topic_word, $all_prefixes) && $type == 'prefix'){
return $str;
if($i == $num - 1){
return $str;
}
$ban[] = $topic_word;
$i++;
$num--;
}
//关键词本身包含了后缀,可拼前缀,也可以再拼一个不重复的后缀,包含两个后缀就不拼后缀了
if(in_array($topic_word, $all_suffixes) && $type == 'suffix'){
... ... @@ -683,6 +689,11 @@ class UpdateSeoTdk extends Command
if ($type == 'suffix' && count($keywords) == 1 && in_array(Arr::last($topic_words), $all_suffixes)) {
return ', ' . $keywords[0];
}
//前缀空格隔开
if($type == 'prefix'){
return implode(' ', $keywords);
}
return implode(', ', $keywords);
}
... ...
... ... @@ -190,9 +190,9 @@ class WorkOrderDing extends Command
}
}catch (\Exception $exception){
echo now() . " | ERROR | gl_ticket_dings ID {$tickDing->id} {$exception->getMessage()} {$exception->getTraceAsString()} \n";
$ding->status = 2; // 标记为失败
$ding->errorMsg = $exception->getMessage();
$ding->save();
$tickDing->status = 2; // 标记为失败
$tickDing->errorMsg = $exception->getMessage();
$tickDing->save();
}
}
}
... ...
... ... @@ -93,8 +93,9 @@ class AsideTicketLogController extends BaseController
$ticket->end_at = now();
$ticket->end_time = diffInHours($ticket->created_at,$ticket->end_at);
$project = $ticket->project;
if ($project->wechat_switch && !$ticket->close_wechat)
if ($project->wechat_switch && !$ticket->close_wechat){
$project->pushWechatGroupMsg("工单(ID:{$ticket->id})已全部完成,请访问查看详情!");
}
$ticket->pushDing('finish');
}else{
$ticket->status = Tickets::STATUS_YANSHOU;
... ...
... ... @@ -77,7 +77,7 @@ class GeoQuestionResController extends BaseController
}
/**
* @remark :
* @remark :获取详情
* @name :getInfo
* @author :lyh
* @method :post
... ... @@ -129,4 +129,16 @@ class GeoQuestionResController extends BaseController
$data = $this->logic->getLabelData();
$this->response('success',Code::SUCCESS,$data);
}
/**
* @remark :根据项目获取
* @name :getPlatformCount
* @author :lyh
* @method :post
* @time :2025/10/14 10:43
*/
public function getPlatformCount(){
$data = $this->logic->getPlatformCount();
$this->response('success',Code::SUCCESS,$data);
}
}
... ...
... ... @@ -177,7 +177,7 @@ class LoginController extends BaseController
}
$wechat = new Wechat();
$accessToken = $wechat->getAccessToken();
$data = $wechat->setQrcode('global-v6_'.$this->param['type'].'_'.$this->param['id'],$accessToken);
$data = $wechat->setQrcode('global-v6_'.$this->param['type'].'_'.$this->param['id'].'_'.($this->param['project_id'] ?? 0),$accessToken);
if(!empty($data) && isset($data['ticket'])){
$data['url'] = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=".$data['ticket'];
}
... ... @@ -313,7 +313,7 @@ class LoginController extends BaseController
if($key[1] == 'login'){
$data = $userLoginLogic->wechatLogin($wechat);
}elseif($key[1] == 'bind'){
$data = $userLoginLogic->wechatBind($wechat,$key[2]);
$data = $userLoginLogic->wechatBind($wechat,$key[2],$key[3] ?? 0);
}else{
$data = [
'code'=>0,
... ...
... ... @@ -6,6 +6,7 @@ use App\Helper\Translate;
use App\Http\Logic\Bside\BaseLogic;
use App\Models\Ai\AiBlogAuthor;
use App\Models\Ai\AiVideo;
use App\Models\AyrShare\AyrShare;
use App\Models\Project\AiBlogTask;
use App\Models\Project\AiVideoTask;
use App\Models\Project\ProjectAiSetting;
... ... @@ -66,8 +67,16 @@ class AiVideoLogic extends BaseLogic
$aiVideoTaskModel = new AiVideoTask();
$aiVideoService = new AiVideoService($this->user['project_id']);
$storage = $aiVideoTaskModel->videoSetting()[$this->user['video_setting'] ?? 1];
if($storage == 'YOUTUBE'){
//查看是否有ayr账号
$ayrModel = new AyrShare();
$ayrInfo = $ayrModel->read(['project_id'=>$this->param['project_id'],'bind_platforms'=>['like','%"youtube"%'],'profile_key'=>['!=',null]]);
if($ayrInfo !== false){
$ayrshare_profile_key = $ayrInfo['profile_key'];
}
}
//todo::获取ayr的key
$result = $aiVideoService->createTask($this->param['title'],$this->param['description'],$this->param['images'],$this->param['anchor'] ?? [],$storage);
$result = $aiVideoService->createTask($this->param['title'],$this->param['description'],$this->param['images'],$this->param['anchor'] ?? [],$storage,$ayrshare_profile_key ?? '');
if($result['status'] == 200){
$aiVideoTaskModel->addReturnId(['task_id'=>$result['data']['task_id'],'project_id'=>$this->user['project_id'],'storage'=>$storage]);
$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 @@
namespace App\Http\Logic\Bside\Geo;
use App\Http\Logic\Bside\BaseLogic;
use App\Models\Geo\GeoCount;
use App\Models\Geo\GeoPlatform;
use App\Models\Geo\GeoQuestion;
use App\Models\Geo\GeoQuestionLog;
... ... @@ -98,7 +99,7 @@ class GeoQuestionResLogic extends BaseLogic
$list = $questionModel->list(['project_id'=>$this->user['project_id']],['question','keywords','url']);
$core_question_count = $questionTotalCount = $urlTotalCount = $keywordsTotalCount = 0;
$keywordArr = [];
$questionLogModel = new GeoQuestionLog();
$questionLogModel = new GeoQuestionResult();
if($this->user['project_id'] == 4533){
$keywordUrlCount = $questionLogModel->counts(['project_id'=>$this->user['project_id'],'is_match'=>1,'hit'=>['!=',0]]);
foreach ($list as $item){
... ... @@ -119,9 +120,8 @@ class GeoQuestionResLogic extends BaseLogic
'core_question_count'=>$core_question_count,//核心问题总数
'keywords_url_count'=>$keywordUrlCount,
'keywords_arr' => $keywordArr,
'core_keyword_url_count'=>$coreKeywordUrlCount ?? 0
'core_keyword_url_count'=>$coreKeywordUrlCount ?? 0,
];
return $this->success($data);
}else{
$keywordUrlCount = $questionLogModel->counts(['project_id'=>$this->user['project_id'],'hit'=>['!=',0]]);
foreach ($list as $item){
... ... @@ -141,8 +141,18 @@ class GeoQuestionResLogic extends BaseLogic
'keywords_url_count'=>$keywordUrlCount,
'keywords_arr' => $keywordArr,
];
return $this->success($data);
}
//问题达标数据
$data['question_qualify_count'] = $questionLogModel->where('project_id', $this->user['project_id'])
->where('hit','!=',0)->whereIn('platform',['openai', 'gemini','google_ai_overview'])
->select(DB::raw('COUNT(DISTINCT question) as total'))
->value('total');
$latestCreatedAt = $questionLogModel
->where('project_id', $this->user['project_id'])
->orderBy('id', 'desc')
->value('created_at');
$data['date'] = $latestCreatedAt ? date('Y-m-d', strtotime($latestCreatedAt)) : null;
return $this->success($data);
}
/**
... ... @@ -156,7 +166,7 @@ class GeoQuestionResLogic extends BaseLogic
$data = [];
$platformModel = new GeoPlatform();
$list = $platformModel->list(['status'=>1],'id',['name','en_name']);
$questionResModel = new GeoQuestionLog();
$questionResModel = new GeoQuestionResult();
foreach ($list as $item){
if($this->user['project_id'] == 4533){
$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
}
return $this->success($data);
}
/**
* @remark :获取图标数据
* @name :getPlatformCount
* @author :lyh
* @method :post
* @time :2025/10/14 10:45
*/
public function getPlatformCount()
{
$geoCountModel = new GeoCount();
$lists = $geoCountModel->list(['project_id'=>$this->user['project_id']],'date',['*'],'desc',30);
return $this->success($lists);
}
}
... ...
... ... @@ -394,7 +394,7 @@ class UserLoginLogic
* @method :post
* @time :2023/9/1 11:43
*/
public function wechatBind($wechat,$id){
public function wechatBind($wechat,$id,$project_id = 0){
$info = $this->model->read(['wechat'=>$wechat]);
if($info !== false){
$data = [
... ...
<?php
/**
* @remark :
* @name :GeoCount.php
* @author :lyh
* @method :post
* @time :2025/10/14 10:23
*/
namespace App\Models\Geo;
use App\Models\Base;
class GeoCount extends Base
{
protected $table = 'gl_geo_count';
}
... ...
... ... @@ -453,33 +453,50 @@ class SyncSubmitTaskService
//关杰 全局过滤 满足 name、message 8-16 纯字母不含空格 ip 荷兰 mobile 10位纯数字 过滤
if(
strlen($data['data']['name']) <= 16 && strlen($data['data']['name']) >= 8 &&
strlen($data['data']['message']) <= 16 && strlen($data['data']['message']) >= 8 &&
preg_match('/^[a-zA-Z]+$/', $data['data']['name']) &&
preg_match('/^[a-zA-Z]+$/', $data['data']['message']) &&
preg_match('/^\d+$/', $data['data']['phone']) &&
strlen($data['data']['phone']) == 10 &&
in_array($data['country'], ['荷兰', '俄罗斯'])
strlen($data['data']['name']??'') <= 16 && strlen($data['data']['name']??'') >= 8 &&
strlen($data['data']['message']??'') <= 16 && strlen($data['data']['message']??'') >= 8 &&
preg_match('/^[a-zA-Z]+$/', $data['data']['name']??'') &&
preg_match('/^[a-zA-Z]+$/', $data['data']['message']??'') &&
preg_match('/^\d+$/', $data['data']['phone']??'') &&
strlen($data['data']['phone']??'') == 10 &&
in_array($data['country']??'', ['荷兰', '俄罗斯'])
){
throw new InquiryFilterException( '全局过滤');
}
if(
strlen($data['data']['name']??'') <= 16 && strlen($data['data']['name']??'') >= 8 &&
strlen($data['data']['message']??'') <= 16 && strlen($data['data']['message']??'') >= 8 &&
preg_match('/^[a-zA-Z]+$/', $data['data']['name']??'') &&
preg_match('/^[a-zA-Z]+$/', $data['data']['message']??'') &&
in_array($data['country']??'', ['荷兰', '俄罗斯'])
){
throw new InquiryFilterException( '全局过滤');
}
//全局过滤 ip 荷兰 有name、phone、email字段,但都是空
if(
in_array($data['country'], ['荷兰', '俄罗斯']) &&
isset($data['data']['name']) &&
isset($data['data']['phone']) &&
isset($data['data']['email']) &&
in_array($data['country']??'', ['荷兰', '俄罗斯']) &&
array_key_exists('name', $data['data']) &&
array_key_exists('phone', $data['data']) &&
array_key_exists('email', $data['data']) &&
empty($data['data']['name']) &&
empty($data['data']['phone']) &&
empty($data['data']['email'])
){
throw new InquiryFilterException( '全局过滤');
throw new InquiryFilterException( '全局过滤2');
}
//1913宁波市鄞州永鑫 ip荷兰 message 8-16 纯字母不含空格
if($project_id == 1913 && in_array($data['country']??'', ['荷兰', '俄罗斯'])
&& strlen($data['data']['message']??'') <= 16 && strlen($data['data']['message']??"") >= 8
&& preg_match('/^[a-zA-Z]+$/', $data['data']['message']??'')
){
throw new InquiryFilterException( '被刷数据');
}
//数据都是空的
$is_all_empty = true;
foreach ($data['data'] as $item){
if(Str::startsWith(strtolower($item),'globalso-')){
if(is_string($item) && Str::startsWith(strtolower($item),'globalso-')){
continue;
}
if(!empty($item)){
... ...
... ... @@ -766,6 +766,7 @@ Route::middleware(['bloginauth'])->group(function () {
Route::any('/getCount', [\App\Http\Controllers\Bside\Geo\GeoQuestionResController::class, 'getCount'])->name('geo_result_getCount');//geo设置类型统计数量
Route::any('/countQuantity', [\App\Http\Controllers\Bside\Geo\GeoQuestionResController::class, 'countQuantity'])->name('geo_result_countQuantity');//geo统计
Route::any('/getSearchDate', [\App\Http\Controllers\Bside\Geo\GeoQuestionResController::class, 'getSearchDate'])->name('geo_result_getSearchDate');//搜索记录时间
Route::any('/getPlatformCount', [\App\Http\Controllers\Bside\Geo\GeoQuestionResController::class, 'getPlatformCount'])->name('geo_result_getPlatformCount');//搜索记录时间
});
});
//无需登录验证的路由组
... ...