作者 lyh

Merge branch 'master' of http://47.244.231.31:8099/zhl/globalso-v6 into master-server

  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: akun
  5 + * Date: 2025/02/26
  6 + * Time: 10:14
  7 + */
  8 +
  9 +namespace App\Console\Commands\Inquiry;
  10 +
  11 +use App\Models\Inquiry\InquiryInfo;
  12 +use App\Models\Inquiry\InquiryProject;
  13 +use App\Models\Inquiry\InquiryRelayDetail;
  14 +use App\Models\Inquiry\InquiryRelayDetailLog;
  15 +use Illuminate\Console\Command;
  16 +use Illuminate\Support\Facades\Http;
  17 +use Illuminate\Support\Facades\Log;
  18 +use Illuminate\Support\Facades\Redis;
  19 +
  20 +/**
  21 + * Class postInquiry
  22 + * @package App\Console\Commands\Inquiry
  23 + */
  24 +class PostInquiryForward extends Command
  25 +{
  26 + /**
  27 + * The name and signature of the console command.
  28 + *
  29 + * @var string
  30 + */
  31 + protected $signature = 'post_inquiry_forward';
  32 +
  33 + /**
  34 + * The console command description.
  35 + *
  36 + * @var string
  37 + */
  38 + protected $description = '执行询盘请求';
  39 +
  40 + /**
  41 + * Create a new command instance.
  42 + *
  43 + * @return void
  44 + */
  45 + public function __construct()
  46 + {
  47 + parent::__construct();
  48 + }
  49 +
  50 +
  51 + public function handle()
  52 + {
  53 + while (true) {
  54 + $list = InquiryRelayDetailLog::where('status', InquiryRelayDetailLog::STATUS_INIT)->where('start_at', '<=', date('Y-m-d H:i:s'))->orderBy('id', 'asc')->limit(100)->get();
  55 + if (!$list->count()) {
  56 + sleep(1);
  57 + }
  58 + // 询盘数据入库
  59 + foreach ($list as $key => $val) {
  60 + //加个锁 避免重复执行
  61 + $lockKey = 'inquiry_relay_detail_log_lock_' . $val->id;
  62 + if (!Redis::setnx($lockKey, 1)) {
  63 + continue;
  64 + }
  65 + Redis::expire($lockKey, 60);
  66 +
  67 + $log = InquiryRelayDetailLog::find($val->id);
  68 + if ($log->status != InquiryRelayDetailLog::STATUS_INIT) {
  69 + continue;
  70 + }
  71 +
  72 + $this->output('开始执行' . $val->id);
  73 + try {
  74 + $detail = InquiryRelayDetail::find($val['detail_id']);
  75 +
  76 + //防止 程序中断 启动时 同一时间一下就发了
  77 + $last_log = InquiryRelayDetailLog::where('detail_id', $val['detail_id'])->where('id', '<', $val['id'])->orderBy('id', 'desc')->first();
  78 + //不是第一个 或者 上一个处理失败了 直接处理
  79 + if (!empty($last_log)) {
  80 + //上一个还没有处理 直接跳过
  81 + if ($last_log->status == InquiryRelayDetailLog::STATUS_INIT) {
  82 + continue;
  83 + }
  84 + //上一个处理完成
  85 + if ($last_log->status == InquiryRelayDetailLog::STATUS_SUCCESS) {
  86 + //上次处理时间间隔达到没
  87 + $interval = strtotime($val->start_at) - strtotime($last_log->start_at);
  88 + if (time() - strtotime($last_log->updated_at) < $interval) {
  89 + continue;
  90 + }
  91 + }
  92 + }
  93 +
  94 + if ($val['type'] == 1) {
  95 + $this->visit($detail, $val);
  96 + } else {
  97 + $res = $this->inquiry($detail, $val);
  98 +
  99 + //转发表单
  100 + if ($res) {
  101 + $form = InquiryInfo::find($detail['form_id']);
  102 + $form->success = $form->success + 1;
  103 + $form->save();
  104 + Log::channel('inquiry_forward')->info('询盘成功:', [$detail['form_id'], $val->id, getmypid()]);
  105 + }
  106 + }
  107 + } catch (\Exception $e) {
  108 + Log::channel('inquiry_forward')->error('post_inquiry_forward handle error', [$e->getMessage(), $e->getFile(), $e->getLine()]);
  109 +
  110 + $val->status = InquiryRelayDetailLog::STATUS_FAIL;
  111 + $val->remark = mb_substr($e->getMessage(), 0, 200);
  112 + $val->save();
  113 + }
  114 + }
  115 + }
  116 + }
  117 +
  118 + public function visit(InquiryRelayDetail $detail, InquiryRelayDetailLog $log)
  119 + {
  120 + $website = 'https://' . $detail['website'] . '/';
  121 + if ($detail['is_v6']) {
  122 + $data = [
  123 + 'ip' => $detail['ip'],
  124 + 'url' => $log['url'],
  125 + 'device_port' => $detail['device_port'],
  126 + 'referrer_url' => $detail['referrer'],
  127 + 'user_agent' => $detail['user_agent'],
  128 + ];
  129 + $res = Http::withoutVerifying()->timeout(30)->post($website . 'api/traffic_visit/', $data)->json();
  130 + if (empty($res['status']) || $res['status'] != 200) {
  131 + $log->status = InquiryRelayDetailLog::STATUS_FAIL;
  132 + $log->remark = mb_substr($res['message'] ?? '', 0, 200);
  133 + $log->save();
  134 +
  135 + Log::channel('inquiry_forward')->error('post_inquiry_forward visit error', [$res, $website . 'api/traffic_visit/', $data]);
  136 + return false;
  137 + }
  138 + } else {
  139 + //v4 v5分离项目 往测试链接推
  140 + $project_info = InquiryProject::select(['is_split', 'test_domain'])->where('domain', 'like', '%' . $detail['website'] . '%')->first();
  141 + if (!$project_info) {
  142 + $log->status = InquiryRelayDetailLog::STATUS_FAIL;
  143 + $log->remark = '获取域名对应项目失败';
  144 + $log->save();
  145 +
  146 + return false;
  147 + }
  148 +
  149 + if ($project_info['is_split'] == 1) {
  150 + $website = $project_info['test_domain'];
  151 + }
  152 +
  153 + $data = [
  154 + 'action' => 'stats_init',
  155 + 'assort' => 0,
  156 + 'referrer' => $detail['referrer'],
  157 + 'currweb' => $log['url'],
  158 + 'user_agent' => $detail['user_agent'],
  159 + "ip" => $detail['ip'],
  160 + ];
  161 + $res = Http::get($website . 'wp-admin/admin-ajax.php', $data);
  162 + $status = $res->status();
  163 + if ($status != 200) {
  164 + $log->status = InquiryRelayDetailLog::STATUS_FAIL;
  165 + $log->remark = mb_substr($res->body() ?? '', 0, 200);
  166 + $log->save();
  167 +
  168 + Log::channel('inquiry_forward')->error('post_inquiry_forward v4|v5 visit error', [$res->body(), $website . 'wp-admin/admin-ajax.php', $data]);
  169 + return false;
  170 + }
  171 + }
  172 + $log->status = InquiryRelayDetailLog::STATUS_SUCCESS;
  173 + $log->save();
  174 + return true;
  175 + }
  176 +
  177 + public function inquiry(InquiryRelayDetail $detail, InquiryRelayDetailLog $log)
  178 + {
  179 + // v6
  180 + if ($detail['is_v6']) {
  181 + $res = $this->v6Inquiry($detail, $log);
  182 + } else {
  183 + $res = $this->v5Inquiry($detail, $log);
  184 + }
  185 +
  186 + if (!$res) {
  187 + return false;
  188 + }
  189 +
  190 + $log->status = InquiryRelayDetailLog::STATUS_SUCCESS;
  191 + $log->save();
  192 +
  193 + return true;
  194 + }
  195 +
  196 + public function v6Inquiry($detail, $log)
  197 + {
  198 + $website = 'https://' . $detail['website'] . '/';
  199 + $data = [
  200 + 'name' => $detail['name'],
  201 + 'phone' => $detail['phone'],
  202 + 'message' => $detail['message'],
  203 + 'submit_ip' => $detail['ip'],
  204 + 'refer' => $log['url'],
  205 + ];
  206 + if ($detail['email']) {
  207 + $data['email'] = $detail['email'];
  208 + } else {
  209 + $data['__amp_source_origin'] = trim($website, '/');
  210 + }
  211 + $res = Http::withoutVerifying()->timeout(30)->withHeaders(['User-Agent' => $detail['user_agent']])->post($website . 'api/inquiryQd?source=5', $data)->json();
  212 + if (empty($res['code']) || $res['code'] != 200) {
  213 + $log->status = InquiryRelayDetailLog::STATUS_FAIL;
  214 + $log->remark = mb_substr($res['message'] ?? '', 0, 200);
  215 + $log->save();
  216 + Log::channel('inquiry_forward')->error('post_inquiry_forward v6 inquiry error', [$res, $website . 'api/inquiryQd/', $data]);
  217 + return false;
  218 + }
  219 + return true;
  220 + }
  221 +
  222 + public function v5Inquiry($detail, $log)
  223 + {
  224 + $data = [
  225 + 'name' => $detail['name'],
  226 + 'phone' => $detail['phone'],
  227 + 'message' => $detail['message'],
  228 + 'email' => $detail['email'],
  229 + 'ip' => $detail['ip'],
  230 + 'token' => md5($log['url'] . $detail['name'] . $detail['ip'] . date("Y-m-d")),
  231 + 'refer' => $log['url'],
  232 + 'submit_time' => date('Y-m-d H:i:s'),
  233 + 'source' => 5,
  234 + ];
  235 + $result = Http::withoutVerifying()->timeout(30)->post('https://www.globalso.site/api/external-interface/add/fa043f9cbec6b38f', $data);
  236 + $res['data'][0]['status'] = 'success';
  237 + //兼容接口返回格式
  238 + if (!empty($res['data'][0]['status'])) {
  239 + $res['data'][0]['code'] = $res['data'][0]['status'] == 'success' ? 200 : 400;
  240 + !empty($res['data'][0]['msg']) && $res['message'] = $res['data'][0]['msg'];
  241 + }
  242 + if (empty($res['data'][0]['code']) || !in_array($res['data'][0]['code'], [200, 300])) {
  243 + $log->status = InquiryRelayDetailLog::STATUS_FAIL;
  244 + $log->remark = mb_substr($res['message'] ?? '', 0, 200);
  245 + $log->save();
  246 +
  247 + Log::channel('inquiry_forward')->error('post_inquiry_forward v4|v5 inquiry error', [$result->body(), 'https://www.globalso.site/api/external-interface/add/fa043f9cbec6b38f', $data]);
  248 + return false;
  249 + }
  250 + return true;
  251 + }
  252 +
  253 +
  254 + public function output($message)
  255 + {
  256 + echo date('Y-m-d H:i:s') . ' | ' . $message . PHP_EOL;
  257 + }
  258 +}
