作者 刘锟

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

@@ -26,7 +26,7 @@ use function Symfony\Component\String\s; @@ -26,7 +26,7 @@ use function Symfony\Component\String\s;
26 26
27 /*** 27 /***
28 * @remark :根据项目更新blog列表 28 * @remark :根据项目更新blog列表
29 - * @name :AiBlogListTask 29 + * @name :AiBlogListProjectTask
30 * @author :lyh 30 * @author :lyh
31 * @method :post 31 * @method :post
32 * @time :2025/3/6 9:45 32 * @time :2025/3/6 9:45
  1 +<?php
  2 +/**
  3 + * @remark :
  4 + * @name :AiBlogTask.php
  5 + * @author :lyh
  6 + * @method :post
  7 + * @time :2025/2/14 11:14
  8 + */
  9 +
  10 +namespace App\Console\Commands\Ai;
  11 +
  12 +use App\Models\Ai\AiBlog;
  13 +use App\Models\Ai\AiBlogAuthor;
  14 +use App\Models\Ai\AiBlogList;
  15 +use App\Models\Domain\DomainInfo;
  16 +use App\Models\Project\ProjectAiSetting;
  17 +use App\Models\RouteMap\RouteMap;
  18 +use App\Services\AiBlogService;
  19 +use App\Services\ProjectServer;
  20 +use Illuminate\Console\Command;
  21 +use App\Models\Project\AiBlogTask as AiBlogTaskModel;
  22 +use Illuminate\Support\Facades\Cache;
  23 +use Illuminate\Support\Facades\DB;
  24 +use function Symfony\Component\String\s;
  25 +
  26 +/***
  27 + * @remark :根据项目更新blog列表
  28 + * @name :AiBlogListProjectTask
  29 + * @author :lyh
  30 + * @method :post
  31 + * @time :2025/3/6 9:45
  32 + */
  33 +class AiBlogListProjectTask extends Command
  34 +{
  35 + /**
  36 + * The name and signature of the console command.
  37 + *
  38 + * @var string
  39 + */
  40 + protected $signature = 'save_ai_blog_list {project_id}';
  41 +
  42 + /**
  43 + * The console command description.
  44 + *
  45 + * @var string
  46 + */
  47 + protected $description = '根据项目生成blog列表';
  48 +
  49 + public function handle(){
  50 + $project_id = $this->argument('project_id');
  51 + @file_put_contents(storage_path('logs/lyh_error.log'), var_export('执行的项目id->'.$project_id, true) . PHP_EOL, FILE_APPEND);
  52 + ProjectServer::useProject($project_id);
  53 + $projectAiSettingModel = new ProjectAiSetting();
  54 + $aiSettingInfo = $projectAiSettingModel->read(['project_id'=>$project_id]);
  55 + $this->updateBlogList($aiSettingInfo);
  56 + $this->curlDelRoute($project_id);
  57 + DB::disconnect('custom_mysql');
  58 + return true;
  59 + }
  60 +
  61 + /**
  62 + * @remark :更新列表页数据
  63 + * @name :updateBlogList
  64 + * @author :lyh
  65 + * @method :post
  66 + * @time :2025/3/5 11:07
  67 + */
  68 + public function updateBlogList($aiSettingInfo){
  69 + $aiBlogService = new AiBlogService();
  70 + $aiBlogService->mch_id = $aiSettingInfo['mch_id'];
  71 + $aiBlogService->key = $aiSettingInfo['key'];
  72 + $page = 1;
  73 + $saveData = [];
  74 + $result = $aiBlogService->getAiBlogList($page,15);
  75 + if(!isset($result['status']) || $result['status'] != 200){
  76 + echo '请示失败。'.json_encode($result, JSON_UNESCAPED_UNICODE);
  77 + return true;
  78 + }
  79 + $total_page = $result['data']['total_page'];
  80 + //组装数据保存
  81 + $saveData[] = [
  82 + 'route'=>$page,
  83 + 'text'=>$result['data']['section'],
  84 + ];
  85 + while ($total_page > $page){
  86 + $page++;
  87 + $result = $aiBlogService->getAiBlogList($page,15);
  88 + if(isset($result['status']) && $result['status'] == 200){
  89 + $saveData[] = [
  90 + 'route'=>$page,
  91 + 'text'=>$result['data']['section'],
  92 + ];
  93 + }
  94 + }
  95 + $aiBlogListModel = new AiBlogList();
  96 + if(!empty($saveData)){
  97 + //写一条路由信息
  98 + $aiBlogListModel->truncate();
  99 + $aiBlogListModel->insertAll($saveData);
  100 + }
  101 + return true;
  102 + }
  103 +
  104 + /**
  105 + * @remark :通知C端生成界面
  106 + * @name :sendNotice
  107 + * @author :lyh
  108 + * @method :post
  109 + * @time :2025/3/6 11:51
  110 + */
  111 + public function curlDelRoute($project_id){
  112 + $domainModel = new DomainInfo();
  113 + //获取项目域名
  114 + $domain = $domainModel->getProjectIdDomain($project_id);
  115 + if(!empty($domain)){
  116 + $c_url = $domain.'api/update_page/';
  117 + $param = [
  118 + 'project_id' => $project_id,
  119 + 'type' => 1,
  120 + 'route' => 3,
  121 + 'url' => ['top-blog'],
  122 + 'language'=> [],
  123 + 'is_sitemap' => 0
  124 + ];
  125 + http_post($c_url, json_encode($param));
  126 + }
  127 + return true;
  128 + }
  129 +}
@@ -21,11 +21,12 @@ use Illuminate\Console\Command; @@ -21,11 +21,12 @@ use Illuminate\Console\Command;
21 use App\Models\Project\AiBlogTask as AiBlogTaskModel; 21 use App\Models\Project\AiBlogTask as AiBlogTaskModel;
22 use Illuminate\Support\Facades\Cache; 22 use Illuminate\Support\Facades\Cache;
23 use Illuminate\Support\Facades\DB; 23 use Illuminate\Support\Facades\DB;
  24 +use Illuminate\Support\Facades\Redis;
