作者 赵彬吉
@@ -296,13 +296,13 @@ class AiBlogTask extends Command @@ -296,13 +296,13 @@ class AiBlogTask extends Command
296 $domain = $domainModel->getProjectIdDomain($project_id); 296 $domain = $domainModel->getProjectIdDomain($project_id);
297 if (empty($domain)) { 297 if (empty($domain)) {
298 $this->output('send: 域名不存在, project id: ' . $project_id); 298 $this->output('send: 域名不存在, project id: ' . $project_id);
299 - return true; 299 + continue;
300 } 300 }
301 //判断是否是自建站服务器,如果是,不请求C端接口,数据直接入库 301 //判断是否是自建站服务器,如果是,不请求C端接口,数据直接入库
302 $project_info = $project_model->read(['id'=>$project_id],['serve_id']); 302 $project_info = $project_model->read(['id'=>$project_id],['serve_id']);
303 if(!$project_info){ 303 if(!$project_info){
304 $this->output('send: 项目不存在, project id: ' . $project_id); 304 $this->output('send: 项目不存在, project id: ' . $project_id);
305 - return true; 305 + continue;
306 } 306 }
307 $serve_ip_model = new ServersIp(); 307 $serve_ip_model = new ServersIp();
308 $serve_ip_info = $serve_ip_model->read(['id'=>$project_info['serve_id']],['servers_id']); 308 $serve_ip_info = $serve_ip_model->read(['id'=>$project_info['serve_id']],['servers_id']);
@@ -79,9 +79,11 @@ class AfterDayCount extends Command @@ -79,9 +79,11 @@ class AfterDayCount extends Command
79 ->where('gl_project.delete_status',0) 79 ->where('gl_project.delete_status',0)
80 ->where('gl_project.created_at','<=',$todayMidnight) 80 ->where('gl_project.created_at','<=',$todayMidnight)
81 ->where('gl_project.is_remain_today',1) 81 ->where('gl_project.is_remain_today',1)
  82 + ->where('gl_project_deploy_build.plan','!=',0)
82 ->whereIn('gl_project_deploy_optimize.optimist_mid',$idArr) 83 ->whereIn('gl_project_deploy_optimize.optimist_mid',$idArr)
83 ->whereIn('gl_project.type',[2,4]) 84 ->whereIn('gl_project.type',[2,4])
84 ->leftJoin('gl_project_deploy_optimize', 'gl_project.id', '=', 'gl_project_deploy_optimize.project_id') 85 ->leftJoin('gl_project_deploy_optimize', 'gl_project.id', '=', 'gl_project_deploy_optimize.project_id')
  86 + ->leftJoin('gl_project_deploy_build', 'gl_project.id', '=', 'gl_project_deploy_build.project_id')
85 ->whereRaw("FIND_IN_SET('2', gl_project.level) = 0 AND FIND_IN_SET('3', gl_project.level) = 0") 87 ->whereRaw("FIND_IN_SET('2', gl_project.level) = 0 AND FIND_IN_SET('3', gl_project.level) = 0")
86 ->whereRaw("FIND_IN_SET('7', gl_project_deploy_optimize.special) = 0 AND FIND_IN_SET('8', gl_project_deploy_optimize.special) = 0") 88 ->whereRaw("FIND_IN_SET('7', gl_project_deploy_optimize.special) = 0 AND FIND_IN_SET('8', gl_project_deploy_optimize.special) = 0")
87 ->count(); 89 ->count();
@@ -102,7 +104,9 @@ class AfterDayCount extends Command @@ -102,7 +104,9 @@ class AfterDayCount extends Command
102 ->where('gl_project.created_at','<=',$threeMonthsAgo) 104 ->where('gl_project.created_at','<=',$threeMonthsAgo)
103 ->whereIn('gl_project_deploy_optimize.optimist_mid',$idArr) 105 ->whereIn('gl_project_deploy_optimize.optimist_mid',$idArr)
104 ->whereIn('gl_project.type',[2,4]) 106 ->whereIn('gl_project.type',[2,4])
  107 + ->where('gl_project_deploy_build.plan','!=',0)
105 ->leftJoin('gl_project_deploy_optimize', 'gl_project.id', '=', 'gl_project_deploy_optimize.project_id') 108 ->leftJoin('gl_project_deploy_optimize', 'gl_project.id', '=', 'gl_project_deploy_optimize.project_id')
  109 + ->leftJoin('gl_project_deploy_build', 'gl_project.id', '=', 'gl_project_deploy_build.project_id')