@@ -10,6 +10,7 @@ namespace App\Console\Commands\Inquiry; @@ -10,6 +10,7 @@ namespace App\Console\Commands\Inquiry;
10 use App\Helper\Common; 10 use App\Helper\Common;
11 use App\Helper\Gpt; 11 use App\Helper\Gpt;
12 use App\Helper\Translate; 12 use App\Helper\Translate;
  13 +use App\Helper\Validate;
13 use App\Models\Ai\AiCommand; 14 use App\Models\Ai\AiCommand;
14 use App\Models\Inquiry\ReInquiryConfig; 15 use App\Models\Inquiry\ReInquiryConfig;
15 use App\Models\Inquiry\ReInquiryDetail; 16 use App\Models\Inquiry\ReInquiryDetail;
@@ -329,7 +330,10 @@ class RelayInquiry extends Command @@ -329,7 +330,10 @@ class RelayInquiry extends Command
329 $val->save(); 330 $val->save();
330 continue; 331 continue;
331 } 332 }
332 - 333 + //验证手机号 无效 号码不推送
  334 + if(!Validate::phone($val->phone)){
  335 + $val->phone = '';
  336 + }
333 try { 337 try {
334 $res = false; 338 $res = false;
335 foreach ($ad_task as $task){ 339 foreach ($ad_task as $task){
@@ -357,10 +361,10 @@ class RelayInquiry extends Command @@ -357,10 +361,10 @@ class RelayInquiry extends Command
357 //FB询盘的全局过滤规则 361 //FB询盘的全局过滤规则
358 $fb_config = ReInquiryConfig::getDefaultConfigCache(ReInquiryConfig::TYPE_FILTER_WORDS); 362 $fb_config = ReInquiryConfig::getDefaultConfigCache(ReInquiryConfig::TYPE_FILTER_WORDS);
359 363
360 - $fb_config['filter_contents'] = array_filter(explode("\r\n", $fb_config['filter_contents']?:''));  
361 - $fb_config['filter_emails'] = array_filter(explode("\r\n", $fb_config['filter_emails']?:''));  
362 - $fb_config['filter_mobiles'] = array_filter(explode("\r\n", $fb_config['filter_mobiles']?:''));  
363 - $fb_config['filter_names'] = array_filter(explode("\r\n", $fb_config['filter_names']?:'')); 364 + $fb_config['filter_contents'] = array_filter(explode("\r\n", $fb_config['filter_contents']??''));
  365 + $fb_config['filter_emails'] = array_filter(explode("\r\n", $fb_config['filter_emails']??''));
  366 + $fb_config['filter_mobiles'] = array_filter(explode("\r\n", $fb_config['filter_mobiles']??''));
  367 + $fb_config['filter_names'] = array_filter(explode("\r\n", $fb_config['filter_names']??''));
364 368
365 $config['filter_contents'] = array_unique(array_merge($fb_config['filter_contents'],$config['filter_contents'])); 369 $config['filter_contents'] = array_unique(array_merge($fb_config['filter_contents'],$config['filter_contents']));
366 $config['filter_emails'] = array_unique(array_merge($fb_config['filter_emails'],$config['filter_emails'])); 370 $config['filter_emails'] = array_unique(array_merge($fb_config['filter_emails'],$config['filter_emails']));
@@ -382,6 +386,10 @@ class RelayInquiry extends Command @@ -382,6 +386,10 @@ class RelayInquiry extends Command
382 return '过滤邮箱:' . $filter_email; 386 return '过滤邮箱:' . $filter_email;
383 } 387 }
384 } 388 }
  389 + //邮箱有效性
  390 + if(!Validate::email($data['email'])){
  391 + return '邮箱无效';
  392 + }