24 use function Symfony\Component\String\s; 25 use function Symfony\Component\String\s;
25 26
26 /*** 27 /***
27 * @remark :根据项目更新blog列表 28 * @remark :根据项目更新blog列表
28 - * @name :AiBlogListTask 29 + * @name :AiBlogListProjectTask
29 * @author :lyh 30 * @author :lyh
30 * @method :post 31 * @method :post
31 * @time :2025/3/6 9:45 32 * @time :2025/3/6 9:45
@@ -37,24 +38,45 @@ class AiBlogListTask extends Command @@ -37,24 +38,45 @@ class AiBlogListTask extends Command
37 * 38 *
38 * @var string 39 * @var string
39 */ 40 */
40 - protected $signature = 'save_ai_blog_list {project_id}'; 41 + protected $signature = 'save_ai_blog_list_task';
41 42
42 /** 43 /**
43 * The console command description. 44 * The console command description.
44 * 45 *
45 * @var string 46 * @var string
46 */ 47 */
47 - protected $description = '生成blog列表'; 48 + protected $description = '生成blog列表';
48 49
49 public function handle(){ 50 public function handle(){
50 - $project_id = $this->argument('project_id');  
51 - @file_put_contents(storage_path('logs/lyh_error.log'), var_export('执行的项目id->'.$project_id, true) . PHP_EOL, FILE_APPEND);  
52 - ProjectServer::useProject($project_id);  
53 - $projectAiSettingModel = new ProjectAiSetting();  
54 - $aiSettingInfo = $projectAiSettingModel->read(['project_id'=>$project_id]);  
55 - $this->updateBlogList($aiSettingInfo);  
56 - $this->curlDelRoute($project_id);  
57 - DB::disconnect('custom_mysql'); 51 + while (true){
  52 + $task_id = $this->getTaskId();
  53 + if(empty($task_id)){
  54 + sleep(200);
  55 + continue;
  56 + }
  57 + $aiBlogTaskModel = new AiBlogTaskModel();
  58 + $info = $aiBlogTaskModel->read(['id'=>$task_id,'type'=>$aiBlogTaskModel::TYPE_LIST]);
  59 + if($info === false){
  60 + echo date('Y-m-d H:i:s').',当前数据不存在或者已被删除。'.PHP_EOL;
  61 + }
  62 + $project_id = $info['project_id'];
  63 + echo '执行的项目ID:'.$info['project_id'].PHP_EOL;
  64 + ProjectServer::useProject($project_id);
  65 + $projectAiSettingModel = new ProjectAiSetting();
  66 + $aiSettingInfo = $projectAiSettingModel->read(['project_id'=>$project_id]);
  67 + $res = $this->updateBlogList($aiSettingInfo);
  68 + if($res){
  69 + $aiBlogTaskModel->edit(['status'=>2],['id'=>$task_id]);
  70 + }else{
  71 + if($info['sort'] >= 5){
  72 + $aiBlogTaskModel->edit(['status'=>9],['id'=>$task_id]);
  73 + }else{
  74 + $aiBlogTaskModel->edit(['status'=>9,'sort'=>($info['sort'] + 1)],['id'=>$task_id]);
  75 + }
  76 + }
  77 + $this->curlDelRoute($project_id);
  78 + DB::disconnect('custom_mysql');
  79 + }
58 return true; 80 return true;
59 } 81 }
60 82
@@ -73,8 +95,8 @@ class AiBlogListTask extends Command @@ -73,8 +95,8 @@ class AiBlogListTask extends Command
73 $saveData = []; 95 $saveData = [];
74 $result = $aiBlogService->getAiBlogList($page,15); 96 $result = $aiBlogService->getAiBlogList($page,15);
75 if(!isset($result['status']) || $result['status'] != 200){ 97 if(!isset($result['status']) || $result['status'] != 200){
76 - echo '请示失败。'.json_encode($result, JSON_UNESCAPED_UNICODE);  
77 - return true; 98 + echo '请求失败。'.json_encode($result, JSON_UNESCAPED_UNICODE);
  99 + return false;
78 } 100 }
79 $total_page = $result['data']['total_page']; 101 $total_page = $result['data']['total_page'];
80 //组装数据保存 102 //组装数据保存
@@ -90,6 +112,9 @@ class AiBlogListTask extends Command @@ -90,6 +112,9 @@ class AiBlogListTask extends Command
90 'route'=>$page, 112 'route'=>$page,
91 'text'=>$result['data']['section'], 113 'text'=>$result['data']['section'],
92 ]; 114 ];
  115 + }else{
  116 + echo '请求失败。'.json_encode($result, JSON_UNESCAPED_UNICODE);
  117 + return false;
93 } 118 }
94 } 119 }
95 $aiBlogListModel = new AiBlogList(); 120 $aiBlogListModel = new AiBlogList();
@@ -97,6 +122,7 @@ class AiBlogListTask extends Command @@ -97,6 +122,7 @@ class AiBlogListTask extends Command
97 //写一条路由信息 122 //写一条路由信息
98 $aiBlogListModel->truncate(); 123 $aiBlogListModel->truncate();
99 $aiBlogListModel->insertAll($saveData); 124 $aiBlogListModel->insertAll($saveData);
  125 + return true;
100 } 126 }
101 return true; 127 return true;
102 } 128 }
@@ -126,4 +152,27 @@ class AiBlogListTask extends Command @@ -126,4 +152,27 @@ class AiBlogListTask extends Command
126 } 152 }
127 return true; 153 return true;
128 } 154 }
  155 +
  156 + /**
  157 + * 获取任务id
  158 + * @param int $finish_at
  159 + * @return mixed
  160 + */
  161 + public function getTaskId($finish_at = 2)
  162 + {
  163 + $keys = 'ai_blog_list_task';
  164 + $task_id = Redis::rpop($keys);
  165 + if (empty($task_id)) {
  166 + $aiBlogTaskModel = new AiBlogTaskModel();
  167 + $finish_at = date('Y-m-d H:i:s', strtotime('-' . $finish_at . ' hour'));
  168 + $ids = $aiBlogTaskModel->formatQuery(['status'=>$aiBlogTaskModel::STATUS_RUNNING, 'type'=>$aiBlogTaskModel::TYPE_LIST, 'updated_at'=>['<=',$finish_at]])->pluck('id');
  169 + if(!empty($ids)){
  170 + foreach ($ids as $id) {
  171 + Redis::lpush($keys, $id);
  172 + }
  173 + }
  174 + $task_id = Redis::rpop($keys);
  175 + }
  176 + return $task_id;
  177 + }