106 ->whereRaw("FIND_IN_SET('2', gl_project.level) = 0 AND FIND_IN_SET('3', gl_project.level) = 0") 110 ->whereRaw("FIND_IN_SET('2', gl_project.level) = 0 AND FIND_IN_SET('3', gl_project.level) = 0")
107 ->whereRaw("FIND_IN_SET('7', gl_project_deploy_optimize.special) = 0 AND FIND_IN_SET('8', gl_project_deploy_optimize.special) = 0") 111 ->whereRaw("FIND_IN_SET('7', gl_project_deploy_optimize.special) = 0 AND FIND_IN_SET('8', gl_project_deploy_optimize.special) = 0")
108 ->count(); 112 ->count();
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: zhl
  5 + * Date: 2025/4/15
  6 + * Time: 10:25
  7 + */
  8 +namespace App\Console\Commands\Monitor;
  9 +
  10 +use App\Models\Domain\DomainInfo;
  11 +use App\Models\Product\Keyword;
  12 +use App\Models\Project\OnlineCheck;
  13 +use App\Models\Project\Project;
  14 +use App\Repositories\ToolRepository;
  15 +use App\Services\DingService;
  16 +use App\Services\ProjectServer;
  17 +use Illuminate\Console\Command;
  18 +use Illuminate\Support\Facades\DB;
  19 +
  20 +/**
  21 + * Class Supervisory
  22 + * @package App\Console\Commands\Monitor
  23 + */
  24 +class Supervisory extends Command
  25 +{
  26 + /**
  27 + * The name and signature of the console command.
  28 + *
  29 + * @var string
  30 + */
  31 + protected $signature = 'monitor_supervisory';
  32 +
  33 + /**
  34 + * The console command description.
  35 + *
  36 + * @var string
  37 + */
  38 + protected $description = '监控脚本';
  39 +
  40 + /**
  41 + * Supervisory constructor.
  42 + */
  43 + public function __construct()
  44 + {
  45 + parent::__construct();
  46 + }
  47 +
  48 + /**
  49 + * @return bool
  50 + */
  51 + public function handle()
  52 + {
  53 + list($robots_ids, $close_ids) = $this->getRobotsProject();
  54 + $spot_projects = $this->getSpotCheck();
  55 + #TODO robots、 TDK、 top-search、 top-blog
  56 + list($error_num, $error, $error_url, $page_404, $tdk_error) = $this->spotCheckPage($spot_projects);
  57 + $this->sendMessage($robots_ids, $close_ids, $error_num, $error, $error_url, $page_404, $tdk_error, $spot_projects);
  58 + return true;
  59 + }
  60 +
  61 + /**
  62 + * 抽查数据
  63 + * @param $projects
  64 + * @return array
  65 + */
  66 + public function spotCheckPage($projects)
  67 + {
  68 + $error_num = 0;
  69 + $error = [];
  70 + $error_url = [];
  71 + $page_404 = [];
  72 + $tdk_error = [];
  73 + $tdk = [];
  74 + foreach ($projects as $project) {
  75 + $this->output('抽查项目:' . $project['project_id'] . ', 域名:' . $project['domain']);
  76 +
  77 + $host = 'https://' . $project['domain'] . '/';
  78 +
  79 + // AI blog页面
  80 + $blog_url = $host . 'top-blog/';
  81 + list($blog_code, $blog_html) = app(ToolRepository::class)->curlRequest($blog_url, [], $method = 'GET', [], 10);
  82 + if ($blog_code != 200) {
  83 + $error_num++;
  84 + array_push($error_url, $blog_url);
  85 + } else {
  86 + $tdk = $this->analysisHtml($blog_html);
  87 + if (FALSE == is_array($tdk)) {
  88 + $error_num++;
  89 + array_push($error, $blog_url);
  90 + } else if (empty($tdk['title'])) {
  91 + array_push($tdk_error, $blog_url);
  92 + } else if (FALSE !== strpos('404', $tdk['title'])){
  93 + array_push($page_404, $blog_url);
  94 + }
  95 + }
  96 +
  97 + // top search页面
  98 + $search_url = $host . 'top-search/';
  99 + list($search_code, $search_html) = app(ToolRepository::class)->curlRequest($search_url, [], $method = 'GET', [], 10);
  100 + if ($search_code != 200) {
  101 + $error_num++;
  102 + array_push($error_url, $search_url);
  103 + } else {
  104 + $tdk = $this->analysisHtml($search_html);
  105 + if (FALSE == is_array($tdk)) {
  106 + $error_num++;
  107 + array_push($error, $search_url);
  108 + } else if (empty($tdk['title'])) {
  109 + array_push($tdk_error, $search_url);
  110 + } else if (FALSE !== strpos('404', $tdk['title'])){
  111 + array_push($page_404, $search_url);
  112 + }
  113 + }
  114 +
  115 + // 关键词聚合页
  116 + foreach ($project['keyword'] as $item) {
  117 + $keyword_url = $host . $item['route'] . '/';
  118 + $this->output('抽查url:' . $keyword_url);
  119 + list($keyword_code, $keyword_html) = app(ToolRepository::class)->curlRequest($keyword_url, [], $method = 'GET', [], 10);
  120 + if ($keyword_code != 200) {
  121 + // 请求失败
  122 + $error_num++;
  123 + array_push($error_url, $keyword_url);
  124 + } else {
  125 + $tdk = $this->analysisHtml($keyword_html);
  126 + if (FALSE == is_array($tdk)) {
  127 + // 解析HTML失败
  128 + $error_num++;
  129 + array_push($error, $keyword_url);
  130 + } else if (empty($tdk['title'])) {
  131 + array_push($tdk_error, $keyword_url);
  132 + } else {
  133 + if (FALSE !== strpos('404', $tdk['title'])) {
  134 + // 404页面
  135 + array_push($page_404, $keyword_url);
  136 + } else {
  137 + // TDK验证
  138 + $tdk = array_filter(array_unique($tdk));
  139 + if (count($tdk) < 3)
  140 + array_push($tdk_error, $keyword_url);
  141 + }
  142 + }
  143 + }
  144 + }
  145 +
  146 + }
  147 + return [$error_num, $error, $error_url, $page_404, $tdk_error];
  148 + }
  149 +
  150 + /**
  151 + * 获取robots信息
  152 + * @return array
  153 + */
  154 + public function getRobotsProject()
  155 + {
  156 + $this->output('统计robots start');
  157 +
  158 + $ids = Project::where(['robots' => 1])->pluck('id')->toArray();
  159 + file_put_contents(storage_path('data/robots/' . date('Ymd'). '.json'), json_encode($ids, 256));
  160 + if (FALSE == is_file(storage_path('data/robots/' . date('Ymd', strtotime('-1 day')). '.json')))
  161 + return [$ids, []];
  162 +
  163 + $string = file_get_contents(storage_path('data/robots/' . date('Ymd', strtotime('-1 day')). '.json'));
  164 + $yesterday_robots_ids = json_decode($string, true) ?: [];
  165 + $close_ids = [];
  166 + foreach ($yesterday_robots_ids as $id) {
  167 + if (FALSE == in_array($id, $ids)) {
  168 + array_push($close_ids, $id);
  169 + }
  170 + }
  171 + return [$ids, $close_ids];
  172 + }
  173 +
  174 + /**
  175 + * 随机获取抽查项目
  176 + * @return array|int|string
  177 + */
  178 + public function getRandProject()
  179 + {
  180 + $this->output('随机获取项目抽查');
  181 +
  182 + $ids = Project::leftJoin('gl_project_deploy_optimize as b', 'gl_project.id', '=', 'b.project_id')
  183 + ->leftJoin('gl_project_online_check as c', 'gl_project.id', '=', 'c.project_id')
  184 + ->leftJoin('gl_domain_info as d', 'gl_project.id', '=', 'd.project_id')
  185 + ->where('gl_project.type', Project::TYPE_TWO)
  186 + ->where('gl_project.extend_type', 0) // 是否续费是由extend_type字段控制
  187 + ->where('gl_project.delete_status', Project::IS_DEL_FALSE)
  188 + ->where(function ($subQuery) {
  189 + $subQuery->orwhere('c.qa_status', OnlineCheck::STATUS_ONLINE_TRUE)->orwhere('gl_project.is_upgrade', Project::IS_UPGRADE_TRUE);
  190 + })
  191 + ->pluck('gl_project.id')
  192 + ->toArray();
  193 + $project_ids = array_rand($ids, 10);
  194 + return $project_ids;
  195 + }
  196 +
  197 + /**
  198 + * 获取抽查项目数据
  199 + * @return mixed
  200 + */
  201 + public function getSpotCheck()
  202 + {
  203 + $project_ids = $this->getRandProject();
  204 + $projects = DomainInfo::whereIn('project_id', $project_ids)->get(['project_id', 'domain'])->toArray();
  205 + foreach ($projects as &$project) {
  206 + ProjectServer::useProject($project['project_id']);
  207 + $keyword = Keyword::where(['project_id' => $project['project_id'], 'status' => Keyword::STATUS_ACTIVE])->inRandomOrder()->take(10)->get(['id', 'title', 'seo_title', 'seo_keywords', 'seo_description', 'route']);
  208 + DB::disconnect('custom_mysql');
  209 + if ($keyword->isEmpty()) {
  210 + $keyword = [];
  211 + } else {
  212 + $keyword = $keyword->toArray();
  213 + }
  214 + $project['keyword'] = $keyword;
  215 + }
  216 + return $projects;
  217 + }
  218 +
  219 + /**
  220 + * 获取页面TDK 分析请求数据
  221 + * @param $html
  222 + * @return array|string
  223 + */
  224 + public function analysisHtml($html)
  225 + {
  226 + $result = [];
  227 + if (empty($html))
  228 + return $result;
  229 + try {
  230 + $dom = new \DOMDocument();
  231 + @$dom->loadHTML($html);
  232 +
  233 + $title = $dom->getElementsByTagName('title');
  234 + $metas = $dom->getElementsByTagName('meta');
  235 + $result['title'] = $title->length > 0 ? trim($title->item(0)->nodeValue) : '';
  236 + foreach ($metas as $meta) {
  237 + $name = strtolower($meta->getAttribute('name'));
  238 + $content = $meta->getAttribute('content');
  239 +
  240 + if ($name === 'description') {
  241 + $result['description'] = trim($content);
  242 + } elseif ($name === 'keywords') {
  243 + $result['keywords'] = trim($content);
  244 + }
  245 + }
  246 + // 解析页面, 使用完成, 手动释放内存变量
  247 + unset($title);
  248 + unset($metas);
  249 + unset($dom);
  250 + return $result;
  251 + } catch (\Exception $e) {
  252 + return '解析HTML失败:' . $e->getMessage();
  253 + }
  254 + }
  255 +
  256 + public function sendMessage($robots_ids, $close_ids, $error_num, $error, $error_url, $page_404, $tdk_error, $spot_projects)
  257 + {
  258 + $tmp = compact('robots_ids', 'close_ids', 'error_num', 'error', 'error_url', 'page_404', 'tdk_error', 'spot_projects');
  259 + file_put_contents(storage_path('data/robots/' . date('Ymd'). 'log.json'), json_encode($tmp, 256));
  260 + unset($tmp);
  261 +
  262 + $domain = array_column($spot_projects, 'domain');
  263 + $domain = array_unique(array_filter($domain));
  264 +
  265 + $message[] = '开启robots项目数:' . count($robots_ids);
  266 + $message[] = '关闭robots项目:' . ($close_ids ? implode(',', $close_ids) : '无');
  267 + $message[] = '抽查项目数量: ' . count($domain);
  268 + $message[] = 'top-blog: ' . count($domain);
  269 + $message[] = 'top-search: ' . count($domain);
  270 + $message[] = '抽查错误次数:' . $error_num;
  271 + $message[] = '抽查项目域名: ' . implode(' 、 ', $domain);
  272 + $message[] = '请求失败链接: ' . implode(' 、 ', $error_url);
  273 + $message[] = '页面失败链接: ' . implode(' 、 ', $error);
  274 + $message[] = '404页面链接: ' . implode(' 、 ', $page_404);
  275 + $message[] = 'TDK错误链接: ' . implode(' 、 ', $tdk_error);
  276 +
  277 + $msg = implode(PHP_EOL, $message);
  278 +
  279 + $link = 'https://oapi.dingtalk.com/robot/send?access_token=3927b42d072972fcf572e7b01728bf3e1390e08094d6f77c5f28bfd85b19f09f';
  280 + $dingService = new DingService();
  281 + $body = [
  282 + 'keyword' => '项目数据推送',
  283 + 'msg' => $msg,
  284 + 'isAtAll' => false, // 是否@所有人
  285 + ];
  286 + $dingService->handle($body, $link);
  287 + }
  288 +
  289 + public function output($message)
  290 + {
  291 + echo date('Y-m-d H:i:s') . ' ' . $message . PHP_EOL;
  292 + }
  293 +}
  1 +<?php
  2 +/**
  3 + * @remark :
  4 + * @name :CheckListController.php
  5 + * @author :lyh
  6 + * @method :post
  7 + * @time :2025/4/17 9:25
  8 + */
  9 +
  10 +namespace App\Http\Controllers\Aside\Optimize;
  11 +
  12 +use App\Enums\Common\Code;
  13 +use App\Http\Controllers\Aside\BaseController;
  14 +use App\Models\Project\OptimizeCheckList;
  15 +use Illuminate\Http\Request;
  16 +
  17 +/**
  18 + * @remark :保存清单
  19 + * @name :CheckListController
  20 + * @author :lyh
  21 + * @method :post
  22 + * @time :2025/4/17 9:25
  23 + */
  24 +class CheckListController extends BaseController
  25 +{
  26 + public function __construct(Request $request)
  27 + {
  28 + parent::__construct($request);
  29 + $this->model = new OptimizeCheckList();
  30 + }
  31 +
  32 + /**
  33 + * @remark :获取分页检查清单数据
  34 + * @name :lists
  35 + * @author :lyh
  36 + * @method :post
  37 + * @time :2025/4/17 9:31
  38 + */
  39 + public function lists(){
  40 + $field = ['id','status','sort','text','created_at'];
  41 + $data = $this->model->lists($this->map,$this->page,$this->row,'id',$field);
  42 + $this->response('success',Code::SUCCESS,$data);
  43 + }
  44 +
  45 + /**
  46 + * @remark :获取数据详情
  47 + * @name :info
  48 + * @author :lyh
  49 + * @method :post
  50 + * @time :2025/4/17 16:18
  51 + */
  52 + public function info(){
  53 + $this->request->validate([
  54 + 'id'=>'required',
  55 + ],[
  56 + 'id.required' => '主键不能为空',
  57 + ]);
  58 + $data = $this->model->read($this->map);
  59 + $this->response('success',Code::SUCCESS,$data);
  60 + }
  61 +
  62 + /**
  63 + * @remark :保存检查清单
  64 + * @name :save
  65 + * @author :lyh
  66 + * @method :post
  67 + * @time :2025/4/17 9:32
  68 + */
  69 + public function save(){
  70 + if(isset($this->param['id']) && !empty($this->param['id'])){
  71 + $id = $this->param['id'];
  72 + $this->model->edit($this->param,['id'=>$this->param['id']]);
  73 + }else{
  74 + $id = $this->model->addReturnId($this->param);
  75 + }
  76 + $this->response('success',Code::SUCCESS,['id'=>$id]);
  77 + }
  78 +
  79 + /**
  80 + * @remark :修改状态
  81 + * @name :status
  82 + * @author :lyh
  83 + * @method :post
  84 + * @time :2025/4/17 9:48
  85 + */
  86 + public function status(){
  87 + $this->request->validate([
  88 + 'id'=>'required',
  89 + 'status'=>'required'
  90 + ],[
  91 + 'id.required' => '主键不能为空',
  92 + 'status.required' => '状态不能为空',
  93 + ]);
  94 + $data = $this->model->edit(['status'=>$this->param['status']],['id'=>$this->param['id']]);
  95 + $this->response('success',Code::SUCCESS,$data);
  96 + }
  97 +
  98 + /**
  99 + * @remark :删除数据
  100 + * @name :del
  101 + * @author :lyh
  102 + * @method :post
  103 + * @time :2025/4/17 9:48
  104 + */
  105 + public function del(){
  106 + $this->request->validate([
  107 + 'id'=>'required',
  108 + ],[
  109 + 'id.required' => '主键不能为空',
  110 + ]);
  111 + if(!is_array($this->param['id'])){
  112 + $this->param['id'] = ['in',[$this->param['id']]];
  113 + }
  114 + $data = $this->model->del($this->map);
  115 + $this->response('success',Code::SUCCESS,$data);
  116 + }
  117 +}
  1 +<?php
  2 +/**
  3 + * @remark :
  4 + * @name :CheckLogController.php
  5 + * @author :lyh
  6 + * @method :post
  7 + * @time :2025/4/17 10:07
  8 + */
  9 +
  10 +namespace App\Http\Controllers\Aside\Optimize;
  11 +
  12 +use App\Enums\Common\Code;
  13 +use App\Http\Controllers\Aside\BaseController;
  14 +use App\Models\Project\OptimizeCheckLog;
  15 +use Illuminate\Http\Request;
  16 +
  17 +/**
  18 + * @remark :检查日志
  19 + * @name :CheckLogController
  20 + * @author :lyh
  21 + * @method :post
  22 + * @time :2025/4/17 10:15
  23 + */
  24 +class CheckLogController extends BaseController
  25 +{
  26 + public function __construct(Request $request)
  27 + {
  28 + parent::__construct($request);
  29 + $this->model = new OptimizeCheckLog();
  30 + }
  31 +
  32 + /**
  33 + * @remark :检查日志列表
  34 + * @name :lists
  35 + * @author :lyh
  36 + * @method :post
  37 + * @time :2025/4/17 10:17
  38 + */
  39 + public function lists(){
  40 + $this->request->validate([
  41 + 'project_id'=>'required',
  42 + ],[
  43 + 'project_id.required' => 'project_id不能为空',
  44 + ]);
  45 + $field = ['id','check_id','date','status','images','result','created_at'];
  46 + $this->map['status'] = 1;
  47 + $lists = $this->model->lists($this->map,$this->page,$this->row,'id',$field);
  48 + $this->response('success',Code::SUCCESS,$lists);
  49 + }
  50 +
  51 + /**
  52 + * @remark :获取数据详情
  53 + * @name :info
  54 + * @author :lyh
  55 + * @method :post
  56 + * @time :2025/4/17 16:18
  57 + */
  58 + public function info(){
  59 + $this->request->validate([
  60 + 'id'=>'required',
  61 + ],[
  62 + 'id.required' => '主键不能为空',
  63 + ]);
  64 + $data = $this->model->read($this->map);
  65 + $this->response('success',Code::SUCCESS,$data);
  66 + }
  67 +
  68 + /**
  69 + * @remark :保存数据
  70 + * @name :save
  71 + * @author :lyh
  72 + * @method :post
  73 + * @time :2025/4/17 10:27
  74 + */
  75 + public function save(){
  76 + $this->request->validate([
  77 + 'project_id'=>'required', 'check_id'=>'required',
  78 + 'date'=>'required', 'result'=>'required',
  79 + ],[
  80 + 'project_id.required' => 'project_id不能为空', 'check_id.required' => '问题id不能为空',
  81 + 'date.required' => '时间不能为空', 'result.required' => '检查结果不能为空',
  82 + ]);
  83 + $this->param = $this->model->saveHandleParam($this->param,$this->manage['id']);
  84 + if(isset($this->param['id']) && !empty($this->param['id'])){
  85 + $id = $this->param['id'];
  86 + $this->model->edit($this->param,['id'=>$this->param['id']]);
  87 + }else{
  88 + $id = $this->model->addReturnId($this->param);
  89 + }
  90 + $this->response('success',Code::SUCCESS,['id'=>$id]);
  91 + }
  92 +
  93 + /**
  94 + * @remark :修改状态
  95 + * @name :status
  96 + * @author :lyh
  97 + * @method :post
  98 + * @time :2025/4/17 10:43
  99 + */
  100 + public function status(){
  101 + $this->request->validate([
  102 + 'id'=>'required',
  103 + 'status'=>'required',
  104 + ],[
  105 + 'id.required' => '主键不能为空',
  106 + 'status.required' => 'status不能为空',
  107 + ]);
  108 + $data = $this->model->edit(['status'=>$this->param['status']],['id'=>$this->param['id']]);
  109 + $this->response('success',Code::SUCCESS,$data);
  110 + }
  111 +
  112 + /**
  113 + * @remark :删除数据
  114 + * @name :del
  115 + * @author :lyh
  116 + * @method :post
  117 + * @time :2025/4/17 10:52
  118 + */
  119 + public function del(){
  120 + $this->request->validate([
  121 + 'id'=>'required',
  122 + ],[
  123 + 'id.required' => '主键不能为空',
  124 + ]);
  125 + if(!is_array($this->param['id'])){
  126 + $this->param['id'] = ['in',[$this->param['id']]];
  127 + }
  128 + $data = $this->model->del($this->map);
  129 + $this->response('success',Code::SUCCESS,$data);
  130 + }
  131 +}