385 } 393 }
386 //过滤电话 394 //过滤电话
387 if(!empty($data['phone']) && !empty($config['filter_mobiles'])){ 395 if(!empty($data['phone']) && !empty($config['filter_mobiles'])){
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: akun
  5 + * Date: 2025/02/24
  6 + * Time: 14:14
  7 + */
  8 +
  9 +namespace App\Console\Commands\Inquiry;
  10 +
  11 +use App\Helper\Translate;
  12 +use App\Models\Inquiry\InquiryRelayDetail;
  13 +use App\Models\Inquiry\InquiryRelayDetailLog;
  14 +use Illuminate\Console\Command;
  15 +use Illuminate\Support\Arr;
  16 +use Illuminate\Support\Facades\Http;
  17 +use Illuminate\Support\Str;
  18 +
  19 +/**
  20 + * Class RelayInquiry
  21 + * @package App\Console\Commands\Inquiry
  22 + */
  23 +class RelayInquiryForward extends Command
  24 +{
  25 + /**
  26 + * The name and signature of the console command.
  27 + *
  28 + * @var string
  29 + */
  30 + protected $signature = 'relay_inquiry_forward';
  31 +
  32 + /**
  33 + * The console command description.
  34 + *
  35 + * @var string
  36 + */
  37 + protected $description = '转发询盘:拆分转发数据';
  38 +
  39 + /**
  40 + * Create a new command instance.
  41 + *
  42 + * @return void
  43 + */
  44 + public function __construct()
  45 + {
  46 + parent::__construct();
  47 + }
  48 +
  49 + /**
  50 + * 模拟访问来源占比
  51 + * @var array
  52 + */
  53 + protected $lyzb = [
  54 + 'https://www.google.com/' => 630,
  55 + 'http://www.google.com/' => 30,
  56 + 'http://www.bing.com/' => 20,
  57 + 'https://www.bing.com/' => 5,
  58 + 'https://www.youtube.com/' => 5,
  59 + 'https://search.yahoo.com/' => 5,
  60 + 'https://www.facebook.com/' => 5,
  61 + ];
  62 +
  63 + /**
  64 + * 俄语站 模拟访问来源占比
  65 + * @var array
  66 + */
  67 + protected $eylyzb = [
  68 + 'https://www.yandex.com/' => 630,
  69 + 'https://www.google.com/' => 30,
  70 + 'http://www.google.com/' => 30,
  71 + 'http://www.bing.com/' => 20,
  72 + 'https://www.bing.com/' => 5,
  73 + 'https://www.youtube.com/' => 5,
  74 + 'https://search.yahoo.com/' => 5,
  75 + 'https://www.facebook.com/' => 5,
  76 + ];
  77 +
  78 + /**
  79 + * PC端访问头信息
  80 + * @var array
  81 + */
  82 + protected $pc_ua = [
  83 + 0 => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11',
  84 + 1 => 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36',
  85 + 2 => 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1'
  86 + ];
  87 +
  88 + /**
  89 + * 移动端访问头信息
  90 + * @var array
  91 + */
  92 + protected $mobile_ua = [
  93 + 0 => 'Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko; googleweblight) Chrome/38.0.1025.166 Mobile Safari/535.19',
  94 + ];
  95 +
  96 + /**
  97 + * google域名后缀
  98 + * @var string[]
  99 + */
  100 + protected $suffix = [
  101 + 'co.jp' => '日本',
  102 + 'com.tr' => '土耳其',
  103 + 'nl' => '荷兰',
  104 + 'ru' => '俄罗斯',
  105 + 'fr' => '法国',
  106 + 'co.kr' => '韩国',
  107 + 'fi' => '芬兰',
  108 + 'be' => '比利时',
  109 + 'lt' => '立陶宛',
  110 + 'es' => '西班牙',
  111 + 'it' => '意大利',
  112 + 'com.au' => '澳大利亚',
  113 + 'no' => '挪威',
  114 + 'al' => '阿尔巴尼亚',
  115 + 'pt' => '葡萄牙',
  116 + 'lv' => '拉脱维亚',
  117 + 'hu' => '匈牙利',
  118 + 'cz' => '捷克',
  119 + 'de' => '德国',
  120 + 'ca' => '加拿大',
  121 + 'co.in' => '印度',
  122 + 'co.uk' => '英国',
  123 + 'com.vn' => '越南',
  124 + 'com.br' => '巴西',
  125 + 'co.il' => '以色列',
  126 + 'pl' => '波兰',
  127 + 'com.eg' => '埃及',
  128 + 'co.th' => '泰国',
  129 + 'sk' => '斯洛伐克',
  130 + 'ro' => '罗马尼亚',
  131 + 'com.mx' => '墨西哥',
  132 + 'com.my' => '马来西亚',
  133 + 'com.pk' => '巴基斯坦',
  134 + 'co.nz' => '新西兰',
  135 + 'co.za' => '南非',
  136 + 'com.ar' => '阿根廷',
  137 + 'com.kw' => '科威特',
  138 + 'com.sg' => '新加坡',
  139 + 'com.co' => '哥伦比亚',
  140 + 'co.id' => '印度尼西亚',
  141 + 'gr' => '希腊',
  142 + 'bg' => '保加利亚',
  143 + 'mn' => '蒙古',
  144 + 'dk' => '丹麦',
  145 + 'com.sa' => '沙特阿拉伯',
  146 + 'com.pe' => '秘鲁',
  147 + 'com.ph' => '菲律宾',
  148 + 'com.ua' => '乌克兰',
  149 + 'ge' => '格鲁吉亚',
  150 + 'ae' => '阿拉伯联合酋长国',
  151 + 'tn' => '突尼斯',
  152 + ];
  153 +
  154 + protected $otherzb = [700, 300]; //模拟访问来源占比 (非美国) google.com|google.其他后缀
  155 +
  156 +
  157 + public function handle()
  158 + {
  159 + while (true) {
  160 + $this->startInquiryDetail();
  161 + }
  162 + }
  163 +
  164 +
  165 + public function startInquiryDetail()
  166 + {
  167 + $inquiry_detail = InquiryRelayDetail::where('status', InquiryRelayDetail::STATUS_INIT)->orderBy('start_at', 'asc')->orderBy('id', 'asc')->first();
  168 + if (!$inquiry_detail) {
  169 + //所有任务执行完成
  170 + sleep(60);
  171 + return true;
  172 + }
  173 +
  174 + try {
  175 + $this->output('询盘详情ID:' . $inquiry_detail['id'] . ',开始拆分转发数据');
  176 +
  177 + $inquiry_detail->status = InquiryRelayDetail::STATUS_PEND;//拆分中
  178 + $inquiry_detail->save();
  179 +
  180 + //先补全询盘详情数据
  181 + $urls = $this->completeDetail($inquiry_detail);
  182 +
  183 + //再拆分转发数据
  184 + $this->relayDetail($inquiry_detail['id'], $urls, $inquiry_detail['start_at']);
  185 +
  186 + $inquiry_detail->status = InquiryRelayDetail::STATUS_SUCCESS;
  187 + $inquiry_detail->save();
  188 +
  189 + $this->output('询盘详情ID:' . $inquiry_detail['id'] . ',拆分转发数据结束');
  190 + } catch (\Exception $e) {
  191 + $inquiry_detail->status = InquiryRelayDetail::STATUS_FAIL;
  192 + $inquiry_detail->remark = mb_substr($e->getMessage(), 0, 200);;
  193 + $inquiry_detail->save();
  194 + $this->output('询盘详情ID:' . $inquiry_detail['id'] . ',拆分转发数据失败,原因:' . $e->getMessage());
  195 + }
  196 +
  197 + return true;
  198 + }
  199 +
  200 + /**
  201 + * 补全询盘详情数据
  202 + * @param $inquiry_detail
  203 + * @return array
  204 + * @author Akun
  205 + * @date 2025/02/25 17:19
  206 + */
  207 + public function completeDetail($inquiry_detail)
  208 + {
  209 + //visit urls
  210 + $visit_urls = $this->getUrls($inquiry_detail['is_v6'], $inquiry_detail['website'], $inquiry_detail['email']);
  211 + $inquiry_url = json_decode($inquiry_detail['urls'], true);
  212 + $urls = array_merge($visit_urls, $inquiry_url);
  213 +
  214 + //lang
  215 + if (is_numeric($inquiry_detail['message'])) { //数字会被识别为中文
  216 + $lang = 'en';
  217 + } else {
  218 + $translateSl = Translate::translateSl($inquiry_detail['message']);
  219 + $lang = $translateSl['texts']['sl'] ?? 'en';
  220 + }
  221 +
  222 + // 客户端 头信息 来源
  223 + $device_port = $inquiry_detail['email'] ? '1' : '2'; //1 pc 2移动端
  224 + $user_agent = $inquiry_detail['email'] ? Arr::random($this->pc_ua) : Arr::random($this->mobile_ua);
  225 + $referrer = $this->getReferer($inquiry_detail['country'], $lang);
  226 +
  227 + $inquiry_detail->device_port = $device_port;
  228 + $inquiry_detail->user_agent = $user_agent;
  229 + $inquiry_detail->referrer = $referrer;
  230 + $inquiry_detail->urls = json_encode($urls);
  231 + $inquiry_detail->num = count($urls) + 1;
  232 + $inquiry_detail->save();
  233 +
  234 + return $urls;
  235 + }
  236 +
  237 + /**
  238 + * 创建转发详情
  239 + * @param $task_id
  240 + * @param $urls
  241 + * @param $start_at
  242 + * @author Akun
  243 + * @date 2025/02/25 15:41
  244 + */
  245 + public function relayDetail($task_id, $urls, $start_at)
  246 + {
  247 + $pre = 0;
  248 + $seconds = rand(300, 7200); // 开始时间 从5分钟-2小时后开始
  249 + foreach ($urls as $k => $v) {
  250 + $pre++;
  251 + $seconds += rand(5, 60);
  252 + InquiryRelayDetailLog::createInquiryLog($task_id, InquiryRelayDetailLog::TYPE_VISIT, $pre, $v, date('Y-m-d H:i:s', strtotime($start_at) + $seconds));
  253 + // 最后一次访问询盘 加上询盘
  254 + if ($k + 1 >= count($urls)) {
  255 + $seconds += rand(30, 120);
  256 + $pre++;
  257 + InquiryRelayDetailLog::createInquiryLog($task_id, InquiryRelayDetailLog::TYPE_INQUIRY, $pre, $v, date('Y-m-d H:i:s', strtotime($start_at) + $seconds));
  258 + }
  259 + }
  260 + }
  261 +
  262 + /**
  263 + * 获取访问url
  264 + * @param $is_v6
  265 + * @param $website
  266 + * @param $email
  267 + * @return array
  268 + * @author Akun
  269 + * @date 2025/02/25 15:45
  270 + */
  271 + public function getUrls($is_v6, $website, $email)
  272 + {
  273 + $domain = 'https://' . $website . '/';
  274 + // v6:有邮箱推送主站,没有邮箱推送AMP站;v5:仅推送有邮箱到主站
  275 + if ($is_v6) {
  276 + // 获取访问明细和着陆页
  277 + $product_url = $this->getLinksFromSitemap($domain . 'product_sitemap.xml');
  278 + $product_cate_url = $this->getLinksFromSitemap($domain . 'product_category_sitemap.xml');
  279 + $keywords_url = $this->getLinksFromSitemap($domain . 'product_keywords_sitemap.xml');
  280 + $page_url = $this->getLinksFromSitemap($domain . 'page_sitemap.xml');
  281 + } else {
  282 + if ($email) {
  283 + //通过sitemap拿访问页面
  284 + $product_url = $this->getLinksFromSitemap($domain . 'sitemap_post.xml');
  285 + $product_cate_url = $this->getLinksFromSitemap($domain . 'sitemap_category.xml');
  286 + $keywords_url = $this->getLinksFromSitemap($domain . 'sitemap_post_tag.xml');
  287 + $page_url = $this->getLinksFromSitemap($domain . 'sitemap_page.xml');
  288 + } else {
  289 + //m站先就往contact-us着陆
  290 + $product_url = $product_cate_url = $keywords_url = [];
  291 + $page_url = [$domain . 'contact-us/'];
  292 + }
  293 + }
  294 +
  295 + // 所有可用url
  296 + $urls = [];
  297 + //入口url 首页30%,单页10%,聚合页60%
  298 + $type = getRandByRatio([30, 10, 60]);
  299 + $inlet = $domain;
  300 + $type == 1 && $inlet = $page_url ? Arr::random($page_url) : $domain;
  301 + $type == 2 && $inlet = $keywords_url ? Arr::random($keywords_url) : $domain;
  302 + $urls[] = $inlet;
  303 + $all_urls = array_merge($urls, $product_url, $product_cate_url, $keywords_url, $page_url);
  304 +
  305 + if (count($all_urls) > 1) {
  306 + // 随机访问1-6个页面
  307 + $deep = rand(1, 6);
  308 + $visit_urls = Arr::random($all_urls, $deep > count($all_urls) ? count($all_urls) : $deep);
  309 + $urls = array_merge($urls, $visit_urls);
  310 + }
  311 +
  312 + return $urls;
  313 + }
  314 +
  315 + /**
  316 + * 获取头信息
  317 + * @param $ip_area
  318 + * @param $lang
  319 + * @return int|string
  320 + */
  321 + public function getReferer($ip_area, $lang)
  322 + {
  323 + if ($lang == 'ru') {
  324 + return $this->get_rand($this->eylyzb);
  325 + }
  326 + if ($ip_area == '美国') {
  327 + $referer = $this->get_rand($this->lyzb);
  328 + } else {
  329 + $referer = 'https://www.google.com/';
  330 + $suffix = array_search($ip_area, $this->suffix);
  331 + if ($suffix) {
  332 + $res_qtzb = $this->get_rand($this->otherzb);
  333 + if ($res_qtzb == 1) {
  334 + $referer = 'https://www.google.' . $suffix . '/';
  335 + }
  336 + }
  337 + }
  338 + return $referer;
  339 + }
  340 +
  341 + /**
  342 + * 概率算法
  343 + * @param $proArr
  344 + * @return int|string
  345 + */
  346 + protected function get_rand($proArr)
  347 + {
  348 + $result = '';
  349 + $proSum = array_sum($proArr);
  350 + foreach ($proArr as $key => $proCur) {
  351 + $randNum = mt_rand(1, $proSum);
  352 + if ($randNum <= $proCur) {
  353 + $result = $key;
  354 + break;
  355 + } else {
  356 + $proSum -= $proCur;
  357 + }
  358 + }
  359 + unset ($proArr);
  360 + return $result;
  361 + }
  362 +
  363 + /**
  364 + * 获取sitemap内容
  365 + * @param $sitemapUrl
  366 + * @return array|mixed
  367 + */
  368 + function getLinksFromSitemap($sitemapUrl)
  369 + {
  370 + try {
  371 + //忽略cert证书 先下载到临时文件
  372 + $result = Http::withoutVerifying()->get($sitemapUrl)->body();
  373 + $tempFilePath = tempnam(sys_get_temp_dir(), 'remote_file_');
  374 + file_put_contents($tempFilePath, $result);
  375 + $xml = simplexml_load_file($tempFilePath);
  376 + $links = [];
  377 + foreach ($xml->url as $url) {
  378 + $loc = (string)$url->loc;
  379 + if (!Str::contains($loc, ['404', 'thanks', 'test'])) {
  380 + $links[] = $loc;
  381 + }
  382 + }
  383 + //随机取20个
  384 + $total = count($links);
  385 + return Arr::random($links, $total > 20 ? 20 : $total);
  386 + } catch (\Exception $e) {
  387 + echo date('Y-m-d H:i:s') . 'sitemap获取失败:' . $e->getMessage() . PHP_EOL;
  388 + return $links ?? [];
  389 + }
  390 + }
  391 +
  392 + public function output($message)
  393 + {
  394 + echo date('Y-m-d H:i:s') . ' | ' . $message . PHP_EOL;
  395 + }
  396 +}
@@ -53,7 +53,7 @@ class SyncInquiryProject extends Command @@ -53,7 +53,7 @@ class SyncInquiryProject extends Command
53 53
54 /** 54 /**
55 * 同步优化项目及路由 55 * 同步优化项目及路由
56 - * TODO 同步v4 v5 v6项目以及路由, 删除过期项目及路由 56 + * 同步v4 v5 v6项目以及路由, 删除过期项目及路由
57 * @return bool 57 * @return bool
58 */ 58 */
59 public function handle() 59 public function handle()
@@ -133,7 +133,6 @@ class SyncInquiryProject extends Command @@ -133,7 +133,6 @@ class SyncInquiryProject extends Command
133 $query->orwhere('gl_project_online_check.qa_status', OnlineCheck::STATUS_ONLINE_TRUE) 133 $query->orwhere('gl_project_online_check.qa_status', OnlineCheck::STATUS_ONLINE_TRUE)
134 ->orwhere('gl_project.is_upgrade', Project::IS_UPGRADE_TRUE); 134 ->orwhere('gl_project.is_upgrade', Project::IS_UPGRADE_TRUE);
135 }) 135 })
136 - ->limit(5)  
137 ->get(['gl_project.id', 'gl_project.title', 'gl_project.level', 'gl_project.channel']); 136 ->get(['gl_project.id', 'gl_project.title', 'gl_project.level', 'gl_project.channel']);
138 // 获取所有项目域名 137 // 获取所有项目域名
139 $domains = DomainInfo::whereIn('project_id', $project->pluck('id')->toArray())->pluck('domain', 'project_id')->toArray(); 138 $domains = DomainInfo::whereIn('project_id', $project->pluck('id')->toArray())->pluck('domain', 'project_id')->toArray();
@@ -142,7 +141,7 @@ class SyncInquiryProject extends Command @@ -142,7 +141,7 @@ class SyncInquiryProject extends Command
142 // 过滤暂停优化项目, 映射类型2, model没有定义常量 141 // 过滤暂停优化项目, 映射类型2, model没有定义常量
143 if (in_array(2, $val->level)) 142 if (in_array(2, $val->level))
144 continue; 143 continue;
145 - $project = InquiryProject::saveProject($date,InquiryProject::VERSION_SIX, $val->id, $val->title, $val->channel['channel_id'], $domains[$val->id]); 144 + $project = InquiryProject::saveProject($date,InquiryProject::VERSION_SIX, $val->id, $val->title, $val->channel['channel_id'], 'https://'.$domains[$val->id].'/');
146 $this->pushTask($project->id); 145 $this->pushTask($project->id);
147 } 146 }
148 147
@@ -190,4 +189,4 @@ class SyncInquiryProject extends Command @@ -190,4 +189,4 @@ class SyncInquiryProject extends Command
190 file_put_contents(storage_path('logs/zhl/output') . date('Y-m-d') . '.log', $message, FILE_APPEND); 189 file_put_contents(storage_path('logs/zhl/output') . date('Y-m-d') . '.log', $message, FILE_APPEND);
191 return true; 190 return true;
192 } 191 }
193 -}  
  192 +}
