作者 刘锟

合并分支 'akun' 到 'master'

Akun



查看合并请求 !3094
@@ -5,14 +5,20 @@ @@ -5,14 +5,20 @@
5 * Date: 2025/10/27 5 * Date: 2025/10/27
6 * Time: 13:42 6 * Time: 13:42
7 */ 7 */
  8 +
8 namespace App\Console\Commands\Product; 9 namespace App\Console\Commands\Product;
9 10
10 use App\Console\Commands\Tdk\UpdateSeoTdk; 11 use App\Console\Commands\Tdk\UpdateSeoTdk;
  12 +use App\Models\Com\NoticeLog;
  13 +use App\Models\Com\UpdateNotify;
  14 +use App\Models\Domain\DomainInfo;
11 use App\Models\Product\Keyword; 15 use App\Models\Product\Keyword;
  16 +use App\Models\Project\DeployBuild;
12 use App\Models\Project\Project; 17 use App\Models\Project\Project;
13 use App\Services\ProjectServer; 18 use App\Services\ProjectServer;
14 use Illuminate\Console\Command; 19 use Illuminate\Console\Command;
15 use Illuminate\Support\Arr; 20 use Illuminate\Support\Arr;
  21 +use Illuminate\Support\Facades\Cache;
16 use Illuminate\Support\Str; 22 use Illuminate\Support\Str;
17 23
18 class SplicePrefix extends Command 24 class SplicePrefix extends Command
@@ -36,17 +42,36 @@ class SplicePrefix extends Command @@ -36,17 +42,36 @@ class SplicePrefix extends Command
36 */ 42 */
37 public function handle() 43 public function handle()
38 { 44 {
39 - #TODO 获取当日不达标项目, 检查关键词前缀拼接 45 + //获取当日不达标项目, 检查关键词前缀拼接
40 $project_ids = $this->getProject(); 46 $project_ids = $this->getProject();
41 if (empty($project_ids)) 47 if (empty($project_ids))
42 return true; 48 return true;
43 49
  50 + //获取已经拼接的项目id
  51 + $key = 'splice_prefix_project_ids';
  52 + $has_splice_ids = Cache::get($key) ?? [];
  53 +
44 foreach ($project_ids as $project_id) { 54 foreach ($project_ids as $project_id) {
45 if ($project_id == 1) 55 if ($project_id == 1)
46 continue; 56 continue;
  57 +
  58 + if (in_array($project_id, $has_splice_ids)) {
  59 + continue;
  60 + }
  61 +
47 $this->output('project start: ' . $project_id); 62 $this->output('project start: ' . $project_id);
  63 +
48 $this->bind($project_id); 64 $this->bind($project_id);
  65 +
  66 + //处理完后加入已拼接项目id集
  67 + array_push($has_splice_ids, $project_id);
  68 +
  69 + $this->output('project end: ' . $project_id);
49 } 70 }
  71 +
  72 + //更新已拼接项目id缓存
  73 + Cache::put($key, $has_splice_ids);
  74 +
50 return true; 75 return true;
51 } 76 }
52 77
@@ -56,129 +81,147 @@ class SplicePrefix extends Command @@ -56,129 +81,147 @@ class SplicePrefix extends Command
56 */ 81 */
57 public function bind($project_id) 82 public function bind($project_id)
58 { 83 {
59 - $project = ProjectServer::useProject($project_id);  
60 -  
61 - // 客户前缀  
62 - $tdk_class = new UpdateSeoTdk();  
63 - $info = $tdk_class->getDeployOptimize($project_id);  
64 - $fix_keyword = explode(",", $info['keyword_prefix']);  
65 - $fix_keyword = array_filter($fix_keyword);  
66 -  
67 - // 所有前缀  
68 - $all_prefixes = $tdk_class->getAllPrefix(1, $project_id);  
69 - $all_prefixes = array_map('strtolower', $all_prefixes);  
70 -  
71 - $keywords = Keyword::select(['id', 'title', 'seo_title'])->get();  
72 - foreach ($keywords as $item) {  
73 - $this_fix_keyword = $fix_keyword;  
74 - if (empty($item->title))  
75 - continue; 84 + $notify_master = false;
  85 + if (ProjectServer::useProject($project_id)) {
76 86
77 - $this->output('keyword id:' . $item->id . ' | title: ' . $item->title . ' | old seo title: ' . $item->seo_title); 87 + // 客户前缀
  88 + $tdk_class = new UpdateSeoTdk();
  89 + $info = $tdk_class->getDeployOptimize($project_id);
  90 + $fix_keyword = explode(",", $info['keyword_prefix']);
  91 + $fix_keyword = array_filter($fix_keyword);
78 92
79 - // 没有 SEO Title 直接生成  
80 - if (empty($item->seo_title)) {  
81 - $prefix = $tdk_class->getPrefixKeyword($project_id, 'prefix', 2, $item->title);  
82 - $suffix = $tdk_class->getPrefixKeyword($project_id, 'suffix', 2, trim($prefix . ' ' . $item->title));  
83 - if(Str::startsWith($suffix, ', ')){  
84 - $seo_title = $prefix . ' ' . $item->title . $suffix;  
85 - }else{  
86 - $seo_title = $prefix . ' ' . $item->title . ' ' . $suffix;  
87 - }  
88 -// $item->seo_title = trim($seo_title);  
89 -// $item->save();  
90 - $this->output('new seo title: ' . $seo_title);  
91 - continue;  
92 - } 93 + // 所有前缀
  94 + $all_prefixes = $tdk_class->getAllPrefix(1, $project_id);
  95 + $all_prefixes = array_map('strtolower', $all_prefixes);
93 96
94 - // 有 SEO Title 需要分析前后缀  
95 - $start = strpos($item->seo_title, $item->title); 97 + $keywords = Keyword::select(['id', 'title', 'seo_title', 'route'])->get();
  98 + foreach ($keywords as $item) {
  99 + $this_fix_keyword = $fix_keyword;
  100 + if (empty($item->title))
  101 + continue;
96 102
97 - // Title 和 SEO Title 不存在包含关系  
98 - if ($start === FALSE) {  
99 - $this->output('Title 和 SEO Title 不存在包含关系');  
100 - continue;  
101 - } 103 + $this->output('keyword id:' . $item->id . ' | title: ' . $item->title . ' | old seo title: ' . $item->seo_title);
102 104
103 - $prefix = $start == 0 ? '' : trim(substr($item->seo_title, 0, $start));  
104 - $prefix_array = explode(' ', $prefix);  
105 - $prefix_array = array_filter($prefix_array);  
106 - $need_num = 2 - count($prefix_array);  
107 - // 已经有两个前缀, 不在处理  
108 - if ($need_num <= 0) {  
109 - $this->output('已经有两个前缀, 不在处理');  
110 - continue;  
111 - } 105 + // 没有 SEO Title 直接生成
  106 + if (empty($item->seo_title)) {
  107 + $prefix = $tdk_class->getPrefixKeyword($project_id, 'prefix', 2, $item->title);
  108 + $suffix = $tdk_class->getPrefixKeyword($project_id, 'suffix', 2, trim($prefix . ' ' . $item->title));
  109 + if (Str::startsWith($suffix, ', ')) {
  110 + $seo_title = $prefix . ' ' . $item->title . $suffix;
  111 + } else {
  112 + $seo_title = $prefix . ' ' . $item->title . ' ' . $suffix;
  113 + }
  114 + $item->seo_title = trim($seo_title);
  115 + $item->save();
112 116
113 - // 关键词最后一个词是前缀的词,前后缀都不拼  
114 - $title_words = explode(' ', strtolower($item->title)); 117 + //存入按需更新表
  118 + UpdateNotify::addUpdateItem($project_id, 'product_keyword', $item->route);
  119 + $notify_master = true;
115 120
116 - // 关键词最后一个词是前缀的词,前后缀都不拼  
117 - if(in_array(Arr::last($title_words), $all_prefixes)) {  
118 - $this->output('关键词最后一个词是前缀的词, 前后缀都不拼');  
119 - continue;  
120 - } 121 + $this->output('new seo title: ' . $seo_title);
  122 + continue;
  123 + }
121 124
122 - // in,for,with,to,near,from 这些介词 只拼前缀,不拼后缀  
123 - $ban = []; 125 + // 有 SEO Title 需要分析前后缀
  126 + $start = strpos($item->seo_title, $item->title);
124 127
125 - // 关键词本身包含了前缀,也可以再拼一个不重复的前缀, 包含两个前缀就不拼前缀了  
126 - foreach ($title_words as $title_word) {  
127 - if(in_array($title_word, $all_prefixes)){  
128 - $ban[] = $title_word; 128 + // Title 和 SEO Title 不存在包含关系
  129 + if ($start === FALSE) {
  130 + $this->output('Title 和 SEO Title 不存在包含关系');
  131 + continue;
129 } 132 }
130 - }  
131 - $need_num = $need_num - count($ban);  
132 133
133 - // 关键词本身包含前缀,包含关键词大于等于需要的前缀,当前关键词不需要处理  
134 - if ($need_num <= 0) {  
135 - $this->output('关键词本身包含前缀,包含关键词大于等于需要的前缀,当前关键词不需要处理');  
136 - continue;  
137 - } 134 + $prefix = $start == 0 ? '' : trim(substr($item->seo_title, 0, $start));
  135 + $prefix_array = explode(' ', $prefix);
  136 + $prefix_array = array_filter($prefix_array);
  137 + $need_num = 2 - count($prefix_array);
  138 + // 已经有两个前缀, 不在处理
  139 + if ($need_num <= 0) {
  140 + $this->output('已经有两个前缀, 不在处理');
  141 + continue;
  142 + }
138 143
  144 + // 关键词最后一个词是前缀的词,前后缀都不拼
  145 + $title_words = explode(' ', strtolower($item->title));
139 146
140 - // services/service 结尾的词,后缀不拼manufacturer,factory  
141 - // manufacturer,factory 结尾的词,后缀不拼 services/service  
142 - // 有wholesale或cheap的词,后缀不拼 manufacturer,factory,exporter,company 147 + // 关键词最后一个词是前缀的词,前后缀都不拼
  148 + if (in_array(Arr::last($title_words), $all_prefixes)) {
  149 + $this->output('关键词最后一个词是前缀的词, 前后缀都不拼');
  150 + continue;
  151 + }
143 152
144 - // 关键词以manufacturer,factory,exporter,company结尾, 前缀不拼wholesale或cheap的词  
145 - if (Str::endsWith(strtolower($item->title), ['manufacturer', 'manufacturers', 'factory', 'factories', 'exporter', 'exporters', 'company', 'companies', 'supplier', 'suppliers']))  
146 - $ban = array_merge($ban, ['wholesale', 'cheap', 'buy']); 153 + // in,for,with,to,near,from 这些介词 只拼前缀,不拼后缀
  154 + $ban = [];
147 155
  156 + // 关键词本身包含了前缀,也可以再拼一个不重复的前缀, 包含两个前缀就不拼前缀了
  157 + foreach ($title_words as $title_word) {
  158 + if (in_array($title_word, $all_prefixes)) {
  159 + $ban[] = $title_word;
  160 + }
  161 + }
  162 + $need_num = $need_num - count($ban);
148 163
149 - foreach ($this_fix_keyword as $k => $keyword) {  
150 - // 被禁用的关键词  
151 - if (in_array(strtolower(Str::plural($keyword)), $ban)) {  
152 - unset($this_fix_keyword[$k]); 164 + // 关键词本身包含前缀,包含关键词大于等于需要的前缀,当前关键词不需要处理
  165 + if ($need_num <= 0) {
  166 + $this->output('关键词本身包含前缀,包含关键词大于等于需要的前缀,当前关键词不需要处理');
  167 + continue;
153 } 168 }
154 - if (in_array(strtolower(Str::singular($keyword)), $ban)) {  
155 - unset($this_fix_keyword[$k]); 169 +
  170 +
  171 + // services/service 结尾的词,后缀不拼manufacturer,factory
  172 + // manufacturer,factory 结尾的词,后缀不拼 services/service
  173 + // 有wholesale或cheap的词,后缀不拼 manufacturer,factory,exporter,company
  174 +
  175 + // 关键词以manufacturer,factory,exporter,company结尾, 前缀不拼wholesale或cheap的词
  176 + if (Str::endsWith(strtolower($item->title), ['manufacturer', 'manufacturers', 'factory', 'factories', 'exporter', 'exporters', 'company', 'companies', 'supplier', 'suppliers']))
  177 + $ban = array_merge($ban, ['wholesale', 'cheap', 'buy']);
  178 +
  179 +
  180 + foreach ($this_fix_keyword as $k => $keyword) {
  181 + // 被禁用的关键词
  182 + if (in_array(strtolower(Str::plural($keyword)), $ban)) {
  183 + unset($this_fix_keyword[$k]);
  184 + }
  185 + if (in_array(strtolower(Str::singular($keyword)), $ban)) {
  186 + unset($this_fix_keyword[$k]);
  187 + }
156 } 188 }
157 - }  
158 - $this_fix_keyword = array_diff($this_fix_keyword, $prefix_array);  
159 - shuffle($this_fix_keyword);  
160 - $need_keyword = [];  
161 - foreach ($this_fix_keyword as $v) {  
162 - if ($need_num == 0)  
163 - break;  
164 -  
165 - $is_repeat = false;  
166 - foreach ($need_keyword as $keyword) {  
167 - if (Str::singular($keyword) == Str::singular($v)) {  
168 - $is_repeat = true; 189 + $this_fix_keyword = array_diff($this_fix_keyword, $prefix_array);
  190 + shuffle($this_fix_keyword);
  191 + $need_keyword = [];
  192 + foreach ($this_fix_keyword as $v) {
  193 + if ($need_num == 0)
169 break; 194 break;
  195 +
  196 + $is_repeat = false;
  197 + foreach ($need_keyword as $keyword) {
  198 + if (Str::singular($keyword) == Str::singular($v)) {
  199 + $is_repeat = true;
  200 + break;
  201 + }
170 } 202 }
  203 + if ($is_repeat)
  204 + continue;
  205 +
  206 + $need_keyword[] = $v;
  207 + $need_num--;
171 } 208 }
172 - if ($is_repeat)  
173 - continue; 209 + $item->seo_title = trim(implode(' ', $need_keyword) . ' ' . trim($item->seo_title));
  210 + $item->save();
174 211
175 - $need_keyword[] = $v;  
176 - $need_num--; 212 + //存入按需更新表
  213 + UpdateNotify::addUpdateItem($project_id, 'product_keyword', $item->route);
  214 + $notify_master = true;
  215 +
  216 + $this->output('new seo title: ' . implode(' ', $need_keyword) . ' ' . trim($item->seo_title));
177 } 217 }
178 -// $item->seo_title = trim(implode(' ', $need_keyword) . ' ' . trim($item->seo_title));  
179 -// $item->save();  
180 - $this->output('new seo title: ' . implode(' ', $need_keyword) . ' ' . trim($item->seo_title));  
181 } 218 }
  219 +
  220 + if ($notify_master) {
  221 + //通知主站按需更新
  222 + $this->sendNotify($project_id, 2);
  223 + }
  224 +
182 return true; 225 return true;
183 } 226 }
184 227
@@ -188,8 +231,40 @@ class SplicePrefix extends Command @@ -188,8 +231,40 @@ class SplicePrefix extends Command
188 */ 231 */
189 public function getProject() 232 public function getProject()
190 { 233 {
191 - $project_ids = Project::where(['type' => Project::TYPE_TWO, 'project_type' => Project::TYPE_ZERO, 'delete_status' => Project::IS_DEL_FALSE, 'is_remain_today' => 0])->pluck('id')->toArray();  
192 - return $project_ids; 234 + return Project::where(['type' => Project::TYPE_TWO, 'project_type' => Project::TYPE_ZERO, 'delete_status' => Project::IS_DEL_FALSE, 'is_remain_today' => 0])->pluck('id')->toArray();
  235 + }
  236 +
  237 + /**
  238 + * 页面更新
  239 + * @param $project_id
  240 + * @param $route
  241 + * @author Akun
  242 + * @date 2025/10/30 14:33
  243 + */
  244 + public function sendNotify($project_id, $route)
  245 + {
  246 + //获取当前项目的域名
  247 + $domainModel = new DomainInfo();
  248 + $domainInfo = $domainModel->read(['project_id' => $project_id]);
  249 + if ($domainInfo === false) {
  250 + //获取测试域名
  251 + $deployBuildModel = new DeployBuild();
  252 + $buildInfo = $deployBuildModel->read(['project_id' => $project_id]);
  253 + $domain = $buildInfo['test_domain'];
  254 + } else {
  255 + $domain = 'https://' . $domainInfo['domain'] . '/';
  256 + }
  257 + $url = $domain . 'api/update_page/';
  258 + $param = [
  259 + 'project_id' => $project_id,
  260 + 'type' => 1,
  261 + 'route' => $route,
  262 + 'url' => [],
  263 + 'language' => [],
  264 + ];
  265 + NoticeLog::createLog(NoticeLog::GENERATE_PAGE, ['c_url' => $url, 'c_params' => $param], date('Y-m-d H:i:s', time() + 300));
  266 +
  267 + $this->output('更新中请稍后, 更新完成将会发送站内信通知更新结果!');
193 } 268 }
194 269
195 /** 270 /**