129 } 178 }
@@ -26,10 +26,8 @@ use App\Services\DingService; @@ -26,10 +26,8 @@ use App\Services\DingService;
26 use App\Services\ProjectServer; 26 use App\Services\ProjectServer;
27 use Illuminate\Console\Command; 27 use Illuminate\Console\Command;
28 use App\Models\Project\AiBlogTask as AiBlogTaskModel; 28 use App\Models\Project\AiBlogTask as AiBlogTaskModel;
29 -use Illuminate\Support\Facades\Cache;  
30 use Illuminate\Support\Facades\DB; 29 use Illuminate\Support\Facades\DB;
31 use Illuminate\Support\Facades\Redis; 30 use Illuminate\Support\Facades\Redis;
32 -use function Symfony\Component\String\s;  
33 31
34 class AiBlogTask extends Command 32 class AiBlogTask extends Command
35 { 33 {
@@ -183,7 +181,7 @@ class AiBlogTask extends Command @@ -183,7 +181,7 @@ class AiBlogTask extends Command
183 ProjectServer::useProject($project_id); 181 ProjectServer::useProject($project_id);
184 $aiSettingInfo = $this->getSetting($project_id); 182 $aiSettingInfo = $this->getSetting($project_id);
185 $this->output('sync: list start, project_id: ' . $project_id); 183 $this->output('sync: list start, project_id: ' . $project_id);
186 - $this->updateBlogList($aiSettingInfo); 184 + $this->updateBlogList($aiSettingInfo,$project_id);
187 $this->output('sync: list end'); 185 $this->output('sync: list end');
188 //更新作者 186 //更新作者
189 $this->output('sync: author start, project_id: ' . $project_id); 187 $this->output('sync: author start, project_id: ' . $project_id);
@@ -249,7 +247,7 @@ class AiBlogTask extends Command @@ -249,7 +247,7 @@ class AiBlogTask extends Command
249 * @param $aiSettingInfo 247 * @param $aiSettingInfo
250 * @return bool 248 * @return bool
251 */ 249 */
252 - public function updateBlogList($aiSettingInfo){ 250 + public function updateBlogList($aiSettingInfo,$project_id = 0){
253 $aiBlogService = new AiBlogService(); 251 $aiBlogService = new AiBlogService();
254 $aiBlogService->mch_id = $aiSettingInfo['mch_id']; 252 $aiBlogService->mch_id = $aiSettingInfo['mch_id'];
255 $aiBlogService->key = $aiSettingInfo['key']; 253 $aiBlogService->key = $aiSettingInfo['key'];
@@ -257,6 +255,21 @@ class AiBlogTask extends Command @@ -257,6 +255,21 @@ class AiBlogTask extends Command
257 $saveData = []; 255 $saveData = [];
258 $result = $aiBlogService->getAiBlogList($page,15); 256 $result = $aiBlogService->getAiBlogList($page,15);
259 if(!isset($result['status']) || $result['status'] != 200){ 257 if(!isset($result['status']) || $result['status'] != 200){
  258 + try {
  259 + // 钉钉通知
  260 + $dingService = new DingService();
  261 + $body = [
  262 + 'keyword' => 'AI_BLOG列表页未生成拉取失败',
  263 + 'msg' => '项目ID:' . $project_id . PHP_EOL . '返回信息:' . json_encode($result,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
  264 + 'isAtAll' => false, // 是否@所有人
  265 + ];
  266 + $dingService->handle($body);
  267 + //写一条更新记录
  268 + $aiBlogTaskModel = new AiBlogTaskModel();
  269 + $aiBlogTaskModel->addReturnId(['project_id'=>$project_id,'task_id'=>$project_id,'status'=>$aiBlogTaskModel::STATUS_RUNNING,'type'=>$aiBlogTaskModel::TYPE_LIST]);
  270 + }catch (\Exception $e){
  271 + $this->output('更新列表页失败同时通知失败--error:' . $e->getMessage());
  272 + }
260 return true; 273 return true;
261 } 274 }
262 $total_page = $result['data']['total_page']; 275 $total_page = $result['data']['total_page'];
@@ -27,7 +27,7 @@ use function Symfony\Component\String\s; @@ -27,7 +27,7 @@ use function Symfony\Component\String\s;
27 27
28 /*** 28 /***
29 * @remark :根据项目更新blog列表 29 * @remark :根据项目更新blog列表
30 - * @name :AiBlogListTask 30 + * @name :AiBlogListProjectTask
31 * @author :lyh 31 * @author :lyh
32 * @method :post 32 * @method :post
33 * @time :2025/3/6 9:45 33 * @time :2025/3/6 9:45
@@ -10,7 +10,9 @@ @@ -10,7 +10,9 @@
10 namespace App\Console\Commands\SyncFilesImage; 10 namespace App\Console\Commands\SyncFilesImage;
11 11
12 use App\Models\File\ErrorFile; 12 use App\Models\File\ErrorFile;
  13 +use App\Models\Geo\GeoQuestion;
13 use Illuminate\Console\Command; 14 use Illuminate\Console\Command;
  15 +use Illuminate\Support\Facades\Redis;
14 16
15 class SyncFile extends Command 17 class SyncFile extends Command
16 { 18 {
@@ -30,22 +32,57 @@ class SyncFile extends Command @@ -30,22 +32,57 @@ class SyncFile extends Command
30 32
31 33
32 public function handle(){ 34 public function handle(){
33 - $errorFileModel = new ErrorFile();  
34 - $lists = $errorFileModel->list(['status'=>0]);//未同步成功的图片及文件  
35 - foreach ($lists as $k => $v){  
36 - if(strpos($v['path'], '/181/') !== false ){  
37 - $code = $this->synchronizationFiles($v['path']); 35 + while (true){
  36 + $task_id = $this->getTaskId();
  37 + echo "task_id:$task_id\n";
  38 + if(empty($task_id)){
  39 + sleep(100);
  40 + continue;
  41 + }
  42 + $errorFileModel = new ErrorFile();
  43 + $info = $errorFileModel->read(['id'=>$task_id],['id','path']);
  44 + if(strpos($info['path'], '/181/') !== false ){
  45 + $code = $this->synchronizationFiles($info['path']);
  46 + }else{
  47 + $code = $this->synchronizationFile($info['path']);
  48 + }
  49 + if(200 == (int)$code){
  50 + echo date('Y-m-d H:i:s') . '编辑的path为:'. $info['path'] .',主键id:'. $info['id'] . PHP_EOL;
  51 + $errorFileModel->edit(['status'=>2],['id'=>$info['id']]);
38 }else{ 52 }else{
39 - $code = $this->synchronizationFile($v['path']); 53 + $errorFileModel->edit(['status'=>0],['id'=>$info['id']]);
40 } 54 }
41 -// echo date('Y-m-d H:i:s') . 'code:'. $code . PHP_EOL;  
42 -// if((int)$code == 200){  
43 -// echo date('Y-m-d H:i:s') . '编辑的path为:'. $v['path'] .',主键id:'. $v['id'] . PHP_EOL;  
44 -// $errorFileModel->edit(['status'=>1],['id'=>$v['id']]);  
45 -// } 55 + echo date('Y-m-d H:i:s') . '编辑的end为:' .$code . PHP_EOL;
46 } 56 }
47 - echo date('Y-m-d H:i:s') . '编辑的end为:' . PHP_EOL;  
48 - return true; 57 + }
  58 +
  59 + public function getTaskId(){
  60 + $key = 'sync_file_task';
  61 + $task_id = Redis::rpop($key);
  62 + if(empty($task_id)){
  63 + $lock_key = 'sync_file_lock';
  64 + $lock_ttl = 60;
  65 + // 尝试获取锁
  66 + $lock = Redis::set($lock_key, 1, 'EX', $lock_ttl, 'NX');
  67 + if (empty($lock)){
  68 + echo '等待加载数据:';
  69 + return $task_id;
  70 + }
  71 + try {
  72 + $errorFileModel = new ErrorFile();
  73 + $lists = $errorFileModel->list(['status'=>0],'id',['id','path'],'asc',2000);
  74 + foreach ($lists as $v){
  75 + Redis::lpush($key, $v['id']);
  76 + $errorFileModel->edit(['status'=>1],['id'=>$v['id']]);
  77 + }
  78 + $task_id = Redis::rpop($key);
  79 + } finally {
  80 + // 释放锁
  81 + Redis::del($lock_key);
  82 + }
  83 + }
  84 +
  85 + return $task_id;
49 } 86 }
50 87
51 /** 88 /**
@@ -57,8 +94,6 @@ class SyncFile extends Command @@ -57,8 +94,6 @@ class SyncFile extends Command
57 */ 94 */
58 public function synchronizationFile($path_name){ 95 public function synchronizationFile($path_name){
59 //同步到大文件 96 //同步到大文件
60 - $file_path = config('filesystems.disks.cos')['cdn1'].$path_name;  
61 - $directoryPath = pathinfo($path_name, PATHINFO_DIRNAME);  
62 $cmd = 'curl -k -F "file_path='.$path_name.'" -F "save_path=/www/wwwroot/cos'.$path_name.'" https://v6-file.globalso.com/upload.php'; 97 $cmd = 'curl -k -F "file_path='.$path_name.'" -F "save_path=/www/wwwroot/cos'.$path_name.'" https://v6-file.globalso.com/upload.php';
63 return shell_exec($cmd); 98 return shell_exec($cmd);
64 } 99 }
@@ -68,7 +103,7 @@ class SyncFile extends Command @@ -68,7 +103,7 @@ class SyncFile extends Command
68 //同步到大文件 103 //同步到大文件
69 $file_path = config('filesystems.disks.s3')['cdn'].$path_name; 104 $file_path = config('filesystems.disks.s3')['cdn'].$path_name;
70 $directoryPath = pathinfo($path_name, PATHINFO_DIRNAME); 105 $directoryPath = pathinfo($path_name, PATHINFO_DIRNAME);
71 - $cmd = 'curl -k -F "file_path='.$path_name.'" -F "save_path=/www/wwwroot/cos'.$path_name.'" https://v6-file.globalso.com/upload.php'; 106 + $cmd = 'curl -k -F "file_path='.$file_path.'" -F "save_path=/www/wwwroot/cos'.$directoryPath.'" https://v6-file.globalso.com/upload.php';
72 return shell_exec($cmd); 107 return shell_exec($cmd);
73 } 108 }
74 } 109 }
@@ -15,7 +15,6 @@ class Kernel extends ConsoleKernel @@ -15,7 +15,6 @@ class Kernel extends ConsoleKernel
15 */ 15 */
16 protected function schedule(Schedule $schedule) 16 protected function schedule(Schedule $schedule)
17 { 17 {
18 - $schedule->command('sync_file')->everyThirtyMinutes()->withoutOverlapping(1);//每半小时执行同步  
19 // 每日更新最新模块 18 // 每日更新最新模块
20 $schedule->command('template_label')->dailyAt('01:00')->withoutOverlapping(1);//最新模块 19 $schedule->command('template_label')->dailyAt('01:00')->withoutOverlapping(1);//最新模块
21 $schedule->command('popular_template_label')->dailyAt('01:30')->withoutOverlapping(1);//热门模块 20 $schedule->command('popular_template_label')->dailyAt('01:30')->withoutOverlapping(1);//热门模块
@@ -685,7 +685,20 @@ if (!function_exists('getImageUrl')) { @@ -685,7 +685,20 @@ if (!function_exists('getImageUrl')) {
685 if ($image_cdn == 0) {//v6链接 685 if ($image_cdn == 0) {//v6链接
686 $cosCdn = $cos['cdn2']; 686 $cosCdn = $cos['cdn2'];
687 } else { 687 } else {
688 - $cosCdn = ($storage_type == 0) ? $cos['cdn'] : $cos['cdn1']; 688 + switch ($storage_type) {
  689 + case 0:
  690 + $cosCdn = $cos['cdn'];
  691 + break;
  692 + case 1:
  693 + $cosCdn = $cos['cdn1'];
  694 + break;
  695 + case 2:
  696 + $cosCdn = $cos['cdn3'];
  697 + break;
  698 + default:
  699 + $cosCdn = $cos['cdn2'];
  700 + break;
  701 + }
689 } 702 }
690 $url = $cosCdn . $path; 703 $url = $cosCdn . $path;
691 } else { 704 } else {
@@ -731,7 +744,20 @@ if (!function_exists('getFileUrl')) { @@ -731,7 +744,20 @@ if (!function_exists('getFileUrl')) {
731 } 744 }
732 if ($location == 0) { 745 if ($location == 0) {
733 $cos = config('filesystems.disks.cos'); 746 $cos = config('filesystems.disks.cos');
734 - $cosCdn = ($storage_type == 0) ? $cos['cdn'] : $cos['cdn1']; 747 + switch ($storage_type) {
  748 + case 0:
  749 + $cosCdn = $cos['cdn'];
  750 + break;
  751 + case 1:
  752 + $cosCdn = $cos['cdn1'];
  753 + break;
  754 + case 2:
  755 + $cosCdn = $cos['cdn3'];
  756 + break;
  757 + default:
  758 + $cosCdn = $cos['cdn2'];
  759 + break;
  760 + }
735 return $cosCdn . $path; 761 return $cosCdn . $path;
736 } else { 762 } else {
737 $s3 = config('filesystems.disks.s3'); 763 $s3 = config('filesystems.disks.s3');
@@ -167,7 +167,7 @@ class Ticket5UploadDataController extends BaseController @@ -167,7 +167,7 @@ class Ticket5UploadDataController extends BaseController
167 } 167 }
168 //验证当前数据是否已提交 168 //验证当前数据是否已提交
169 $this->param['text'] = json_encode($this->param['text'], true); 169 $this->param['text'] = json_encode($this->param['text'], true);
170 - $this->pushTicketByBots($this->param['post_id'],$this->param['project_type']); 170 + $this->pushTicketByBots($this->param['post_id'],1);
171 if(isset($this->param['id']) && !empty($this->param['id'])){ 171 if(isset($this->param['id']) && !empty($this->param['id'])){
172 //执行编辑 172 //执行编辑
173 $info = $this->model->read(['id'=>$this->param['id']]); 173 $info = $this->model->read(['id'=>$this->param['id']]);
@@ -259,4 +259,25 @@ class TicketController extends BaseController @@ -259,4 +259,25 @@ class TicketController extends BaseController
259 } 259 }
260 $this->response('success',Code::SUCCESS,$data); 260 $this->response('success',Code::SUCCESS,$data);
261 } 261 }
  262 +
  263 + /**
  264 + * @remark :获取项目uuid
  265 + * @name :getProjectUuid
  266 + * @author :lyh
  267 + * @method :post
  268 + * @time :2025/11/19 11:35
  269 + */
  270 + public function getProjectUuid()
  271 + {
  272 + $this->request->validate([
  273 + 'table_id'=>'required',
  274 + 'project_cate'=>'required'
  275 + ],[
  276 + 'table_id.required' => '项目ID不能为空',
  277 + 'project_cate.required' => '项目类型不能为空'
  278 + ]);
  279 + $ticketProjectModel = new TicketProject();
  280 + $uuid = $ticketProjectModel->getValue(['table_id'=>$this->param['table_id'],'project_cate'=>$this->param['project_cate']],'uuid');
  281 + $this->response('success',Code::SUCCESS,['project_id'=>$uuid]);
  282 + }
262 } 283 }
@@ -200,4 +200,17 @@ class IndexController extends BaseController @@ -200,4 +200,17 @@ class IndexController extends BaseController
200 $data = Translate::translateSl($this->param['text']); 200 $data = Translate::translateSl($this->param['text']);
201 $this->response('success', Code::SUCCESS, $data); 201 $this->response('success', Code::SUCCESS, $data);
202 } 202 }
  203 +
  204 + /**
  205 + * @remark :pr报告下载
  206 + * @name :prInfoDownload
  207 + * @author :lyh
  208 + * @method :post
  209 + * @time :2025/11/18 15:00
  210 + */
  211 + public function prInfoDownload()
  212 + {
  213 + $url = 'http://crawl.scraper.waimaoq.com/export/issuewire?token=MT0CM7y4tdFTFTm';
  214 + $this->response('success', Code::SUCCESS, ['url'=>$url]);
  215 + }