@@ -53,7 +53,7 @@ class SyncInquiryProjectRoute extends Command @@ -53,7 +53,7 @@ class SyncInquiryProjectRoute extends Command
53 53
54 /** 54 /**
55 * 同步优化项目及路由 55 * 同步优化项目及路由
56 - * TODO 同步v4 v5 v6项目以及路由, 删除过期项目及路由 56 + * 同步v4 v5 v6项目以及路由, 删除过期项目及路由
57 * @return bool 57 * @return bool
58 */ 58 */
59 public function handle() 59 public function handle()
@@ -130,7 +130,7 @@ class SyncInquiryProjectRoute extends Command @@ -130,7 +130,7 @@ class SyncInquiryProjectRoute extends Command
130 echo '同步项目ID:' . $task->id . PHP_EOL; 130 echo '同步项目ID:' . $task->id . PHP_EOL;
131 $date = intval(date('Ymd')); 131 $date = intval(date('Ymd'));
132 ProjectServer::useProject($task->primary_id); 132 ProjectServer::useProject($task->primary_id);
133 - // TODO 产品分类标题、路由, 产品标题、路由, 同步到路由表 133 + // 产品分类标题、路由, 产品标题、路由, 同步到路由表
134 $category = Category::where('status', Category::STATUS_ACTIVE)->get(['title', 'route']); 134 $category = Category::where('status', Category::STATUS_ACTIVE)->get(['title', 'route']);
135 foreach ($category as $key=>$val) { 135 foreach ($category as $key=>$val) {
136 InquiryProjectRoute::saveProjectRoute($task->id, $val->title, $val->route, $date); 136 InquiryProjectRoute::saveProjectRoute($task->id, $val->title, $val->route, $date);
@@ -181,4 +181,4 @@ class SyncInquiryProjectRoute extends Command @@ -181,4 +181,4 @@ class SyncInquiryProjectRoute extends Command
181 file_put_contents(storage_path('logs/zhl/output') . date('Y-m-d') . '.log', $message, FILE_APPEND); 181 file_put_contents(storage_path('logs/zhl/output') . date('Y-m-d') . '.log', $message, FILE_APPEND);
182 return true; 182 return true;
183 } 183 }
184 -}  
  184 +}
  1 +<?php
  2 +
  3 +
  4 +namespace App\Helper;
  5 +
  6 +use App\Utils\HttpUtils;
  7 +use GuzzleHttp\Exception\GuzzleException;
  8 +
  9 +
  10 +/**
  11 + * Class Validate
  12 + * @package App\Helper
  13 + * @author zbj
  14 + * @date 2025/2/27
  15 + */
  16 +class Validate
  17 +{
  18 + /**
  19 + * 邮箱有效性
  20 + * @param $email
  21 + * @return bool
  22 + * @author zbj
  23 + * @date 2025/2/27
  24 + */
  25 + public static function email($email)
  26 + {
  27 + try {
  28 + $res = HttpUtils::get('https://fob.ai.cc/api/check_email', ['email' => $email]);
  29 + $res = Arr::s2a($res);
  30 + $status = $res['data']['status'] ?? 0;
  31 + } catch (\Exception | GuzzleException $e) {
  32 + $status = 0;
  33 + }
  34 + return !($status == 4);
  35 + }
  36 +
  37 + /**
  38 + * 邮箱有效性
  39 + * @param $email
  40 + * @return bool
  41 + * @author zbj
  42 + * @date 2025/2/27
  43 + */
  44 + public static function phone($email)
  45 + {
  46 + try {
  47 + $res = HttpUtils::get('https://fob.ai.cc/api/check_phone', ['phone' => $email]);
  48 + $res = Arr::s2a($res);
  49 + $status = $res['data']['valid_status'] ?? 0;
  50 + } catch (\Exception | GuzzleException $e) {
  51 + $status = 0;
  52 + }
  53 + return !($status == 2);
  54 + }
  55 +}
  1 +<?php
  2 +
  3 +namespace App\Http\Controllers\Aside\Optimize;
  4 +
  5 +use App\Enums\Common\Code;
  6 +use App\Http\Controllers\Aside\BaseController;
  7 +use App\Http\Logic\Aside\Optimize\InquiryForwardLogic;
  8 +use Illuminate\Support\Facades\DB;
  9 +
  10 +class InquiryForwardController extends BaseController
  11 +{
  12 + /**
  13 + * 获取询信息发列表
  14 + * @param InquiryForwardLogic $inquiryForwardLogic
  15 + * @author Akun
  16 + * @date 2025/02/21 10:55
  17 + */
  18 + public function lists(InquiryForwardLogic $inquiryForwardLogic)
  19 + {
  20 + if (isset($this->param['url'])) {
  21 + $this->map['url'] = ['like', '%' . $this->map['url'] . '%'];
  22 + }
  23 + if (isset($this->param['email'])) {
  24 + $this->map['email'] = ['like', '%' . $this->map['email'] . '%'];
  25 + }
  26 + if (isset($this->param['url_title'])) {
  27 + $this->map['url_title'] = ['like', '%' . $this->map['url_title'] . '%'];
  28 + }
  29 + if (isset($this->param['url_keyword'])) {
  30 + $this->map['url_keyword'] = ['like', '%' . $this->map['url_keyword'] . '%'];
  31 + }
  32 + $lists = $inquiryForwardLogic->getInquiryLists($this->map, $this->page, $this->row, $this->order);
  33 + $this->response('success', Code::SUCCESS, $lists);
  34 + }
  35 +
  36 + /**
  37 + * 获取询盘类型
  38 + * @param InquiryForwardLogic $inquiryForwardLogic
  39 + * @author Akun
  40 + * @date 2025/02/21 11:20
  41 + */
  42 + public function getInquiryType(InquiryForwardLogic $inquiryForwardLogic)
  43 + {
  44 + $lists = $inquiryForwardLogic->getType();
  45 + $this->response('success', Code::SUCCESS, $lists);
  46 + }
  47 +
  48 + /**
  49 + * 手动转发询盘
  50 + * @param InquiryForwardLogic $inquiryForwardLogic
  51 + * @throws \App\Exceptions\AsideGlobalException
  52 + * @throws \App\Exceptions\BsideGlobalException
  53 + * @author Akun
  54 + * @date 2025/02/21 14:54
  55 + */
  56 + public function forwardInquiry(InquiryForwardLogic $inquiryForwardLogic)
  57 + {
  58 + $this->validationParam();
  59 + $inquiryForwardLogic->inquiryForward();
  60 + $this->response('success');
  61 + }
  62 +
  63 + /**
  64 + * 手动转发询盘:参数验证
  65 + * @author Akun
  66 + * @date 2025/02/21 14:19
  67 + */
  68 + public function validationParam()
  69 + {
  70 + $this->request->validate([
  71 + 'id' => 'required',//ID
  72 + 'name' => 'required',//名称
  73 + 'email' => 'required',//邮箱
  74 + 'phone' => 'required',//电话号码
  75 + 'ip' => 'required',//ip
  76 + 'forward_url' => 'required',//转发网址
  77 + 'message' => 'required',//发送内容
  78 + 'inquiry_diff' => 'required',//发送时区
  79 + 'inquiry_date' => 'required',//发送时间
  80 + ], [
  81 + 'id.required' => 'ID不能为空',
  82 + 'name.required' => '名称不能为空',
  83 + 'email.required' => '邮箱不能为空',
  84 + 'phone.required' => '电话号码不能为空',
  85 + 'ip.required' => 'ip不能为空',
  86 + 'forward_url.required' => '转发网址不能为空',
  87 + 'message.required' => '内容不能为空',
  88 + 'inquiry_diff.required' => '发送时区不能为空',
  89 + 'inquiry_date.required' => '发送时间不能为空',
  90 + ]);
  91 + }
  92 +
  93 + /**
  94 + * 根据国家获取随机ip
  95 + * @param InquiryForwardLogic $inquiryForwardLogic
  96 + * @throws \App\Exceptions\AsideGlobalException
  97 + * @throws \App\Exceptions\BsideGlobalException
  98 + * @author Akun
  99 + * @date 2025/02/26 15:50
  100 + */
  101 + public function getInquiryIp(InquiryForwardLogic $inquiryForwardLogic)
  102 + {
  103 + $this->request->validate([
  104 + 'country' => 'required',
  105 + ], [
  106 + 'country.required' => '国家不能为空',
  107 + ]);
  108 +
  109 + $data = $inquiryForwardLogic->getIp();
  110 + $this->response('success', Code::SUCCESS, $data);
  111 + }
  112 +
  113 + /**
  114 + * 关键词查询项目着陆页
  115 + * @param InquiryForwardLogic $inquiryForwardLogic
  116 + * @author Akun
  117 + * @date 2025/02/26 17:12
  118 + */
  119 + public function searchInquiryKeywords(InquiryForwardLogic $inquiryForwardLogic)
  120 + {
  121 + $this->request->validate([
  122 + 'keywords' => 'required',
  123 + 'type' => 'required',
  124 + ], [
  125 + 'keywords.required' => '关键词不能为空',
  126 + 'type.required' => '搜索类型不能为空',
  127 + ]);
  128 +
  129 + $lists = $inquiryForwardLogic->searchKeywords();
  130 + $this->response('success', Code::SUCCESS, $lists);
  131 + }
  132 +
  133 + /**
  134 + * AI重写询盘文案
  135 + * @param InquiryForwardLogic $inquiryForwardLogic
  136 + * @throws \App\Exceptions\AsideGlobalException
  137 + * @throws \App\Exceptions\BsideGlobalException
  138 + * @author Akun
  139 + * @date 2025/02/27 10:40
  140 + */
  141 + public function aiRewriteInquiry(InquiryForwardLogic $inquiryForwardLogic)
  142 + {
  143 + $this->request->validate([
  144 + 'message' => 'required',
  145 + ], [
  146 + 'message.required' => '需要重写的文案不能为空',
  147 + ]);
  148 +
  149 + $data = $inquiryForwardLogic->aiRewrite();
  150 + $this->response('success', Code::SUCCESS, $data);
  151 + }
  152 +}
  1 +<?php
  2 +
  3 +namespace App\Http\Logic\Aside\Optimize;
  4 +
  5 +use App\Helper\Common;
  6 +use App\Helper\Gpt;
  7 +use App\Helper\Translate;
  8 +use App\Http\Logic\Aside\BaseLogic;
  9 +use App\Models\Ai\AiCommand;
  10 +use App\Models\Inquiry\InquiryInfo;
  11 +use App\Models\Inquiry\InquiryProject;
  12 +use App\Models\Inquiry\InquiryProjectRoute;
  13 +use App\Models\Inquiry\InquiryRelayDetail;
  14 +use Illuminate\Support\Arr;
  15 +use Illuminate\Support\Facades\DB;
  16 +use Illuminate\Support\Facades\Log;
  17 +use Illuminate\Support\Str;
  18 +
  19 +/**
  20 + * @remark :询盘中心
  21 + * @class :InquiryForwardLogic.php
  22 + * @author :akun
  23 + * @time :2025/2/21 11:17
  24 + */
  25 +class InquiryForwardLogic extends BaseLogic
  26 +{
  27 +
  28 + public function __construct()
  29 + {
  30 + parent::__construct();
  31 + $this->param = $this->requestAll;
  32 + $this->model = new InquiryInfo();
  33 + }
  34 +
  35 + /**
  36 + * 获取类型
  37 + * @return array
  38 + * @author Akun
  39 + * @date 2025/02/21 11:19
  40 + */
  41 + public function getType()
  42 + {
  43 + return $this->success($this->model->typeMap());
  44 + }
  45 +
  46 + /**
  47 + * 获取列表
  48 + * @param $map
  49 + * @param $page
  50 + * @param $row
  51 + * @param string $order
  52 + * @param string[] $filed
  53 + * @return array
  54 + * @author Akun
  55 + * @date 2025/02/21 11:19
  56 + */
  57 + public function getInquiryLists($map, $page, $row, $order = 'id', $filed = ['*'])
  58 + {
  59 + $lists = $this->model->lists($map, $page, $row, $order, $filed);
  60 + return $this->success($lists);
  61 + }
  62 +
  63 + /**
  64 + * 转发询盘
  65 + * @return array
  66 + * @throws \App\Exceptions\AsideGlobalException
  67 + * @throws \App\Exceptions\BsideGlobalException
  68 + * @author Akun
  69 + * @date 2025/02/21 14:54
  70 + */
  71 + public function inquiryForward()
  72 + {
  73 + $info = $this->model->read(['id' => $this->param['id']]);
  74 + if ($info === false) {
  75 + $this->fail('获取询盘详情失败');
  76 + }
  77 + if ($info['status'] != InquiryInfo::STATUS_INIT) {
  78 + $this->fail('当前询盘状态无法转发');
  79 + }
  80 +
  81 + DB::beginTransaction();
  82 + try {
  83 + $num = 0;
  84 + $now = date('Y-m-d H:i:s');
  85 + foreach ($this->param['forward_url'] as $url) {
  86 + $domain_array = parse_url($url);
  87 + $website = $domain_array['host'] ?? '';
  88 + if (!$website) {
  89 + continue;
  90 + }
  91 +
  92 + //获取站点对应项目版本
  93 + $project_version = InquiryProject::select(['version'])->where('domain', 'like', '%' . $website . '%')->first();
  94 + if (!$project_version) {
  95 + continue;
  96 + }
  97 + $is_v6 = $project_version->version == 6 ? 1 : 0;
  98 +
  99 +
  100 + //计算发送时间
  101 + if ($this->param['inquiry_diff'] > 0) {
  102 + $start_at = date('Y-m-d H:i:s', strtotime($this->param['inquiry_date'] . ' -' . $this->param['inquiry_diff'] . ' hours'));
  103 + } elseif ($this->param['inquiry_diff'] < 0) {
  104 + $start_at = date('Y-m-d H:i:s', strtotime($this->param['inquiry_date'] . ' +' . abs($this->param['inquiry_diff']) . ' hours'));
  105 + } else {
  106 + $start_at = $this->param['inquiry_date'];
  107 + }
  108 + if ($start_at < $now) {
  109 + $start_at = $now;
  110 + }
  111 +
  112 + InquiryRelayDetail::createInquiry($info['id'], $website, $info['country'], $this->param['ip'], $this->param['name'], $this->param['email'], $this->param['phone'], $this->param['message'], $is_v6, json_encode([$url]), $start_at);
  113 +
  114 + $num += 1;
  115 + }
  116 +
  117 + //更改询盘状态及转发数量
  118 + $this->model->edit(['status' => 1, 'num' => $num], ['id' => $this->param['id']]);
  119 +
  120 + DB::commit();
  121 + } catch (\Exception $e) {
  122 + DB::rollback();
  123 +
  124 + Log::error('inquiry_forward error:' . $e->getMessage());
  125 + $this->fail('转发询盘失败');
  126 + }
  127 +
  128 + return $this->success();
  129 + }
  130 +
  131 + /**
  132 + * 获取随机ip
  133 + * @return array
  134 + * @throws \App\Exceptions\AsideGlobalException
  135 + * @throws \App\Exceptions\BsideGlobalException
  136 + * @author Akun
  137 + * @date 2025/02/26 15:50
  138 + */
  139 + public function getIp()
  140 + {
  141 + $ip = DB::table('gl_xunpan_ipdata')->where('ip_area', $this->param['country'])->inRandomOrder()->value('ip');
  142 + if (!$ip) {
  143 + $this->fail('当前国家无法获取随机ip');
  144 + }
  145 +
  146 + return $this->success(['ip' => $ip]);
  147 + }
  148 +
  149 + /**
  150 + * 关键词查询项目着陆页
  151 + * @return int|mixed
  152 + * @author Akun
  153 + * @date 2025/02/26 17:13
  154 + */
  155 + public function searchKeywords()
  156 + {
  157 + $num = $this->param['num'] ?? 3;
  158 +
  159 + $model = new InquiryProjectRoute();
  160 + if ($this->param['type'] == 1) {
  161 + //使用全文索引搜索
  162 + $routeQuery = $model->select(['project_id', 'route'])->whereRaw("MATCH(title) AGAINST(? IN BOOLEAN MODE)", [$this->param['keywords']]);
  163 + } else {
  164 + //使用like查询
  165 + $routeQuery = $model->select(['project_id', 'route'])->where('title', 'like', '%' . $this->param['keywords'] . '%');
  166 + }
  167 +
  168 + $re_route = $routeQuery->inRandomOrder()->take(100)->get()->toArray();
  169 +
  170 + $lists = [];
  171 + if (count($re_route) > 0) {
  172 + //根据项目id查询项目,并根据询盘量排序
  173 + $project_ids = array_column($re_route, 'project_id');
  174 + $re_project = InquiryProject::select(['id', 'project', 'channel', 'domain'])->whereIn('id', $project_ids)->orderBy('recent_inquiry', 'asc')->get();
  175 +
  176 + if ($re_project->count() > 0) {
  177 + //根据代理商去重
  178 + $channel = [];
  179 + foreach ($re_project as $vp) {
  180 + $vp_channel = explode(',', $vp->channel);
  181 + $has_channel = 0;
  182 + foreach ($vp_channel as $vpc) {
  183 + if (in_array($vpc, $channel)) {
  184 + $has_channel = 1;
  185 + }
  186 + }
  187 +
  188 + if ($has_channel == 0) {
  189 + $channel = array_merge($channel, $vp_channel);
  190 +
  191 + $route = '';
  192 + foreach ($re_route as $vr) {
  193 + if ($vr['project_id'] == $vp->id) {
  194 + $route = $vr['route'];
  195 + break;
  196 + }
  197 + }
  198 + if (substr($route, -5) != '.html') {
  199 + $route = $route . '/';
  200 + }
  201 +
  202 + $lists[] = [
  203 + 'id' => $vp->id,
  204 + 'project' => $vp->project,
  205 + 'route' => $vp->domain . $route
  206 + ];
  207 + }
  208 + }
  209 + }
  210 + }
  211 +
  212 + return $this->success(array_slice($lists, 0, $num, true));
  213 + }
  214 +
  215 + /**
  216 + * AI重写询盘文案
  217 + * @return array
  218 + * @throws \App\Exceptions\AsideGlobalException
  219 + * @throws \App\Exceptions\BsideGlobalException
  220 + * @author Akun
  221 + * @date 2025/02/27 10:40
  222 + */
  223 + public function aiRewrite()
  224 + {
  225 + $ai_command = AiCommand::where('key', 'inquiry_text_rewrite')->value('ai');
  226 + if (!$ai_command) {
  227 + $this->fail('AI重写指令未配置');
  228 + }
  229 +
  230 + $in_content = $this->param['message'];
  231 + $translateSl = Translate::translateSl($in_content);
  232 + $lang = $translateSl['texts']['sl'] ?? 'en';
  233 + if ($lang == 'en' || $lang == 'ja' || $lang == 'ko' || Str::contains($lang, 'zh')) {
  234 + $lang = 'en';
  235 + }
  236 +
  237 + $ai_command = str_replace('{incontent}', Arr::random(explode("\r\n", $in_content)), $ai_command);
  238 +
  239 + $text = Gpt::instance()->openai_chat_qqs($ai_command);
  240 + if ($lang != 'en' && !Str::contains($lang, 'zh')) {
  241 + $text = Translate::tran($text, $lang);
  242 + }
  243 +
  244 + return $this->success(['ai_message' => Common::deal_str($text)]);
  245 + }
  246 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: zhl
  5 + * Date: 2024/9/30
  6 + * Time: 14:56
  7 + */
  8 +
  9 +namespace App\Models\Inquiry;
  10 +
  11 +use Illuminate\Database\Eloquent\Model;
  12 +
  13 +/**
  14 + * 询盘转发详情
  15 + * Class ReInquiryDetail
  16 + * @package App\Models\Inquiry
  17 + */
  18 +class InquiryRelayDetail extends Model
  19 +{
  20 + /**
  21 + * @var string
  22 + */
  23 + protected $table = 'gl_inquiry_relay_detail';
  24 +
  25 + /**
  26 + * 任务状态, 0:待处理,1:处理中,2:处理成功,3:抛弃数据,9:处理失败
  27 + */
  28 + const STATUS_INIT = 0;
  29 + const STATUS_PEND = 1;
  30 + const STATUS_SUCCESS = 2;
  31 + const STATUS_FORGO = 3;
  32 + const STATUS_FAIL = 9;
  33 +
  34 + /**
  35 + * 状态映射
  36 + * @return array
  37 + */
  38 + public static function statusMap()
  39 + {
  40 + return [
  41 + self::STATUS_INIT => '待处理',
  42 + self::STATUS_PEND => '处理中',
  43 + self::STATUS_SUCCESS => '处理成功',
  44 + self::STATUS_FORGO => '抛弃数据',
  45 + self::STATUS_FAIL => '处理失败',
  46 + ];
  47 + }
  48 +
  49 + /**
  50 + * 创建询盘转发详情待处理任务
  51 + * @param $form_id
  52 + * @param $website
  53 + * @param $country
  54 + * @param $ip
  55 + * @param $name
  56 + * @param $email
  57 + * @param $phone
  58 + * @param $message
  59 + * @param $is_v6
  60 + * @param $urls
  61 + * @param $start_at
  62 + * @param int $status
  63 + */
  64 + public static function createInquiry($form_id, $website, $country, $ip, $name, $email, $phone, $message, $is_v6, $urls, $start_at, $status = self::STATUS_INIT)
  65 + {
  66 + $self = self::where(compact('form_id', 'website'))->first();
  67 + if(!$self){
  68 + $self = new self();
  69 + $self->form_id = $form_id;
  70 + $self->website = $website;
  71 + $self->country = $country;
  72 + $self->ip = $ip;
  73 + $self->name = $name;
  74 + $self->email = $email;
  75 + $self->phone = $phone;
  76 + $self->message = $message;
  77 + $self->is_v6 = $is_v6;
  78 + $self->urls = $urls;
  79 + $self->start_at = $start_at;
  80 + $self->status = $status;
  81 + $self->save();
  82 + }
  83 + }
  84 +
  85 + /**
  86 + * 转发日志详情
  87 + * @return \Illuminate\Database\Eloquent\Relations\HasMany
  88 + */
  89 + public function detailLog()
  90 + {
  91 + return $this->hasMany(InquiryRelayDetailLog::class, 'detail_id', 'id');
  92 + }
  93 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: zhl
  5 + * Date: 2024/10/08
  6 + * Time: 14:10
  7 + */
  8 +
  9 +namespace App\Models\Inquiry;
  10 +
  11 +use Illuminate\Database\Eloquent\Model;
  12 +
  13 +/**
  14 + * 转发详情日志
  15 + * Class ReInquiryDetailLog
  16 + * @package App\Models\Inquiry
  17 + */
  18 +class InquiryRelayDetailLog extends Model
  19 +{
  20 + /**
  21 + * @var string
  22 + */
  23 + protected $table = 'gl_inquiry_relay_detail_log';
  24 +
  25 + /**
  26 + * 任务状态, 0:初始化,1:待处理,2:处理成功,9:处理失败
  27 + */
  28 + const STATUS_INIT = 0;
  29 + const STATUS_PEND = 1;
  30 + const STATUS_SUCCESS = 2;
  31 + const STATUS_FAIL = 9;
  32 +
  33 + /**
  34 + * 执行类型, 1:访问, 2:询盘
  35 + */
  36 + const TYPE_VISIT = 1;
  37 + const TYPE_INQUIRY = 2;
  38 +
  39 + /**
  40 + * 状态映射
  41 + * @return array
  42 + */
  43 + public static function statusMap()
  44 + {
  45 + return [
  46 + self::STATUS_INIT => '初始化',
  47 + self::STATUS_PEND => '待处理',
  48 + self::STATUS_SUCCESS => '处理成功',
  49 + self::STATUS_FAIL => '处理失败',
  50 + ];
  51 + }
  52 +
  53 +
  54 + /**
  55 + * 创建转发详情日志
  56 + * @param $detail_id
  57 + * @param $type
  58 + * @param $pre
  59 + * @param $url
  60 + * @param $start_at
  61 + */
  62 + public static function createInquiryLog($detail_id, $type, $pre, $url, $start_at)
  63 + {
  64 + $self = self::where(compact('detail_id', 'type', 'pre'))->first();
  65 + if (!$self) {
  66 + $self = new self();
  67 + $self->detail_id = $detail_id;
  68 + $self->type = $type;
  69 + $self->pre = $pre;
  70 + $self->url = $url;
  71 + $self->start_at = $start_at;
  72 + $self->save();
  73 + }
  74 + }
  75 +}
@@ -340,6 +340,16 @@ Route::middleware(['aloginauth'])->group(function () { @@ -340,6 +340,16 @@ Route::middleware(['aloginauth'])->group(function () {
340 Route::any('/getInternalCount', [Aside\Optimize\InquiryInfoController::class, 'getInternalCount'])->name('admin.inquiry_getInternalCount'); 340 Route::any('/getInternalCount', [Aside\Optimize\InquiryInfoController::class, 'getInternalCount'])->name('admin.inquiry_getInternalCount');
341 }); 341 });
342 342
  343 + //手动转发询盘
  344 + Route::prefix('inquiry_forward')->group(function () {
  345 + Route::any('/', [Aside\Optimize\InquiryForwardController::class, 'lists'])->name('admin.inquiry_lists');
  346 + Route::any('/getInquiryType', [Aside\Optimize\InquiryForwardController::class, 'getInquiryType'])->name('admin.inquiry_forward_getInquiryType');
  347 + Route::any('/forwardInquiry', [Aside\Optimize\InquiryForwardController::class, 'forwardInquiry'])->name('admin.inquiry_forward_forwardInquiry');
  348 + Route::any('/getInquiryIp', [Aside\Optimize\InquiryForwardController::class, 'getInquiryIp'])->name('admin.inquiry_forward_getInquiryIp');
  349 + Route::any('/searchInquiryKeywords', [Aside\Optimize\InquiryForwardController::class, 'searchInquiryKeywords'])->name('admin.inquiry_forward_searchInquiryKeywords');
  350 + Route::any('/aiRewriteInquiry', [Aside\Optimize\InquiryForwardController::class, 'aiRewriteInquiry'])->name('admin.inquiry_forward_aiRewriteInquiry');
  351 + });
  352 +
343 Route::prefix('custom_module')->group(function () { 353 Route::prefix('custom_module')->group(function () {
344 Route::any('/', [\App\Http\Controllers\Aside\CustomModule\CustomModuleController::class, 'lists'])->name('custom_lists'); 354 Route::any('/', [\App\Http\Controllers\Aside\CustomModule\CustomModuleController::class, 'lists'])->name('custom_lists');
345 Route::any('/save', [\App\Http\Controllers\Aside\CustomModule\CustomModuleController::class, 'save'])->name('custom_save'); 355 Route::any('/save', [\App\Http\Controllers\Aside\CustomModule\CustomModuleController::class, 'save'])->name('custom_save');