@@ -29,7 +29,7 @@ class PackDirController extends BaseController @@ -29,7 +29,7 @@ class PackDirController extends BaseController
29 $serverModel = new Servers(); 29 $serverModel = new Servers();
30 $domainModel = new DomainInfo(); 30 $domainModel = new DomainInfo();
31 foreach ($lists['list'] as $k => $v) { 31 foreach ($lists['list'] as $k => $v) {
32 - $lists['list'][$k]['operator_name'] = $manageModel->getName($v['user_id']); 32 + $lists['list'][$k]['operator_name'] = $v['user_id'] ? $manageModel->getName($v['user_id']) : '系统';
33 $lists['list'][$k]['project_name'] = $projectModel->getProjectName($v['project_id']); 33 $lists['list'][$k]['project_name'] = $projectModel->getProjectName($v['project_id']);
34 34
35 $download_url = ''; 35 $download_url = '';
@@ -82,12 +82,8 @@ class CustomModuleContentController extends BaseController @@ -82,12 +82,8 @@ class CustomModuleContentController extends BaseController
82 * @time :2024/1/31 15:48 82 * @time :2024/1/31 15:48
83 */ 83 */
84 public function getHandleImageFile($v){ 84 public function getHandleImageFile($v){
85 - if(!empty($v['image'])){  
86 - $v['image_link'] = getImageUrl($v['image'],$this->user['storage_type'] ?? 0,$this->user['project_location']);  
87 - }  
88 - if(!empty($v['og_image'])){  
89 - $v['og_image'] = getImageUrl($v['og_image'],$this->user['storage_type'] ?? 0,$this->user['project_location']);  
90 - } 85 + $v['image_link'] = getImageUrl($v['image'] ?? '',$this->user['storage_type'] ?? 0,$this->user['project_location']);
  86 + $v['og_image'] = getImageUrl(empty($v['og_image']) ? $v['image'] : $v['og_image'],$this->user['storage_type'],$this->user['project_location']);
91 if(!empty($v['video'])){ 87 if(!empty($v['video'])){
92 $v['video']['url'] = getFileUrl($v['video']['url'],$this->user['storage_type'] ?? 0,$this->user['project_location'],$this->user['file_cdn'] ?? 0); 88 $v['video']['url'] = getFileUrl($v['video']['url'],$this->user['storage_type'] ?? 0,$this->user['project_location'],$this->user['file_cdn'] ?? 0);
93 $v['video']['video_image'] = getImageUrl($v['video']['video_image'],$this->user['storage_type'] ?? 0,$this->user['project_location']); 89 $v['video']['video_image'] = getImageUrl($v['video']['video_image'],$this->user['storage_type'] ?? 0,$this->user['project_location']);
@@ -295,4 +295,21 @@ class KeywordController extends BaseController @@ -295,4 +295,21 @@ class KeywordController extends BaseController
295 $logic->delAllKeyword(); 295 $logic->delAllKeyword();
296 $this->response('success'); 296 $this->response('success');
297 } 297 }
  298 +
  299 + /**
  300 + * @remark :删除关键词所有关联产品
  301 + * @name :delRelatedProductId
  302 + * @author :lyh
  303 + * @method :post
  304 + * @time :2025/4/17 11:01
  305 + */
  306 + public function delRelatedProductId(KeywordLogic $logic){
  307 + $this->request->validate([
  308 + 'keyword_id'=>'required',
  309 + ],[
  310 + 'keyword_id.required' => '关键词ID不能为空',
  311 + ]);
  312 + $logic->delAllRelated($this->param['keyword_id']);
  313 + $this->response('success');
  314 + }
298 } 315 }
@@ -826,4 +826,5 @@ class ProductController extends BaseController @@ -826,4 +826,5 @@ class ProductController extends BaseController
826 } 826 }
827 return $keyword_name; 827 return $keyword_name;
828 } 828 }
  829 +