203 } 216 }
@@ -271,11 +271,11 @@ class OptimizeController extends BaseController @@ -271,11 +271,11 @@ class OptimizeController extends BaseController
271 if($this->map['seo_plan'] == 0){ 271 if($this->map['seo_plan'] == 0){
272 $query = $query->where('gl_project_deploy_build.plan','!=',0); 272 $query = $query->where('gl_project_deploy_build.plan','!=',0);
273 }elseif(is_array($this->map['seo_plan'])){ 273 }elseif(is_array($this->map['seo_plan'])){
274 - $query = $query->whereIn('gl_project_deploy_build.seo_plan',$this->map['seo_plan'])  
275 - ->where(function ($subQuery) {  
276 - $subQuery->where('gl_project_deploy_build.plan', '=', 0)  
277 - ->orWhere('gl_project_deploy_build.seo_plan', '!=', 9);  
278 - });; 274 + $query = $query->whereIn('gl_project_deploy_build.seo_plan',$this->map['seo_plan']);
  275 +// ->where(function ($subQuery) {
  276 +// $subQuery->where('gl_project_deploy_build.plan', '=', 0)
  277 +// ->orWhere('gl_project_deploy_build.seo_plan', '!=', 9);
  278 +// });
279 }else{ 279 }else{
280 $query = $query->where('gl_project_deploy_build.seo_plan',$this->map['seo_plan']); 280 $query = $query->where('gl_project_deploy_build.seo_plan',$this->map['seo_plan']);
281 } 281 }
@@ -332,11 +332,11 @@ class ProjectController extends BaseController @@ -332,11 +332,11 @@ class ProjectController extends BaseController
332 } 332 }
333 } 333 }
334 if (isset($this->map['seo_plan'])) { 334 if (isset($this->map['seo_plan'])) {
335 - $query = $query->where('gl_project_deploy_build.seo_plan', '!=', 0)  
336 - ->where(function ($subQuery) {  
337 - $subQuery->where('gl_project_deploy_build.plan', '=', 0)  
338 - ->orWhere('gl_project_deploy_build.seo_plan', '!=', 9);  
339 - }); 335 + $query = $query->where('gl_project_deploy_build.seo_plan', '!=', 0);
  336 +// ->where(function ($subQuery) {
  337 +// $subQuery->where('gl_project_deploy_build.plan', '=', 0)
  338 +// ->orWhere('gl_project_deploy_build.seo_plan', '!=', 9);
  339 +// });
340 } 340 }
341 if (isset($this->map['site_status'])) { 341 if (isset($this->map['site_status'])) {
342 $query = $query->where('gl_project.site_status', $this->map['site_status']); 342 $query = $query->where('gl_project.site_status', $this->map['site_status']);
@@ -85,4 +85,22 @@ class TicketUploadDataController extends BaseController @@ -85,4 +85,22 @@ class TicketUploadDataController extends BaseController
85 $data = $this->logic->saveData(); 85 $data = $this->logic->saveData();
86 $this->response('success',Code::SUCCESS,$data); 86 $this->response('success',Code::SUCCESS,$data);
87 } 87 }
  88 +
  89 + /**
  90 + * @remark :删除数据
  91 + * @name :del
  92 + * @author :lyh
  93 + * @method :post
  94 + * @time :2025/11/14 11:05
  95 + */
  96 + public function del()
  97 + {
  98 + $this->request->validate([
  99 + 'id'=>'required',
  100 + ],[
  101 + 'id.required' => '主键ID不能为空',
  102 + ]);
  103 + $data = $this->logic->delData();
  104 + $this->response('success',Code::SUCCESS,$data);
  105 + }
88 } 106 }
@@ -118,7 +118,7 @@ class AsideTicketController extends BaseController @@ -118,7 +118,7 @@ class AsideTicketController extends BaseController
118 $manageIdArr = $manageHrModel->selectField(['entry_position' => ['in', [42, 43, 45, 48, 51]], 'status' => 1], 'manage_id'); 118 $manageIdArr = $manageHrModel->selectField(['entry_position' => ['in', [42, 43, 45, 48, 51]], 'status' => 1], 'manage_id');
119 } 119 }
120 $query->whereHas('logs', function ($q) use ($manageIdArr) { 120 $query->whereHas('logs', function ($q) use ($manageIdArr) {
121 - $q->whereIn('engineer_id', $manageIdArr); 121 + $q->whereIn('engineer_id', $manageIdArr)->where('is_engineer',1);
122 }); 122 });
123 }else{ 123 }else{
124 $manageIdArr = $manageHrModel->selectField(['dept_id'=>$this->param['dept_id'],'status'=>1],'manage_id'); 124 $manageIdArr = $manageHrModel->selectField(['dept_id'=>$this->param['dept_id'],'status'=>1],'manage_id');
@@ -17,12 +17,15 @@ use App\Models\CustomModule\CustomModule; @@ -17,12 +17,15 @@ use App\Models\CustomModule\CustomModule;
17 use App\Models\CustomModule\CustomModuleCategory; 17 use App\Models\CustomModule\CustomModuleCategory;
18 use App\Models\CustomModule\CustomModuleContent; 18 use App\Models\CustomModule\CustomModuleContent;
19 use App\Models\News\News; 19 use App\Models\News\News;
  20 +use App\Models\Product\Category;
  21 +use App\Models\Product\CategoryRelated;
20 use App\Models\Product\Product; 22 use App\Models\Product\Product;
21 use App\Models\Project\Project; 23 use App\Models\Project\Project;
22 use App\Models\RouteMap\RouteMap; 24 use App\Models\RouteMap\RouteMap;
23 use App\Models\WebSetting\SettingNum; 25 use App\Models\WebSetting\SettingNum;
24 use App\Models\WebSetting\Translate; 26 use App\Models\WebSetting\Translate;
25 use App\Models\WebSetting\TranslateKey; 27 use App\Models\WebSetting\TranslateKey;
  28 +use Illuminate\Support\Facades\Cache;
26 29
27 class TranslateController extends BaseController 30 class TranslateController extends BaseController
28 { 31 {
@@ -351,7 +354,20 @@ class TranslateController extends BaseController @@ -351,7 +354,20 @@ class TranslateController extends BaseController
351 if($v['route'] == 'products'){ 354 if($v['route'] == 'products'){
352 $count = $productModel->formatQuery(['status'=>1])->count(); 355 $count = $productModel->formatQuery(['status'=>1])->count();
353 }else{ 356 }else{
354 - $count = $productModel->formatQuery(['category_id'=>['like','%,'.$v['source_id'].',%'],'status'=>1])->count(); 357 + $catelists = Cache::get('product_category_trans');
  358 + if(!$catelists){
  359 + $cateModel = new Category();
  360 + $catelists = $cateModel->list(['status'=>1],'id',['id','pid']);
  361 + Cache::put('product_category_trans',$catelists,3600 * 24);
  362 + }
  363 + $ids = $this->getCategoryWithChildrenIds($catelists,$v['source_id']);
  364 + if (empty($ids) || !is_array($ids)) {
  365 + // 处理空值情况,返回0或者默认值
  366 + $count = 0;
  367 + } else {
  368 + $cateRelateModel = new CategoryRelated();
  369 + $count = $cateRelateModel->whereIn('cate_id', $ids)->distinct('product_id')->count();
  370 + }
355 } 371 }
356 $this->pageSixList($data,$count,$v,1,15); 372 $this->pageSixList($data,$count,$v,1,15);
357 break; 373 break;
@@ -474,4 +490,27 @@ class TranslateController extends BaseController @@ -474,4 +490,27 @@ class TranslateController extends BaseController
474 } 490 }
475 return true; 491 return true;
476 } 492 }
  493 +
  494 + /**
  495 + * 迭代方式获取分类及所有子分类的总数
  496 + * @param array $categories 所有分类数据
  497 + * @param int $categoryId 分类ID
  498 + * @return int 分类总数
  499 + */
  500 + public function getCategoryWithChildrenIds($categories, $categoryId) {
  501 + $ids = []; // 存储所有ID的数组
  502 + $queue = [$categoryId]; // 待处理的ID队列
  503 + while (!empty($queue)) {
  504 + $currentId = array_shift($queue);
  505 + // 将当前ID添加到结果数组
  506 + $ids[] = $currentId;
  507 + // 查找所有子分类
  508 + foreach ($categories as $category) {
  509 + if (isset($category['pid']) && $category['pid'] == $currentId) {
  510 + $queue[] = $category['id']; // 将子分类ID加入队列
  511 + }
  512 + }
  513 + }
  514 + return $ids;
  515 + }