829 } 830 }
@@ -1025,7 +1025,7 @@ class ProjectLogic extends BaseLogic @@ -1025,7 +1025,7 @@ class ProjectLogic extends BaseLogic
1025 public function saveOtherProject(){ 1025 public function saveOtherProject(){
1026 //获取当前数据详情 1026 //获取当前数据详情
1027 $projectInfo = $this->getProjectInfo($this->param['id']); 1027 $projectInfo = $this->getProjectInfo($this->param['id']);
1028 - if(($projectInfo['created_at'] >= '2014-12-01 00:00:00')){//12月1号过后默认不开启 1028 + if(($projectInfo['created_at'] >= '2024-12-01 00:00:00')){//12月1号过后默认不开启
1029 $this->param['aicc'] = Project::TYPE_ZERO; 1029 $this->param['aicc'] = Project::TYPE_ZERO;
1030 } 1030 }
1031 if($this->param['aicc'] == Project::TYPE_ONE && !empty($this->param['exclusive_aicc_day'])){ 1031 if($this->param['aicc'] == Project::TYPE_ONE && !empty($this->param['exclusive_aicc_day'])){
@@ -100,7 +100,7 @@ class BlogLogic extends BaseLogic @@ -100,7 +100,7 @@ class BlogLogic extends BaseLogic
100 $blogLabelLogic = new BlogLabelLogic(); 100 $blogLabelLogic = new BlogLabelLogic();
101 $info['label_name'] = $blogLabelLogic->getLabelName($info['label_id']); 101 $info['label_name'] = $blogLabelLogic->getLabelName($info['label_id']);
102 $info['image_link'] = getImageUrl($info['image'],$this->user['storage_type'],$this->user['project_location']); 102 $info['image_link'] = getImageUrl($info['image'],$this->user['storage_type'],$this->user['project_location']);
103 - $info['og_image'] = getImageUrl($info['og_image'],$this->user['storage_type'],$this->user['project_location']); 103 + $info['og_image'] = getImageUrl(empty($info['og_image']) ? $info['image'] : $info['og_image'],$this->user['storage_type'],$this->user['project_location']);
104 return $this->success($info); 104 return $this->success($info);
105 } 105 }
106 106
@@ -147,6 +147,7 @@ class NewsLogic extends BaseLogic @@ -147,6 +147,7 @@ class NewsLogic extends BaseLogic
147 } 147 }
148 $info['category_id'] = explode(',',trim($info['category_id'],',')); 148 $info['category_id'] = explode(',',trim($info['category_id'],','));
149 $info['image_link'] = getImageUrl($info['image'],$this->user['storage_type'],$this->user['project_location']); 149 $info['image_link'] = getImageUrl($info['image'],$this->user['storage_type'],$this->user['project_location']);
  150 + $info['og_image'] = getImageUrl(empty($info['og_image']) ? $info['image'] : $info['og_image'],$this->user['storage_type'],$this->user['project_location']);