477 } 516 }
@@ -76,12 +76,16 @@ class GeoLinkLogic extends BaseLogic @@ -76,12 +76,16 @@ class GeoLinkLogic extends BaseLogic
76 if(!empty($this->param['data'])){ 76 if(!empty($this->param['data'])){
77 $data = []; 77 $data = [];
78 foreach ($this->param['data'] as $item){ 78 foreach ($this->param['data'] as $item){
79 - $data[] = [  
80 - 'project_id'=>$this->param['project_id'],  
81 - 'da'=>$item['da'] ?? 0,  
82 - 'url'=>$item['url'],  
83 - 'send_time'=>$item['send_time']  
84 - ]; 79 + //查看当前Url是否存在
  80 + $info = $this->model->read(['url'=>$item['url'],'type'=>$this->model::TYPE_NEWS,'project_id'=>$this->param['project_id']]);
  81 + if($info === false){
  82 + $data[] = [
  83 + 'project_id'=>$this->param['project_id'],
  84 + 'da'=>$item['da'] ?? 0,
  85 + 'url'=>$item['url'],
  86 + 'send_time'=>$item['send_time']
  87 + ];
  88 + }
85 } 89 }
86 $this->model->insertAll($data); 90 $this->model->insertAll($data);
87 } 91 }
@@ -84,18 +84,41 @@ class GeoQuestionLogic extends BaseLogic @@ -84,18 +84,41 @@ class GeoQuestionLogic extends BaseLogic
84 */ 84 */
85 public function saveGeoQuestion(){ 85 public function saveGeoQuestion(){
86 //处理数据 86 //处理数据
87 - $this->param['question'] = json_encode($this->param['question'] ?? [],true); 87 + $count = count($this->param['question']);
  88 + $question = $this->param['question'];
88 $this->param['url'] = json_encode($this->param['url'] ?? [],true); 89 $this->param['url'] = json_encode($this->param['url'] ?? [],true);
89 $this->param['keywords'] = json_encode($this->param['keywords'] ?? [],true); 90 $this->param['keywords'] = json_encode($this->param['keywords'] ?? [],true);
90 - //执行时间设置为今天  
91 - if(isset($this->param['id']) && !empty($this->param['id'])){  
92 - $id = $this->param['id'];  
93 - $this->model->edit($this->param,['id'=>$id]); 91 + if($count <= 20){
  92 + if(isset($this->param['id']) && !empty($this->param['id'])){
  93 + $id = $this->param['id'];
  94 + $this->model->edit($this->param,['id'=>$id]);
  95 + }else{
  96 + $this->param['next_time'] = date('Y-m-d');
  97 + $id = $this->model->addReturnId($this->param);
  98 + }
  99 + return $this->success(['id'=>$id]);
94 }else{ 100 }else{
95 - $this->param['next_time'] = date('Y-m-d');  
96 - $id = $this->model->addReturnId($this->param); 101 + $chunks = array_chunk($question, 20);
  102 + if(isset($this->param['id']) && !empty($this->param['id'])){
  103 + foreach ($chunks as $index => $chunk) {
  104 + $this->param['question'] = json_encode($chunk ?? [],true);
  105 + if($index == 0){
  106 + $id = $this->param['id'];
  107 + $this->model->edit($this->param,['id'=>$id]);
  108 + }else{
  109 + unset($this->param['id']);
  110 + $id = $this->model->addReturnId($this->param);
  111 + }
  112 + }
  113 + }else{
  114 + $this->param['next_time'] = date('Y-m-d');
  115 + foreach ($chunks as $chunk) {
  116 + $this->param['question'] = json_encode($chunk ?? [],true);
  117 + $id = $this->model->addReturnId($this->param);
  118 + }
  119 + }
  120 + return $this->success(['id'=>$id]);
97 } 121 }
98 - return $this->success(['id'=>$id]);  
99 } 122 }
100 123
101 /** 124 /**
@@ -142,10 +142,12 @@ class TicketUploadDataLogic extends BaseLogic @@ -142,10 +142,12 @@ class TicketUploadDataLogic extends BaseLogic
142 if($info === false){ 142 if($info === false){
143 $this->fail('当前数据不存在或已被删除'); 143 $this->fail('当前数据不存在或已被删除');
144 } 144 }
145 - ProjectServer::useProject($info['project_id']);  
146 - $info['text']['cate_name'] = $this->cateText($info['type'],$info['text']['category_id'] ?? [],$info['text']['keyword_id'] ?? [],true);  
147 - $info = $this->getHandleFileImage($info);  
148 - DB::disconnect('custom_mysql'); 145 + if($info['project_type'] == $this->model::TYPE_SIX){
  146 + ProjectServer::useProject($info['project_id']);
  147 + $info['text']['cate_name'] = $this->cateText($info['type'],$info['text']['category_id'] ?? [],$info['text']['keyword_id'] ?? [],true);
  148 + $info = $this->getHandleFileImage($info);
  149 + DB::disconnect('custom_mysql');
  150 + }
149 return $this->success($info); 151 return $this->success($info);
150 } 152 }
151 153
@@ -395,4 +397,17 @@ class TicketUploadDataLogic extends BaseLogic @@ -395,4 +397,17 @@ class TicketUploadDataLogic extends BaseLogic
395 } 397 }
396 return $this->success(); 398 return $this->success();
397 } 399 }
  400 +
  401 + /**
  402 + * @remark :删除
  403 + * @name :delData
  404 + * @author :lyh
  405 + * @method :post
  406 + * @time :2025/11/14 11:04
  407 + */
  408 + public function delData()
  409 + {
  410 + $this->model->del(['id'=>['in',$this->param['id']]]);
  411 + return $this->success();
  412 + }
398 } 413 }
@@ -44,13 +44,16 @@ class LinkDataLogic extends BaseLogic @@ -44,13 +44,16 @@ class LinkDataLogic extends BaseLogic
44 public function batchSave(){ 44 public function batchSave(){
45 $data = []; 45 $data = [];
46 foreach ($this->param['data'] as $v){ 46 foreach ($this->param['data'] as $v){
47 - $data[] = [  
48 - 'url'=>$v['url'],  
49 - 'da'=>$v['da_values'],  
50 - 'type'=>GeoLink::TYPE_LINK,  
51 - 'project_id'=>$this->user['project_id'],  
52 - 'send_time'=>$v['send_time'] ?? date('Y-m-d H:i:s')  
53 - ]; 47 + $info = $this->model->read(['da'=>$v['da_values'],'project_id'=>$this->user['project_id'],'type'=>GeoLink::TYPE_LINK]);
  48 + if($info === false){
  49 + $data[] = [
  50 + 'url'=>$v['url'],
  51 + 'da'=>$v['da_values'],
  52 + 'type'=>GeoLink::TYPE_LINK,
  53 + 'project_id'=>$this->user['project_id'],
  54 + 'send_time'=>$v['send_time'] ?? date('Y-m-d H:i:s')
  55 + ];
  56 + }
54 } 57 }
55 if(!empty($data)){ 58 if(!empty($data)){
56 $this->model->insertAll($data); 59 $this->model->insertAll($data);
@@ -44,8 +44,8 @@ class GeoConfirm extends Base @@ -44,8 +44,8 @@ class GeoConfirm extends Base
44 public static function typeMapping() 44 public static function typeMapping()
45 { 45 {
46 return [ 46 return [
47 - self::TYPE_TITLE => '核心关键词问题已整理,请查看并确认',  
48 - self::TYPE_KEYWORD => '文章标题已整理,请查看并确认' 47 + self::TYPE_TITLE => '文章标题已整理,请查看并确认',
  48 + self::TYPE_KEYWORD => '核心关键词问题已整理,请查看并确认'
49 ]; 49 ];
50 } 50 }
51 51
@@ -27,4 +27,5 @@ class AiBlogTask extends Base @@ -27,4 +27,5 @@ class AiBlogTask extends Base
27 const TYPE_AUTHOR = 1; 27 const TYPE_AUTHOR = 1;
28 const TYPE_BLOG = 2; 28 const TYPE_BLOG = 2;
29 const TYPE_AUTHOR_ID = 3;//根据对应id页面 29 const TYPE_AUTHOR_ID = 3;//根据对应id页面
  30 + const TYPE_LIST = 4;//更新列表页
30 } 31 }
@@ -65,7 +65,7 @@ class MessagePush extends Base @@ -65,7 +65,7 @@ class MessagePush extends Base
65 } 65 }
66 66
67 //特殊处理, 要求任何时候收到询盘都要及时推送到群里面 67 //特殊处理, 要求任何时候收到询盘都要及时推送到群里面
68 - $special_project_ids = [650, 2045, 916]; 68 + $special_project_ids = [650, 2045, 916, 3587, 568];
69 //9-21 点,每条消息及时通知 69 //9-21 点,每条消息及时通知
70 //21-第二天 9 点,整合一起通知 70 //21-第二天 9 点,整合一起通知
71 $hour = date('H', strtotime($submit_at)); 71 $hour = date('H', strtotime($submit_at));
@@ -549,8 +549,8 @@ class SyncSubmitTaskService @@ -549,8 +549,8 @@ class SyncSubmitTaskService
549 549
550 //数据都是空的 550 //数据都是空的
551 $is_all_empty = true; 551 $is_all_empty = true;
552 - foreach ($data['data'] as $item){  
553 - if(is_string($item) && Str::startsWith(strtolower($item),'globalso-')){ 552 + foreach ($data['data'] as $index=>$item){
  553 + if(is_string($item) && Str::startsWith(strtolower($index),'globalso-')){
554 continue; 554 continue;
555 } 555 }
556 if(!empty($item)){ 556 if(!empty($item)){
@@ -84,6 +84,8 @@ Route::get('/get_manage_by_domain', [\App\Http\Controllers\Api\PrivateController @@ -84,6 +84,8 @@ Route::get('/get_manage_by_domain', [\App\Http\Controllers\Api\PrivateController
84 84
85 // 获取信息通过商户号 85 // 获取信息通过商户号
86 Route::any('/get_project_by_mch_id', [\App\Http\Controllers\Api\PrivateController::class, 'getProjectByMchId']); 86 Route::any('/get_project_by_mch_id', [\App\Http\Controllers\Api\PrivateController::class, 'getProjectByMchId']);
  87 +//获取项目uuid
  88 +Route::any('/getProjectUuid',[\App\Http\Controllers\Api\WorkOrder\TicketController::class,'getProjectUuid']);
87 89
88 // B端,渠道在企微群操作-售后工单 90 // B端,渠道在企微群操作-售后工单
89 Route::prefix('tickets')->group(function () { 91 Route::prefix('tickets')->group(function () {
@@ -18,6 +18,7 @@ Route::middleware(['aloginauth'])->group(function () { @@ -18,6 +18,7 @@ Route::middleware(['aloginauth'])->group(function () {
18 Route::any('/getCountry', [Aside\Com\CNoticeController::class, 'getCountry'])->name('admin.getCountry'); 18 Route::any('/getCountry', [Aside\Com\CNoticeController::class, 'getCountry'])->name('admin.getCountry');
19 Route::any('/getDynamicPassword', [Aside\Com\IndexController::class, 'getDynamicPassword'])->name('admin.getDynamicPassword'); 19 Route::any('/getDynamicPassword', [Aside\Com\IndexController::class, 'getDynamicPassword'])->name('admin.getDynamicPassword');
20 Route::any('/notAiHumanizer', [Aside\Com\IndexController::class, 'notAiHumanizer'])->name('admin.notAiHumanizer'); 20 Route::any('/notAiHumanizer', [Aside\Com\IndexController::class, 'notAiHumanizer'])->name('admin.notAiHumanizer');
  21 + Route::any('/prInfoDownload', [Aside\Com\IndexController::class, 'prInfoDownload'])->name('admin.prInfoDownload');//pr报告下载
21 //会员相关 22 //会员相关
22 Route::prefix('user')->group(function () { 23 Route::prefix('user')->group(function () {
23 //会员管理 24 //会员管理
@@ -680,6 +681,7 @@ Route::middleware(['aloginauth'])->group(function () { @@ -680,6 +681,7 @@ Route::middleware(['aloginauth'])->group(function () {
680 Route::any('/', [Aside\Ticket\TicketUploadDataController::class,'lists'])->name('ticket_upload_lists'); 681 Route::any('/', [Aside\Ticket\TicketUploadDataController::class,'lists'])->name('ticket_upload_lists');
681 Route::any('/save', [Aside\Ticket\TicketUploadDataController::class,'save'])->name('ticket_upload_save'); 682 Route::any('/save', [Aside\Ticket\TicketUploadDataController::class,'save'])->name('ticket_upload_save');
682 Route::any('/detail', [Aside\Ticket\TicketUploadDataController::class,'detail'])->name('ticket_upload_detail'); 683 Route::any('/detail', [Aside\Ticket\TicketUploadDataController::class,'detail'])->name('ticket_upload_detail');
  684 + Route::any('/del', [Aside\Ticket\TicketUploadDataController::class,'del'])->name('ticket_upload_del');
683 }); 685 });
684 //岗位管理 686 //岗位管理
685 Route::prefix('entry_position')->group(function () { 687 Route::prefix('entry_position')->group(function () {