150 return $this->success($info); 151 return $this->success($info);
151 } 152 }
152 153
@@ -298,6 +298,23 @@ class KeywordLogic extends BaseLogic @@ -298,6 +298,23 @@ class KeywordLogic extends BaseLogic
298 } 298 }
299 299
300 /** 300 /**
  301 + * @remark :对应删除关联关系
  302 + * @name :delRelated
  303 + * @author :lyh
  304 + * @method :post
  305 + * @time :2024/11/28 9:46
  306 + */
  307 + public function delAllRelated($keyword_id){
  308 + $productModel = new Product();
  309 + $productModel->update(['keyword_id' => DB::raw("REPLACE(keyword_id, ',$keyword_id,' , ',')"),'keyword_video_id' => DB::raw("REPLACE(keyword_video_id, ',$keyword_id,' , ',')")]);
  310 + $productModel->where('keyword_id',',')->orWhere('keyword_video_id',',')
  311 + ->update(['keyword_id' => DB::raw("REPLACE(keyword_id, ',' , '')"),'keyword_video_id' => DB::raw("REPLACE(keyword_video_id, ',' , '')")]);
  312 + $keywordRelatedModel = new KeywordRelated();
  313 + $keywordRelatedModel->del(['keyword_id'=>$keyword_id]);
  314 + return $this->success();
  315 + }
  316 +
  317 + /**
301 * @remark :删除所有的关键字 318 * @remark :删除所有的关键字
302 * @name :delAllKeyword 319 * @name :delAllKeyword
303 * @author :lyh 320 * @author :lyh
@@ -51,7 +51,6 @@ class RankDataLogic extends BaseLogic @@ -51,7 +51,6 @@ class RankDataLogic extends BaseLogic
51 }else{ 51 }else{
52 $api_no = $project['deploy_optimize']['api_no'] ?? 0; 52 $api_no = $project['deploy_optimize']['api_no'] ?? 0;
53 } 53 }
54 -  
55 $domain_info = (new DomainInfoLogic)->getDomainInfo($project_id); 54 $domain_info = (new DomainInfoLogic)->getDomainInfo($project_id);
56 $rank = RankData::where('project_id', $project_id)->where('api_no', $api_no)->first(); 55 $rank = RankData::where('project_id', $project_id)->where('api_no', $api_no)->first();
57 if(empty($rank) && ($project['deploy_optimize']['api_no'] != 0)){ 56 if(empty($rank) && ($project['deploy_optimize']['api_no'] != 0)){
@@ -23,6 +23,7 @@ class AutoPullNotify extends Base @@ -23,6 +23,7 @@ class AutoPullNotify extends Base
23 8 => '香港服务器', 23 8 => '香港服务器',
24 17 => '解析IP专用服务器', 24 17 => '解析IP专用服务器',
25 22 => '白帽专属服务器01', 25 22 => '白帽专属服务器01',
  26 + 24 => '白帽专属服务器02',
26 23 => '西班牙服务器', 27 23 => '西班牙服务器',
27 ]; 28 ];
28 } 29 }
@@ -11,6 +11,13 @@ namespace App\Models\Project; @@ -11,6 +11,13 @@ namespace App\Models\Project;
11 11
12 use App\Models\Base; 12 use App\Models\Base;
13 13
  14 +/**
  15 + * @remark :售后数据统计
  16 + * @name :After
  17 + * @author :lyh
  18 + * @method :post
  19 + * @time :2025/4/17 9:26
  20 + */
14 class After extends Base 21 class After extends Base
15 { 22 {
16 protected $table = 'gl_project_after'; 23 protected $table = 'gl_project_after';
  1 +<?php
  2 +/**
  3 + * @remark :
  4 + * @name :OptimizeCheckList.php
  5 + * @author :lyh
  6 + * @method :post
  7 + * @time :2025/4/17 9:27
  8 + */
  9 +
  10 +namespace App\Models\Project;
  11 +
  12 +use App\Models\Base;
  13 +
  14 +/**
  15 + * @remark :优化检查清单
  16 + * @name :OptimizeCheckList
  17 + * @author :lyh
  18 + * @method :post
  19 + * @time :2025/4/17 9:27
  20 + */
  21 +class OptimizeCheckList extends Base
  22 +{
  23 + protected $table = 'gl_optimize_check_list';
  24 +}
  1 +<?php
  2 +/**
  3 + * @remark :
  4 + * @name :OptimizeCheckList.php
  5 + * @author :lyh
  6 + * @method :post
  7 + * @time :2025/4/17 9:27
  8 + */
  9 +
  10 +namespace App\Models\Project;
  11 +
  12 +use App\Helper\Arr;
  13 +use App\Models\Base;
  14 +
  15 +/**
  16 + * @remark :优化检查日志
  17 + * @name :OptimizeCheckList
  18 + * @author :lyh
  19 + * @method :post
  20 + * @time :2025/4/17 9:27
  21 + */
  22 +class OptimizeCheckLog extends Base
  23 +{
  24 + protected $table = 'gl_optimize_check_log';
  25 +
  26 + /**
  27 + * @remark :获取器图片数据
  28 + * @name :getImagesAttribute
  29 + * @author :lyh
  30 + * @method :post
  31 + * @time :2025/4/17 10:26
  32 + */
  33 + public function getImagesAttribute($value){
  34 + return Arr::s2a($value);
  35 + }
  36 +
  37 + /**
  38 + * @remark :保存数据设置参数
  39 + * @name :handleParam
  40 + * @author :lyh
  41 + * @method :post
  42 + * @time :2025/4/17 10:35
  43 + */
  44 + public function saveHandleParam($param,$manage_id){
  45 + if(isset($param['images'])){
  46 + $param['images'] = Arr::a2s($param['images'] ?? []);
  47 + }
  48 + $this->param['operator_id'] = $manage_id;
  49 + $this->param['date'] = date('Y-m-d hH:i:s');
  50 + return $param;
  51 + }
  52 +}
@@ -23,14 +23,14 @@ class DingService @@ -23,14 +23,14 @@ class DingService
23 23
24 24
25 /** 25 /**
26 - * @remark :钉钉发送错误信息  
27 - * @name :handle  
28 - * @author :lyh  
29 - * @method :post  
30 - * @time :2025/3/19 18:03 26 + * 钉钉发送错误信息
  27 + * @param array $body
  28 + * @param string $link
  29 + * @return int
31 */ 30 */
32 - public function handle(array $body) 31 + public function handle(array $body, $link = '')
33 { 32 {
  33 + $link = $link ?: self::LINK;
34 $msgKey = mb_substr($body['msg'], 50); 34 $msgKey = mb_substr($body['msg'], 50);
35 if (!$this->getData(RedisKey::DING_MSG . $msgKey)) { 35 if (!$this->getData(RedisKey::DING_MSG . $msgKey)) {
36 $arr = [ 36 $arr = [
@@ -44,7 +44,7 @@ class DingService @@ -44,7 +44,7 @@ class DingService
44 'isAtAll' => $body['isAtAll'], 44 'isAtAll' => $body['isAtAll'],
45 ] 45 ]
46 ]; 46 ];
47 - $re = json_decode(HttpUtils::post(self::LINK, $arr), true); 47 + $re = json_decode(HttpUtils::post($link, $arr), true);
48 $this->setData(RedisKey::DING_MSG . $msgKey, true, 60); 48 $this->setData(RedisKey::DING_MSG . $msgKey, true, 60);
49 return $re['errcode'] ?? 0; 49 return $re['errcode'] ?? 0;
50 } 50 }
@@ -306,6 +306,22 @@ Route::middleware(['aloginauth'])->group(function () { @@ -306,6 +306,22 @@ Route::middleware(['aloginauth'])->group(function () {
306 Route::any('/getAnchorLink', [Aside\Optimize\OptimizeController::class, 'getAnchorLink'])->name('admin.optimize_getAnchorLink');//设置robots开关 306 Route::any('/getAnchorLink', [Aside\Optimize\OptimizeController::class, 'getAnchorLink'])->name('admin.optimize_getAnchorLink');//设置robots开关
307 Route::any('/getAfterCount', [Aside\Optimize\AfterCountController::class, 'getAfterCount'])->name('admin.optimize_getAfterCount');//售后统计数据 307 Route::any('/getAfterCount', [Aside\Optimize\AfterCountController::class, 'getAfterCount'])->name('admin.optimize_getAfterCount');//售后统计数据
308 Route::any('/getAfterCountInfo', [Aside\Optimize\AfterCountController::class, 'getAfterCountInfo'])->name('admin.optimize_getAfterCountInfo');//售后统计数据详情 308 Route::any('/getAfterCountInfo', [Aside\Optimize\AfterCountController::class, 'getAfterCountInfo'])->name('admin.optimize_getAfterCountInfo');//售后统计数据详情
  309 +
  310 + //检查列表
  311 + Route::prefix('check_list')->group(function () {
  312 + Route::any('/', [Aside\Optimize\CheckListController::class, 'lists'])->name('admin.check_list');
  313 + Route::any('/info', [Aside\Optimize\CheckListController::class, 'info'])->name('admin.check_list_info');
  314 + Route::any('/save', [Aside\Optimize\CheckListController::class, 'save'])->name('admin.check_list_save');
  315 + Route::any('/del', [Aside\Optimize\CheckListController::class, 'del'])->name('admin.check_list_del');
  316 + });
  317 +
  318 + //检查记录
  319 + Route::prefix('check_log')->group(function () {
  320 + Route::any('/', [Aside\Optimize\CheckLogController::class, 'lists'])->name('admin.check_log');
  321 + Route::any('/info', [Aside\Optimize\CheckLogController::class, 'info'])->name('admin.check_log_info');
  322 + Route::any('/save', [Aside\Optimize\CheckLogController::class, 'save'])->name('admin.check_log_save');
  323 + Route::any('/del', [Aside\Optimize\CheckLogController::class, 'del'])->name('admin.check_log_del');
  324 + });
309 }); 325 });
310 //生成关键字 326 //生成关键字
311 Route::prefix('create_keyword')->group(function () { 327 Route::prefix('create_keyword')->group(function () {
@@ -551,6 +567,7 @@ Route::middleware(['aloginauth'])->group(function () { @@ -551,6 +567,7 @@ Route::middleware(['aloginauth'])->group(function () {
551 Route::any('/save', [Aside\Project\AggregateKeywordController::class, 'save'])->name('admin.aggregateKeyword_save'); 567 Route::any('/save', [Aside\Project\AggregateKeywordController::class, 'save'])->name('admin.aggregateKeyword_save');
552 Route::any('/del', [Aside\Project\AggregateKeywordController::class, 'del'])->name('admin.aggregateKeyword_del'); 568 Route::any('/del', [Aside\Project\AggregateKeywordController::class, 'del'])->name('admin.aggregateKeyword_del');
553 }); 569 });
  570 +
554 }); 571 });
555 572
556 //无需登录验证的路由组 573 //无需登录验证的路由组
@@ -283,6 +283,7 @@ Route::middleware(['bloginauth'])->group(function () { @@ -283,6 +283,7 @@ Route::middleware(['bloginauth'])->group(function () {
283 Route::any('/delProductType', [\App\Http\Controllers\Bside\Product\ProductController::class, 'delProductType'])->name('product_delProductType'); 283 Route::any('/delProductType', [\App\Http\Controllers\Bside\Product\ProductController::class, 'delProductType'])->name('product_delProductType');
284 Route::any('/getButton', [\App\Http\Controllers\Bside\Product\ProductController::class, 'getButton'])->name('product_getButton'); 284 Route::any('/getButton', [\App\Http\Controllers\Bside\Product\ProductController::class, 'getButton'])->name('product_getButton');
285 Route::any('/batchSetKeyword', [\App\Http\Controllers\Bside\Product\ProductController::class, 'batchSetKeyword'])->name('product_batchSetKeyword'); 285 Route::any('/batchSetKeyword', [\App\Http\Controllers\Bside\Product\ProductController::class, 'batchSetKeyword'])->name('product_batchSetKeyword');
  286 +
286 //产品分类batchSetKeyword 287 //产品分类batchSetKeyword
287 Route::get('category', [\App\Http\Controllers\Bside\Product\CategoryController::class, 'index'])->name('product_category'); 288 Route::get('category', [\App\Http\Controllers\Bside\Product\CategoryController::class, 'index'])->name('product_category');
288 Route::get('category/info', [\App\Http\Controllers\Bside\Product\CategoryController::class, 'info'])->name('product_category_info'); 289 Route::get('category/info', [\App\Http\Controllers\Bside\Product\CategoryController::class, 'info'])->name('product_category_info');
@@ -304,6 +305,7 @@ Route::middleware(['bloginauth'])->group(function () { @@ -304,6 +305,7 @@ Route::middleware(['bloginauth'])->group(function () {
304 Route::any('keyword/batchUpdateKeyword', [\App\Http\Controllers\Bside\Product\KeywordController::class, 'batchUpdateKeyword'])->name('product_keyword_batchUpdateKeyword'); 305 Route::any('keyword/batchUpdateKeyword', [\App\Http\Controllers\Bside\Product\KeywordController::class, 'batchUpdateKeyword'])->name('product_keyword_batchUpdateKeyword');
305 Route::any('keyword/batchKeywordIsVideo', [\App\Http\Controllers\Bside\Product\KeywordController::class, 'batchKeywordIsVideo'])->name('product_keyword_batchKeywordIsVideo'); 306 Route::any('keyword/batchKeywordIsVideo', [\App\Http\Controllers\Bside\Product\KeywordController::class, 'batchKeywordIsVideo'])->name('product_keyword_batchKeywordIsVideo');
306 Route::any('keyword/batchKeywordFiled', [\App\Http\Controllers\Bside\Product\KeywordController::class, 'batchKeywordFiled'])->name('product_keyword_batchKeywordFiled'); 307 Route::any('keyword/batchKeywordFiled', [\App\Http\Controllers\Bside\Product\KeywordController::class, 'batchKeywordFiled'])->name('product_keyword_batchKeywordFiled');
  308 + Route::any('keyword/delRelatedProductId', [\App\Http\Controllers\Bside\Product\KeywordController::class, 'delRelatedProductId'])->name('product_keyword_delRelatedProductId');
307 //产品参数 309 //产品参数
308 Route::get('attr', [\App\Http\Controllers\Bside\Product\AttrController::class, 'index'])->name('product_attr'); 310 Route::get('attr', [\App\Http\Controllers\Bside\Product\AttrController::class, 'index'])->name('product_attr');
309 Route::get('attr/info', [\App\Http\Controllers\Bside\Product\AttrController::class, 'info'])->name('product_attr_info'); 311 Route::get('attr/info', [\App\Http\Controllers\Bside\Product\AttrController::class, 'info'])->name('product_attr_info');