作者 ZhengBing He

del

要显示太多修改。

为保证性能只显示 35 of 35+ 个文件。

root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2
[docker-compose.yml]
indent_size = 4
APP_NAME=Laravel
APP_ENV=development
APP_KEY=base64:+ouoKlz2sFDOisnROMRpxT/u9xkZJVrXlzP4cfTqPow=
APP_DEBUG=false
APP_URL=http://localhost
LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306F
DB_DATABASE=globalso
DB_USERNAME=debian-sys-maint
DB_PASSWORD=WtujxV73XIclQet0
BROADCAST_DRIVER=log
CACHE_DRIVER=file
FILESYSTEM_DRIVER=local
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
MEMCACHED_HOST=127.0.0.1
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:+ouoKlz2sFDOisnROMRpxT/u9xkZJVrXlzP4cfTqPow=
APP_DEBUG=false
APP_URL=http://localhost
LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=globalso
DB_USERNAME=debian-sys-maint
DB_PASSWORD=WtujxV73XIclQet0
BROADCAST_DRIVER=log
CACHE_DRIVER=file
FILESYSTEM_DRIVER=local
QUEUE_CONNECTION=sync
SESSION_DRIVER=file
SESSION_LIFETIME=120
MEMCACHED_HOST=127.0.0.1
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp
MAIL_HOST=mailhog
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS=null
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=mt1
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
* text=auto
*.blade.php diff=html
*.css diff=css
*.html diff=html
*.md diff=markdown
*.php diff=php
/.github export-ignore
CHANGELOG.md export-ignore
/node_modules
/public/hot
/public/storage
/public/.user.ini
/storage
/vendor
/uploads
composer.lock
.env
.env.backup
.phpunit.result.cache
docker-compose.override.yml
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
/.idea
/.vscode
composer.lock
app/Console/Commands/Test/DataRecovery.php
/public/upload
/public/runtime
public/nginx.htaccess
public/.htaccess
.gitignore
\ No newline at end of file
php:
preset: laravel
version: 8
disabled:
- no_unused_imports
finder:
not-name:
- index.php
- server.php
js:
finder:
not-name:
- webpack.mix.js
css: true
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>
# 基础框架 - 后端管理系统
## 路由
### 路由提供者Provider中预定义两个路由
- bside 代表B端用户访问路由 完整路由:{{url}}/a/xxx
- aside 代表管理员访问路由 完整路由:{{url}}/b/xxx
## 枚举
### 使用插件bensampo/laravel-enum 版本4 github地址:https://github.com/BenSampo/laravel-enum/blob/v4.2.0/README.md
- 创建枚举类 : php artisan make:enum ”文件名“
- 给枚举类生成注释: php artisan enum:annotate "文件名"
- 如有翻译本地化需求,在 resources/lang/zh-CN/enums.php文件中中文翻译,英文语言包不用写,会自动翻译键名
- 在验证器中使用 : '参数名' => ['required ', new EnumValue(CaptchaType::class)],(或者按照键名new EnumKey)
- 可参考Enums/Common/Common.php枚举类
## 状态码
- 该系统所有状态码都定义在 App\Enums\Commom\Code枚举类中
- 大大类 和 大类不能变动 ,以大类为基准步长为100,根据业务自定义状态码
## 中间件
- 登录验证中间件 ”loginauth“
- Bside路由默认已经使用的中间件组为bside
- Aside路由默认已经使用的中间件组为aside
## 参数加密
- .env文件中有三个配置,其中iv必须是八位
- 参数加密不开启的时候,前端正常传入参数,是明文不安全
## 控制器
- 各个端控制器目录:App\Http\Controllers\XXXside
- BaseController基础控制器,需要被其他控制器继承
- 控制器中只需要干三件事情:
第一,验证参数(如果注入了自定义验证Request就可以省略$request->validate这一步)
第二,调用逻辑层Logic
第三,success返回---错误直接走异常处理
## 请求and响应
- 控制器方法注入请求Illuminate\Http\Request或者注入自定义请求表单
- 创建请求表单: php artisan make:request 文件名
- 请求表单中定义,用户是否有权限请求以及参数验证规则
- 控制器中调用request->validated()
- 响应只能调用BaseController的success()方法
> 注意!全站返回不能编写自定义的message,只能通过Code码
## 逻辑层
- App\Http\Logic逻辑层只能被控制器调用
- 要继承基类BaseLogic,return 使用基类定义的方法
## 错误截获
- 自定义某端全局异常:App\Exceptions\XXXsideGlobalException,throw new XXXsideGlobalException($code); 注意也只能传入Code码
> 注意!.env文件APP_DEBUG控制是否显示详细错误信息,否则就按照本地化的错误码的message来显示
## 日志规范
- 配置文件logging.php中预定义了B端错误日志bside
- 日志格式:logs -> bside(端)-> 2022-06(年月)-> 日期_级别.log (预定义了两个级别 errors和info)
- errors错误日志会在异常抛出的时候自动记录,info手动调用
- 共工具类App\Utils\LogUtils 提供了两个方法errorBside,infoBside记录日志
## 数据迁移
- 每个版本的迭代如有数据结构修改,必须写到数据迁移里面
- 创建迁移 :php artisan make:migration create_users_table --create=users 或者 php artisan make:migration
add_votes_to_users_table --table=users (--create是创建表 --table是编辑表)
- 编写迁移脚本
- 执行迁移: php artisan migrate
## 数据填充
- 每个版本的迭代如有数据预设置,必须写到数据填充里面
- 创建填充 : php artisan make:seeder 文件名
- 如果是简单的直接在seeder文件的run()方法中写insert
- 如果较复杂需要编写模型工厂:php artisan make:factory UserFactory
- 执行填充 : composer dump-autoload (用来重新生成composer映射) ,php artisan db:seed
## Redis
- 配置文件database.php中的redis
- 所有使用到的键名需要在枚举类中定义:App\Enums\Common\RedisKey
- 工具类App\Utils\RedisUtils中提供了获取redis实例的方法
- traits文件App\Traits\RedisTraits中,定义了常用的redis方法,使用的时候只需要: use RedisTrait;
<?php
/**
* @remark :
* @name :AiBlogAuthorId.php
* @author :lyh
* @method :post
* @time :2025/5/26 15:57
*/
namespace App\Console\Commands\Ai;
use App\Helper\Arr;
use App\Models\Com\Notify;
use App\Models\Devops\ServerConfig;
use App\Models\Devops\ServersIp;
use App\Models\Domain\DomainInfo;
use App\Models\Project\AiBlogTask as AiBlogTaskModel;
use App\Models\Ai\AiBlogAuthor as AiBlogAuthorModel;
use App\Models\Project\Project;
use App\Services\AiBlogService;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;
class AiBlogAuthorId extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'save_ai_blog_author_id';
/**
* The console command description.
*
* @var string
*/
protected $description = '拉取对应作者的页面';
public $route = [];
public function handle(){
while (true){
//获取任务id
$task_id = $this->getTaskId();
if(empty($task_id)){
sleep(300);
continue;
}
$this->_action($task_id);
}
}
public function getTaskId()
{
$task_id = Redis::rpop('ai_blog_author_id');
if (empty($task_id)) {
$aiBlogTaskModel = new AiBlogTaskModel();
$ids = $aiBlogTaskModel->formatQuery(['status'=>$aiBlogTaskModel::STATUS_RUNNING, 'type'=>$aiBlogTaskModel::TYPE_AUTHOR_ID])->pluck('id');
if(!empty($ids)){
foreach ($ids as $id) {
Redis::lpush('ai_blog_author_id', $id);
}
}
$task_id = Redis::rpop('ai_blog_author_id');
}
return $task_id;
}
/**
* @remark :执行方法
* @name :_action
* @author :lyh
* @method :post
* @time :2025/5/26 16:06
*/
public function _action($task_id){
$aiBlogTaskModel = new AiBlogTaskModel();
$item = $aiBlogTaskModel->read(['id'=>$task_id]);
if($item === false){
echo '当前数据不存在.'.$item['id'].PHP_EOL;
return true;
}
$aiBlogService = new AiBlogService($item['project_id']);
ProjectServer::useProject($item['project_id']);
$aiBlogService->author_id = $item['task_id'];
$result = $aiBlogService->getAuthorDetail();
if(isset($result['status']) && $result['status'] == 200){
//当前作者的页面
$aiBlogAuthorModel = new AiBlogAuthorModel();
$authorInfo = $aiBlogAuthorModel->read(['author_id'=>$item['task_id']],['id','route']);
if($authorInfo !== false && !empty($result['data']['section'])){
$this->route[] = $authorInfo['route'];
$aiBlogAuthorModel->edit(['text'=>$result['data']['section']],['author_id'=>$item['task_id']]);
}
}
DB::disconnect('custom_mysql');
$aiBlogTaskModel->edit(['status'=>2],['id'=>$task_id]);
$this->sendCPost($item['project_id']);
return true;
}
/**
* @remark :通知C端
* @name :sendCPost
* @author :lyh
* @method :post
* @time :2025/5/26 16:21
*/
public function sendCPost($project_id){
//获取项目所在服务器
$project_model = new Project();
$project_info = $project_model->read(['id'=>$project_id],['serve_id','is_upgrade', 'main_lang_id']);
if(!$project_info){
return false;
}
$serve_ip_model = new ServersIp();
$serve_ip_info = $serve_ip_model->read(['id'=>$project_info['serve_id']],['servers_id']);
$servers_id = $serve_ip_info ? $serve_ip_info['servers_id'] : 0;
if($servers_id == ServerConfig::SELF_SITE_ID){
//自建站服务器:如果项目已经上线,不请求C端接口,数据直接入库
$domain_model = new DomainInfo();
$domain_info = $domain_model->read(['project_id'=>$project_id],['domain']);
if($domain_info){
//判断是否已有更新进行中
$notify_model = new Notify();
$data = [
'project_id' => $project_id,
'type' => 1,
'route' => 3,
'server_id' => ServerConfig::SELF_SITE_ID,
'status' => ['!=',Notify::STATUS_FINISH_SITEMAP]
];
$notify = $notify_model->read($data,['id']);
if(!$notify){
$domain = $domain_info['domain'];
$data['data'] = Arr::a2s(['domain'=>$domain,'url'=>$this->route,'language'=>[]]);
$data['status'] = Notify::STATUS_INIT;
$data['is_pull_html_zip'] = Notify::IS_PULL_HTML_ZIP_FALSE;
$data['sort'] = 1;
$notify_model->add($data);
}
}
}else{
$domainModel = new DomainInfo();
$domain = $domainModel->getProjectIdDomain($project_id);
$c_url = $domain.'api/update_page/';
$param = [
'project_id' => $project_id,
'type' => 1,
'route' => 3,
'url' => $this->route,
'language'=> [],
'is_sitemap' => 0
];
$res = http_post($c_url, json_encode($param,true));
echo 'notify: project id: ' . $project_id . ', result: ' . json_encode($res,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}
}
}
<?php
/**
* @remark :
* @name :AiBlogAuthorTask.php
* @author :lyh
* @method :post
* @time :2025/2/21 11:12
*/
namespace App\Console\Commands\Ai;
use App\Models\Ai\AiBlog;
use App\Models\Ai\AiBlogAuthor;
use App\Models\Project\AiBlogTask as AiBlogTaskModel;
use App\Models\Project\ProjectAiSetting;
use App\Models\RouteMap\RouteMap;
use App\Services\AiBlogService;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
class AiBlogAuthorTask extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'save_ai_blog_author';
/**
* The console command description.
*
* @var string
*/
protected $description = '查询ai_blog_author是否已经生成';
/**
* @remark :获取作者
* @name :handle
* @author :lyh
* @method :post
* @time :2025/2/21 11:30
*/
public function handle(){
$aiBlogTaskModel = new AiBlogTaskModel();
while (true){
$info = $aiBlogTaskModel->where('status',1)->where('type',1)->inRandomOrder()->first();
if(empty($info)){
sleep(300);
continue;
}
$info = $info->toArray();
echo date('Y-m-d H:i:s').'开始->project_id:' . $info['project_id'] . PHP_EOL;
//获取配置
$aiSettingInfo = $this->getSetting($info['project_id']);
if(empty($aiSettingInfo)){
continue;
}
$aiBlogService = new AiBlogService();
$aiBlogService->mch_id = $aiSettingInfo['mch_id'];
$aiBlogService->key = $aiSettingInfo['key'];
$result = $aiBlogService->getAuthor();
if(!isset($result['status'])){
echo '错误:'.json_encode($result,true);
continue;
}
if($result['status'] != 200){
sleep(10);
continue;
}
if(empty($result['data'])){
echo '没有作者任务-'.PHP_EOL;
continue;
}
//保存当前项目ai_blog数据
ProjectServer::useProject($info['project_id']);
$this->saveAiBlogAuthor($result['data'] ?? [],$info['project_id']);
RouteMap::setRoute('top-blog',RouteMap::SOURCE_AI_BLOG_LIST,0,$info['project_id']);//写一条列表页路由
RouteMap::setRoute('top-video',RouteMap::SOURCE_AI_VIDEO_LIST,0,$info['project_id']);//写一条列表页路由
DB::disconnect('custom_mysql');
//修改任务状态
$aiBlogTaskModel->edit(['status'=>2],['id'=>$info['id']]);
echo date('Y-m-d H:i:s').'结束->任务id:' . $info['id'] . PHP_EOL;
}
return true;
}
/**
* @remark :获取项目配置
* @name :getSetting
* @author :lyh
* @method :post
* @time :2025/2/14 11:27
*/
public function getSetting($project_id){
$ai_cache = Cache::get('ai_blog_'.$project_id);
if($ai_cache){
return $ai_cache;
}
$projectAiSettingModel = new ProjectAiSetting();
$aiSettingInfo = $projectAiSettingModel->read(['project_id'=>$project_id]);
Cache::put('ai_blog_'.$project_id,$aiSettingInfo,3600);
return $aiSettingInfo;
}
/**
* @remark :保存数据
* @name :saveAiBlogAuthor
* @author :lyh
* @method :post
* @time :2025/2/21 11:36
*/
public function saveAiBlogAuthor($data,$project_id){
if(empty($data)){
return true;
}
$aiBlogAuthorModel = new AiBlogAuthor();
foreach ($data as $v){
$param = [
'author_id'=>$v['id'],
'title'=>$v['title'],
'image'=>str_replace_url($v['picture']),
'description'=>$v['description'],
];
//查询当前数据是否存在
$info = $aiBlogAuthorModel->read(['author_id'=>$v['id']]);
try {
if($info === false){
echo '执行新增'.PHP_EOL;
$id = $aiBlogAuthorModel->addReturnId($param);
$param['route'] = RouteMap::setRoute($v['route'] ?? $v['title'], RouteMap::SOURCE_AI_BLOG_AUTHOR, $id, $project_id);
$aiBlogAuthorModel->edit(['route'=>$param['route']],['id'=>$id]);
}else{
$param['route'] = RouteMap::setRoute($v['route'] ?? $v['title'], RouteMap::SOURCE_AI_BLOG_AUTHOR, $info['id'], $project_id);
$aiBlogAuthorModel->edit($param,['id'=>$info['id']]);
echo '执行更新'.PHP_EOL;
}
$aiSettingInfo = $this->getSetting($project_id);
$aiBlogService = new AiBlogService();
$aiBlogService->mch_id = $aiSettingInfo['mch_id'];
$aiBlogService->key = $aiSettingInfo['key'];
$aiBlogService->updateAuthorInfo(['author_id'=>$param['author_id'],'route'=>$param['route'],'title'=>$param['title'],'picture'=>$param['image'],'description'=>$param['description']]);
}catch (\Exception $e){
echo 'error:'.$e->getMessage().PHP_EOL;
continue;
}
}
return true;
}
}
<?php
namespace App\Console\Commands\Ai;
use App\Http\Logic\Aside\Project\ProjectLogic;
use App\Models\Ai\AiBlog;
use App\Models\Ai\AiBlogKeyword;
use App\Models\Ai\AiBlogOpenLog;
use App\Models\Project\AiBlogTask as AiBlogTaskModel;
use App\Models\Project\Project;
use App\Models\Project\ProjectKeyword;
use App\Models\RankData\RankData;
use App\Models\WebSetting\WebSetting;
use App\Services\AiBlogService;
use App\Services\DingService;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
/**
* 自动发布AI博客任务
* Class AiBlogAutoPublish
* @package App\Console\Commands\Ai
* @author zbj
* @date 2025/3/6
*/
class AiBlogAutoPublish extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'ai_blog_auto_publish {action}';
/**
* The console command description.
*
* @var string
*/
protected $description = '自动发布AI Blog';
/**
* @return bool
* @author zbj
* @date 2025/3/6
*/
public function handle()
{
$action = $this->argument('action');
if($action == 'auto_publish'){
$this->auto_publish();
}
if($action == 'auto_open'){
$this->auto_open();
}
}
public function auto_publish()
{
$this->output('开始自动发布博客文章');
$projects = Project::where('is_ai_blog', 1)->whereIn('type',[1,2,3,4,6])->where('delete_status',0)->where('site_status',0)->where('extend_type',0)->get();
foreach ($projects as $project) {
try {
$this->output("项目{$project->id}开始自动发布");
if(!$project->deploy_optimize['is_ai_blog_send']){
$this->output("项目{$project->id}未开启自动发布" . $project->deploy_optimize['start_date']);
continue;
}
if(($project->deploy_optimize['start_date'] > date('Y-m-d')) || !$project->deploy_optimize['start_date']){
$this->output("项目{$project->id}未到推广时间" . $project->deploy_optimize['start_date']);
continue;
}
$next_auto_date = AiBlogTaskModel::where('project_id', $project->id)->where('type', 2)->whereNotNull('next_auto_date')->orderBy('id', 'desc')->value('next_auto_date');
if($next_auto_date && $next_auto_date > date('Y-m-d')){
$this->output("项目{$project->id}未到执行时间" . $next_auto_date);
continue;
}
$aiKeywordModel = new AiBlogKeyword();
$keywords = $aiKeywordModel->getValue(['project_id'=>$project->id],'keywords');
if(empty($keywords)){
//核心关键词+网站关键词+白帽关键词
$main_keywords = ProjectKeyword::where('project_id', $project->id)->value('main_keyword');
$main_keywords = explode("\r\n", $main_keywords);
$seo_keywords = ProjectKeyword::where('project_id', $project->id)->value('seo_keywords');
$seo_keywords = explode("\r\n", $seo_keywords);
ProjectServer::useProject($project->id);
$site_keywords = WebSetting::where('project_id', $project->id)->value('keyword');
DB::disconnect('custom_mysql');
$site_keywords = explode(",", $site_keywords);
$keywords = array_filter(array_merge($main_keywords, $site_keywords, $seo_keywords));
$keywords = array_map('trim', $keywords);
}else{
$keywords = explode("\r\n", $keywords);
$keywords = array_map('trim', $keywords); // 清理空格
$keywords = array_filter($keywords); // 移除空值
}
if (empty($keywords)) {
$this->output("项目{$project->id}未获取到关键词");
continue;
}
$last_task = AiBlogTaskModel::where('project_id', $project->id)->where('type', 2)->orderBy('id', 'desc')->first();
$compliance = RankData::where(['project_id' => $project->id, 'lang' => ''])->value('is_compliance');
$frequency = Project::typeBlogFrequency($project->deploy_optimize->send_ai_blog_frequency);
$frequency = explode('-', $frequency);
//1、之前测试那批项目,按照正常频率发送;
//2、未达标的项目,开启AIblog, 并立即推送三篇;
//3、其他项目等下下周 1 (2025-03-17)开始推送第一篇, 之后按照正频率发送;
if (!$last_task) {
if(strpos($frequency[0],'/')){
$frequency = [1,1];//默认每天执行
}
if(!$compliance) {
for ($i = 0; $i < 3; $i++) {
$this->createTask($keywords, $project->id, $frequency);
}
}else{
if(date('Y-m-d') >= '2025-03-17'){
$this->createTask($keywords, $project->id, $frequency);
}
}
} else {
if(strpos($frequency[0],'/')){//一天2/3篇
$aiBlogTaskModel = new AiBlogTaskModel();
$frequency = explode('/', $frequency[0]);
//查询当前已发布几篇
$count = $aiBlogTaskModel->counts(['next_auto_date' => date('Y-m-d', strtotime('+1 day')),'project_id' => $project->id]);
while ($count < ($frequency[1] ?? 2) && ($count <= 3)){
$this->createTask($keywords, $project->id, [1,1]);
$count++;
}
}else{
$this->createTask($keywords, $project->id, $frequency);
}
}
}catch (\Exception $e){
(new DingService())->handle([
'keyword' => 'AI_BLOG自动发布失败',
'msg' => '项目ID:' . $project->id . PHP_EOL .
'错误信息:' . $e->getMessage() . PHP_EOL .
'错误文件:' . $e->getFile() . PHP_EOL .
'错误行数:' . $e->getLine(),
'isAtAll' => true, // 是否@所有人
]);
$this->output("自动发布失败:" . $e->getMessage() . $e->getFile() . $e->getLine());
}
sleep(5);
}
}
public function createTask($keywords, $project_id, $frequency){
$keyword = $keywords[array_rand($keywords)];
$aiBlogService = new AiBlogService($project_id);
$result = $aiBlogService->createTask($keyword);
if ($result['status'] == 200) {
$aiBlogTaskModel = new AiBlogTaskModel();
$next_auto_date = date('Y-m-d', strtotime('+' . mt_rand($frequency[0] ?? 3, $frequency[1] ?? 6) . 'days')); //每3-6天自动发布
$aiBlogTaskModel->addReturnId(['project_id' => $project_id, 'type' => 2, 'task_id' => $result['data']['task_id'], 'status' => 1, 'next_auto_date' => $next_auto_date]);
ProjectServer::useProject($project_id);
$aiBlogModel = new AiBlog();
$start = strtotime('10:00:00');
$end = strtotime('16:00:00');
$randomTimestamp = mt_rand($start, $end);
$created_at = date("Y-m-d H:i:s", $randomTimestamp);
$aiBlogModel->addReturnId(['keyword' => $keyword, 'status' => 1, 'task_id' => $result['data']['task_id'], 'project_id' => $project_id, 'created_at' => $created_at]);
DB::disconnect('custom_mysql');
$this->output("任务创建成功");
} else {
$this->output('任务创建失败:' . json_encode($result));
}
}
/**
* 上线的推广项目自动开启
* @author zbj
* @date 2025/3/7
*/
public function auto_open()
{
while (true) {
$this->output('上线的推广项目自动开启');
$projects = Project::whereIn('type', [Project::TYPE_TWO, Project::TYPE_FOUR])
->whereIn('id', function ($query) {
//按推广时间
$query->select('project_id')
->from('gl_project_deploy_optimize')
->where('start_date', '<=', date('Y-m-d'))
->where('start_date', '<>', '');
})
->where('is_ai_blog', 0)
->get();
foreach ($projects as $project) {
try {
//未开启过 自动开启
if (!AiBlogOpenLog::isOpened($project->id)) {
//创建AI博客项目
$deploy_optimize = $project->deploy_optimize;
(new ProjectLogic())->setAiBlog($project->id, $project->main_lang_id, 1, $project->company, $deploy_optimize->company_en_name, $deploy_optimize->company_en_description,$project->is_related_video ?? 0);
//开启
$project->is_ai_blog = 1;
//开启自动发布
$project->deploy_optimize->is_ai_blog_send = 1;
$project->deploy_optimize->save();
$project->save();
//开启日志
AiBlogOpenLog::addLog($project->id);
$this->output('自动开启项目:' . $project->id);
}
}catch (\Exception $e){
(new DingService())->handle([
'keyword' => 'AI_BLOG自动开启失败',
'msg' => '项目ID:' . $project->id . PHP_EOL .
'错误信息:' . $e->getMessage() . PHP_EOL .
'错误文件:' . $e->getFile() . PHP_EOL .
'错误行数:' . $e->getLine(),
'isAtAll' => true, // 是否@所有人
]);
$this->output("自动开启失败:" . $e->getMessage() . $e->getFile() . $e->getLine());
}
}
sleep(60);
}
}
/**
* 输出message
* @param $message
*/
public function output($message)
{
Log::channel('ai_blog')->info($message);
echo date('Y-m-d H:i:s') . ' ' . $message . PHP_EOL;
}
}
<?php
/**
* @remark :
* @name :AiBlogTask.php
* @author :lyh
* @method :post
* @time :2025/2/14 11:14
*/
namespace App\Console\Commands\Ai;
use App\Models\Ai\AiBlog;
use App\Models\Ai\AiBlogAuthor;
use App\Models\Ai\AiBlogList;
use App\Models\Domain\DomainInfo;
use App\Models\Project\Project;
use App\Models\Project\ProjectAiSetting;
use App\Models\RouteMap\RouteMap;
use App\Services\AiBlogService;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use App\Models\Project\AiBlogTask as AiBlogTaskModel;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use function Symfony\Component\String\s;
/***
* @remark :根据项目更新blog列表
* @name :AiBlogListProjectTask
* @author :lyh
* @method :post
* @time :2025/3/6 9:45
*/
class AiBlogListAllTask extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'save_all_ai_blog_list';
/**
* The console command description.
*
* @var string
*/
protected $description = '生成blog列表';
public function handle(){
$projectModel = new Project();
$lists = $projectModel->list(['delete_status' => 0,'project_type'=>0,'extend_type'=>0,'type'=>['in',[2,3,4,6]]], 'id', ['id']);
foreach ($lists as $item){
echo '执行的项目的id'.$item['id'].PHP_EOL;
$project_id = $item['id'];
ProjectServer::useProject($project_id);
$projectAiSettingModel = new ProjectAiSetting();
$aiSettingInfo = $projectAiSettingModel->read(['project_id'=>$project_id]);
if($aiSettingInfo === false){
echo '未加载到配置。'.PHP_EOL;
continue;
}
$this->updateBlogList($aiSettingInfo);
$this->curlDelRoute($project_id);
DB::disconnect('custom_mysql');
}
return true;
}
/**
* @remark :更新列表页数据
* @name :updateBlogList
* @author :lyh
* @method :post
* @time :2025/3/5 11:07
*/
public function updateBlogList($aiSettingInfo){
$aiBlogService = new AiBlogService();
$aiBlogService->mch_id = $aiSettingInfo['mch_id'];
$aiBlogService->key = $aiSettingInfo['key'];
$page = 1;
$saveData = [];
$result = $aiBlogService->getAiBlogList($page,15);
if(!isset($result['status']) || $result['status'] != 200){
return true;
}
$total_page = $result['data']['total_page'];
//组装数据保存
$saveData[] = [
'route'=>$page,
'text'=>$result['data']['section'],
];
while ($total_page > $page){
$page++;
$result = $aiBlogService->getAiBlogList($page,15);
if(isset($result['status']) && $result['status'] == 200){
$saveData[] = [
'route'=>$page,
'text'=>$result['data']['section'],
];
}
}
$aiBlogListModel = new AiBlogList();
if(!empty($saveData)){
//写一条路由信息
$aiBlogListModel->truncate();
$aiBlogListModel->insertAll($saveData);
}
return true;
}
/**
* @remark :通知C端生成界面
* @name :sendNotice
* @author :lyh
* @method :post
* @time :2025/3/6 11:51
*/
public function curlDelRoute($project_id){
$domainModel = new DomainInfo();
//获取项目域名
$domain = $domainModel->getProjectIdDomain($project_id);
if(!empty($domain)){
$c_url = $domain.'api/update_page/';
$param = [
'project_id' => $project_id,
'type' => 1,
'route' => 3,
'url' => ['top-blog'],
'language'=> [],
'is_sitemap' => 0
];
http_post($c_url, json_encode($param));
}
return true;
}
}
<?php
/**
* @remark :
* @name :AiBlogTask.php
* @author :lyh
* @method :post
* @time :2025/2/14 11:14
*/
namespace App\Console\Commands\Ai;
use App\Models\Ai\AiBlog;
use App\Models\Ai\AiBlogAuthor;
use App\Models\Ai\AiBlogList;
use App\Models\Domain\DomainInfo;
use App\Models\Project\ProjectAiSetting;
use App\Models\RouteMap\RouteMap;
use App\Services\AiBlogService;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use App\Models\Project\AiBlogTask as AiBlogTaskModel;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use function Symfony\Component\String\s;
/***
* @remark :根据项目更新blog列表
* @name :AiBlogListProjectTask
* @author :lyh
* @method :post
* @time :2025/3/6 9:45
*/
class AiBlogListProjectTask extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'save_ai_blog_list {project_id}';
/**
* The console command description.
*
* @var string
*/
protected $description = '根据项目生成blog列表';
public function handle(){
$project_id = $this->argument('project_id');
@file_put_contents(storage_path('logs/lyh_error.log'), var_export('执行的项目id->'.$project_id, true) . PHP_EOL, FILE_APPEND);
ProjectServer::useProject($project_id);
$projectAiSettingModel = new ProjectAiSetting();
$aiSettingInfo = $projectAiSettingModel->read(['project_id'=>$project_id]);
$this->updateBlogList($aiSettingInfo);
$this->curlDelRoute($project_id);
DB::disconnect('custom_mysql');
return true;
}
/**
* @remark :更新列表页数据
* @name :updateBlogList
* @author :lyh
* @method :post
* @time :2025/3/5 11:07
*/
public function updateBlogList($aiSettingInfo){
$aiBlogService = new AiBlogService();
$aiBlogService->mch_id = $aiSettingInfo['mch_id'];
$aiBlogService->key = $aiSettingInfo['key'];
$page = 1;
$saveData = [];
$result = $aiBlogService->getAiBlogList($page,15);
if(!isset($result['status']) || $result['status'] != 200){
echo '请示失败。'.json_encode($result, JSON_UNESCAPED_UNICODE);
return true;
}
$total_page = $result['data']['total_page'];
//组装数据保存
$saveData[] = [
'route'=>$page,
'text'=>$result['data']['section'],
];
while ($total_page > $page){
$page++;
$result = $aiBlogService->getAiBlogList($page,15);
if(isset($result['status']) && $result['status'] == 200){
$saveData[] = [
'route'=>$page,
'text'=>$result['data']['section'],
];
}
}
$aiBlogListModel = new AiBlogList();
if(!empty($saveData)){
//写一条路由信息
$aiBlogListModel->truncate();
$aiBlogListModel->insertAll($saveData);
}
return true;
}
/**
* @remark :通知C端生成界面
* @name :sendNotice
* @author :lyh
* @method :post
* @time :2025/3/6 11:51
*/
public function curlDelRoute($project_id){
$domainModel = new DomainInfo();
//获取项目域名
$domain = $domainModel->getProjectIdDomain($project_id);
if(!empty($domain)){
$c_url = $domain.'api/update_page/';
$param = [
'project_id' => $project_id,
'type' => 1,
'route' => 3,
'url' => ['top-blog'],
'language'=> [],
'is_sitemap' => 0
];
http_post($c_url, json_encode($param));
}
return true;
}
}
<?php
/**
* @remark :
* @name :AiBlogTask.php
* @author :lyh
* @method :post
* @time :2025/2/14 11:14
*/
namespace App\Console\Commands\Ai;
use App\Models\Ai\AiBlog;
use App\Models\Ai\AiBlogAuthor;
use App\Models\Ai\AiBlogList;
use App\Models\Domain\DomainInfo;
use App\Models\Project\ProjectAiSetting;
use App\Models\RouteMap\RouteMap;
use App\Services\AiBlogService;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use App\Models\Project\AiBlogTask as AiBlogTaskModel;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;
use function Symfony\Component\String\s;
/***
* @remark :根据项目更新blog列表
* @name :AiBlogListProjectTask
* @author :lyh
* @method :post
* @time :2025/3/6 9:45
*/
class AiBlogListTask extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'save_ai_blog_list_task';
/**
* The console command description.
*
* @var string
*/
protected $description = '生成blog列表页';
public function handle(){
while (true){
$task_id = $this->getTaskId();
if(empty($task_id)){
sleep(200);
continue;
}
$aiBlogTaskModel = new AiBlogTaskModel();
$info = $aiBlogTaskModel->read(['id'=>$task_id,'type'=>$aiBlogTaskModel::TYPE_LIST]);
if($info === false){
echo date('Y-m-d H:i:s').',当前数据不存在或者已被删除。'.PHP_EOL;
}
$project_id = $info['project_id'];
echo '执行的项目ID:'.$info['project_id'].PHP_EOL;
ProjectServer::useProject($project_id);
$projectAiSettingModel = new ProjectAiSetting();
$aiSettingInfo = $projectAiSettingModel->read(['project_id'=>$project_id]);
$res = $this->updateBlogList($aiSettingInfo);
if($res){
$aiBlogTaskModel->edit(['status'=>2],['id'=>$task_id]);
}else{
if($info['sort'] >= 5){
$aiBlogTaskModel->edit(['status'=>9],['id'=>$task_id]);
}else{
$aiBlogTaskModel->edit(['status'=>9,'sort'=>($info['sort'] + 1)],['id'=>$task_id]);
}
}
$this->curlDelRoute($project_id);
DB::disconnect('custom_mysql');
}
return true;
}
/**
* @remark :更新列表页数据
* @name :updateBlogList
* @author :lyh
* @method :post
* @time :2025/3/5 11:07
*/
public function updateBlogList($aiSettingInfo){
$aiBlogService = new AiBlogService();
$aiBlogService->mch_id = $aiSettingInfo['mch_id'];
$aiBlogService->key = $aiSettingInfo['key'];
$page = 1;
$saveData = [];
$result = $aiBlogService->getAiBlogList($page,15);
if(!isset($result['status']) || $result['status'] != 200){
echo '请求失败。'.json_encode($result, JSON_UNESCAPED_UNICODE);
return false;
}
$total_page = $result['data']['total_page'];
//组装数据保存
$saveData[] = [
'route'=>$page,
'text'=>$result['data']['section'],
];
while ($total_page > $page){
$page++;
$result = $aiBlogService->getAiBlogList($page,15);
if(isset($result['status']) && $result['status'] == 200){
$saveData[] = [
'route'=>$page,
'text'=>$result['data']['section'],
];
}else{
echo '请求失败。'.json_encode($result, JSON_UNESCAPED_UNICODE);
return false;
}
}
$aiBlogListModel = new AiBlogList();
if(!empty($saveData)){
//写一条路由信息
$aiBlogListModel->truncate();
$aiBlogListModel->insertAll($saveData);
return true;
}
return true;
}
/**
* @remark :通知C端生成界面
* @name :sendNotice
* @author :lyh
* @method :post
* @time :2025/3/6 11:51
*/
public function curlDelRoute($project_id){
$domainModel = new DomainInfo();
//获取项目域名
$domain = $domainModel->getProjectIdDomain($project_id);
if(!empty($domain)){
$c_url = $domain.'api/update_page/';
$param = [
'project_id' => $project_id,
'type' => 1,
'route' => 3,
'url' => ['top-blog'],
'language'=> [],
'is_sitemap' => 0
];
http_post($c_url, json_encode($param));
}
return true;
}
/**
* 获取任务id
* @param int $finish_at
* @return mixed
*/
public function getTaskId($finish_at = 2)
{
$keys = 'ai_blog_list_task';
$task_id = Redis::rpop($keys);
if (empty($task_id)) {
$aiBlogTaskModel = new AiBlogTaskModel();
$finish_at = date('Y-m-d H:i:s', strtotime('-' . $finish_at . ' hour'));
$ids = $aiBlogTaskModel->formatQuery(['status'=>$aiBlogTaskModel::STATUS_RUNNING, 'type'=>$aiBlogTaskModel::TYPE_LIST, 'updated_at'=>['<=',$finish_at]])->pluck('id');
if(!empty($ids)){
foreach ($ids as $id) {
Redis::lpush($keys, $id);
}
}
$task_id = Redis::rpop($keys);
}
return $task_id;
}
}
<?php
/**
* @remark :
* @name :AiBlogTask.php
* @author :lyh
* @method :post
* @time :2025/2/14 11:14
*/
namespace App\Console\Commands\Ai;
use App\Helper\Arr;
use App\Models\Ai\AiBlog;
use App\Models\Ai\AiBlogAuthor;
use App\Models\Ai\AiBlogList;
use App\Models\Com\NoticeLog;
use App\Models\Com\Notify;
use App\Models\Devops\ServerConfig;
use App\Models\Devops\ServersIp;
use App\Models\Domain\DomainInfo;
use App\Models\Project\Project;
use App\Models\Project\ProjectAiSetting;
use App\Models\RouteMap\RouteMap;
use App\Services\AiBlogService;
use App\Services\DingService;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use App\Models\Project\AiBlogTask as AiBlogTaskModel;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;
class AiBlogTask extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'save_ai_blog';
public $updateProject = [];//需更新的列表
public $projectSetting = [];
public $routes = [];//需要更新的路由
/**
* The console command description.
*
* @var string
*/
protected $description = '查询ai_blog是否已经生成';
/**
* @return bool
* @throws \Exception
*/
public function handle(){
while (true){
//获取任务id
$task_id = $this->getTaskId();
if(empty($task_id)){
sleep(300);
continue;
}
$this->sendRequest($task_id);
}
return true;
}
/**
* 请求方法
* @param $task_id
* @return bool
* @throws \Exception
*/
public function sendRequest($task_id){
$aiBlogTaskModel = new AiBlogTaskModel();
$item = $aiBlogTaskModel->read(['id'=>$task_id]);
$this->output('start:project ID: ' . $item['project_id'] . ',task ID: ' . $task_id);
//获取配置
$aiSettingInfo = $this->getSetting($item['project_id']);
$aiBlogService = new AiBlogService();
$aiBlogService->mch_id = $aiSettingInfo['mch_id'];
$aiBlogService->key = $aiSettingInfo['key'];
$aiBlogService->task_id = $item['task_id'];
//拉取文章数据
$result = $aiBlogService->getDetail();
if(empty($result['status']) || ($result['status'] != 200)){
if($item['sort'] < 5){
$aiBlogTaskModel->edit(['sort'=>$item['sort'] + 1],['id'=>$item['id']]);
}else{
$aiBlogTaskModel->edit(['status'=>9],['id'=>$item['id']]);
// 钉钉通知
$dingService = new DingService();
$body = [
'keyword' => 'AI_BLOG获取失败',
'msg' => '任务ID:' . $item['task_id'] . PHP_EOL . '返回信息:' . json_encode($result,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
'isAtAll' => false, // 是否@所有人
];
$dingService->handle($body);
}
$this->output('error: 数据获取失败,status:' . $result['status'] . ',message: ' . ($result['message'] ?? 'null'));
return false;
}
//保存当前项目ai_blog数据
ProjectServer::useProject($item['project_id']);
$aiBlogModel = new AiBlog();
$aiBlogInfo = $aiBlogModel->read(['task_id'=>$item['task_id']],['id','route']);
if($aiBlogInfo === false){
// 钉钉通知
$dingService = new DingService();
$body = [
'keyword' => 'AI_BLOG生成错误',
'msg' => '任务ID:' . $item['task_id'] . ', 子库获取数据失败, 检查子库数据是否被删除!',
'isAtAll' => false, // 是否@所有人
];
$dingService->handle($body);
$this->output('error: 子库获取数据失败, task id: ' . $task_id);
$aiBlogTaskModel->edit(['status'=>9],['id'=>$item['id']]);
DB::disconnect('custom_mysql');
return false;
}
//拿到返回的路由查看是否重复
$route = RouteMap::setRoute($result['data']['url'], RouteMap::SOURCE_AI_BLOG, $aiBlogInfo['id'], $item['project_id']);
if($route != $result['data']['url']){
$aiBlogService->updateDetail(['route'=>$route,'task_id'=>$item['task_id']]);
}
//需要更新的路由
if (!in_array($result['data']['author_id'], $this->updateProject[$item['project_id']] ?? [])) {
$this->updateProject[$item['project_id']][] = $result['data']['author_id'];
}
if (!in_array($route, $this->routes[$item['project_id']] ?? [])) {
$this->routes[$item['project_id']][] = $route;
}
$aiBlogModel->edit(['new_title'=>$result['data']['title'], 'image'=>$result['data']['thumb'], 'text'=>$result['data']['section'], 'author_id'=>$result['data']['author_id'],'seo_title'=>$result['data']['title'],'seo_keyword'=>$result['data']['keyword'],'seo_description'=>$result['data']['description'], 'route'=>$route ,'status'=>$aiBlogModel::STATUS_FINISH], ['task_id'=>$item['task_id']]);
DB::disconnect('custom_mysql');
$aiBlogTaskModel->edit(['status'=>$aiBlogModel::STATUS_FINISH],['id'=>$item['id']]);
$this->output('success: task id: ' . $task_id);
return true;
}
/**
* 获取任务id
* @param int $finish_at
* @return mixed
*/
public function getTaskId($finish_at = 2)
{
$task_id = Redis::rpop('ai_blog_task');
if (empty($task_id)) {
if(!empty($this->updateProject)){
$this->updateProject($this->updateProject);
$this->updateProject = [];
}
if(!empty($this->routes)){
$this->updateRoutes($this->routes);
$this->routes = [];
}
$aiBlogTaskModel = new AiBlogTaskModel();
$finish_at = date('Y-m-d H:i:s', strtotime('-' . $finish_at . ' hour'));
$ids = $aiBlogTaskModel->formatQuery(['status'=>$aiBlogTaskModel::STATUS_RUNNING, 'type'=>$aiBlogTaskModel::TYPE_BLOG, 'updated_at'=>['<=',$finish_at]])->pluck('id');
if(!empty($ids)){
foreach ($ids as $id) {
Redis::lpush('ai_blog_task', $id);
}
}
$task_id = Redis::rpop('ai_blog_task');
}
return $task_id;
}
/**
* 更新项目作者页面及列表页
* @param $updateProject
* @return bool
*/
public function updateProject($updateProject){
if(empty($updateProject)){
return true;
}
foreach ($updateProject as $project_id => $author){
ProjectServer::useProject($project_id);
$aiSettingInfo = $this->getSetting($project_id);
$this->output('sync: list start, project_id: ' . $project_id);
$this->updateBlogList($aiSettingInfo,$project_id);
$this->output('sync: list end');
//更新作者
$this->output('sync: author start, project_id: ' . $project_id);
foreach ($author as $val){
$this->updateAiBlogAuthor($aiSettingInfo,$val,$project_id);
}
$this->output('sync: author end');
DB::disconnect('custom_mysql');
}
return true;
}
/**
* 获取项目配置
* @param $project_id
* @return bool
*/
public function getSetting($project_id)
{
$project_setting = $this->projectSetting;
if (FALSE == empty($project_setting[$project_id])){
return $project_setting[$project_id];
}
$projectAiSettingModel = new ProjectAiSetting();
$aiSettingInfo = $projectAiSettingModel->read(['project_id'=>$project_id]);
$this->projectSetting[$project_id] = $aiSettingInfo;
return $aiSettingInfo;
}
/**
* 更新作者的页面
* @param $aiSettingInfo
* @param $author_id
* @return bool
*/
public function updateAiBlogAuthor($aiSettingInfo,$author_id,$project_id){
if(empty($author_id)){
return true;
}
$aiBlogService = new AiBlogService();
$aiBlogService->mch_id = $aiSettingInfo['mch_id'];
$aiBlogService->key = $aiSettingInfo['key'];
$aiBlogService->author_id = $author_id;
$result = $aiBlogService->getAuthorDetail();
if(isset($result['status']) && $result['status'] == 200){
//当前作者的页面
$aiBlogAuthorModel = new AiBlogAuthor();
$authorInfo = $aiBlogAuthorModel->read(['author_id'=>$author_id],['id','route']);
if($authorInfo !== false && !empty($result['data']['section'])){
//需要更新的路由
if (!in_array($authorInfo['route'], $this->routes[$project_id] ?? [])) {
$this->routes[$project_id][] = $authorInfo['route'];
}
$aiBlogAuthorModel->edit(['text'=>$result['data']['section']],['author_id'=>$author_id]);
}
}
return true;
}
/**
* 更新列表页
* @param $aiSettingInfo
* @return bool
*/
public function updateBlogList($aiSettingInfo,$project_id = 0){
$aiBlogService = new AiBlogService();
$aiBlogService->mch_id = $aiSettingInfo['mch_id'];
$aiBlogService->key = $aiSettingInfo['key'];
$page = 1;
$saveData = [];
$result = $aiBlogService->getAiBlogList($page,15);
if(!isset($result['status']) || $result['status'] != 200){
try {
// 钉钉通知
$dingService = new DingService();
$body = [
'keyword' => 'AI_BLOG列表页未生成拉取失败',
'msg' => '项目ID:' . $project_id . PHP_EOL . '返回信息:' . json_encode($result,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
'isAtAll' => false, // 是否@所有人
];
$dingService->handle($body);
//写一条更新记录
$aiBlogTaskModel = new AiBlogTaskModel();
$aiBlogTaskModel->addReturnId(['project_id'=>$project_id,'task_id'=>$project_id,'status'=>$aiBlogTaskModel::STATUS_RUNNING,'type'=>$aiBlogTaskModel::TYPE_LIST]);
}catch (\Exception $e){
$this->output('更新列表页失败同时通知失败--error:' . $e->getMessage());
}
return true;
}
$total_page = $result['data']['total_page'];
//组装数据保存
$saveData[] = [
'route'=>$page,
'text'=>$result['data']['section'],
];
while ($total_page > $page){
$page++;
$result = $aiBlogService->getAiBlogList($page,15);
if(isset($result['status']) && $result['status'] == 200){
$saveData[] = [
'route'=>$page,
'text'=>$result['data']['section'],
];
}
}
$aiBlogListModel = new AiBlogList();
if(!empty($saveData)){
//写一条路由信息
$aiBlogListModel->truncate();
$aiBlogListModel->insertAll($saveData);
}
return true;
}
/**
* 通知C端生成界面
* @param $project_id
* @return bool
*/
public function updateRoutes($routes){
$domainModel = new DomainInfo();
$project_model = new Project();
foreach ($routes as $project_id => $route){
if($project_id == 4339){
continue;
}
$route[] = 'top-blog';
$domain = $domainModel->getProjectIdDomain($project_id);
if (empty($domain)) {
$this->output('send: 域名不存在, project id: ' . $project_id);
continue;
}
//判断是否是自建站服务器,如果是,不请求C端接口,数据直接入库
$project_info = $project_model->read(['id'=>$project_id],['serve_id']);
if(!$project_info){
$this->output('send: 项目不存在, project id: ' . $project_id);
continue;
}
$serve_ip_model = new ServersIp();
$serve_ip_info = $serve_ip_model->read(['id'=>$project_info['serve_id']],['servers_id']);
$servers_id = $serve_ip_info ? $serve_ip_info['servers_id'] : 0;
if($servers_id == ServerConfig::SELF_SITE_ID){
//判断是否已有更新进行中
$notify_model = new Notify();
$data = [
'project_id' => $project_id,
'type' => Notify::TYPE_MASTER,
'route' => Notify::ROUTE_AI_BLOG,
'server_id' => ServerConfig::SELF_SITE_ID,
'status' => ['!=',Notify::STATUS_FINISH_SITEMAP]
];
$notify = $notify_model->read($data,['id']);
if(!$notify){
$domain_array = parse_url($domain);
$data['data'] = Arr::a2s(['domain'=>$domain_array['host'],'url'=>$route,'language'=>[]]);
$data['status'] = Notify::STATUS_INIT;
$data['sort'] = 2;
$notify_model->add($data);
}
$this->output('send: 自建站项目, project id: ' . $project_id);
}else{
$c_url = $domain.'api/update_page/';
$param = [
'project_id' => $project_id,
'type' => 1,
'route' => 3,
'url' => $route,
'language'=> [],
'is_sitemap' => 0
];
$res = http_post($c_url, json_encode($param,true));
if(empty($res)){
NoticeLog::createLog(NoticeLog::GENERATE_PAGE, ['c_url'=>$c_url,'c_params'=>$param],date('Y-m-d H:i:s',time()+300));
}
$this->output('notify: project id: ' . $project_id . ', result: ' . json_encode($res,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
}
}
return true;
}
/**
* 输入日志
* @param $message
* @return bool
*/
public function output($message)
{
$message = date('Y-m-d H:i:s') . ' ' . $message . PHP_EOL;
echo $message;
file_put_contents(storage_path('logs/AiBlog/') . date('Ymd') . '.log', $message, FILE_APPEND);
return true;
}
}
<?php
/**
* @remark :
* @name :AiDomainTask.php
* @author :lyh
* @method :post
* @time :2025/6/19 10:53
*/
namespace App\Console\Commands\Ai;
use App\Models\Domain\DomainInfo;
use Illuminate\Console\Command;
/**
* @remark :拉取项目Ai域名
* @name :AiDomainTask
* @author :lyh
* @method :post
* @time :2025/6/19 10:54
*/
class AiDomainTask extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'ai_domain';
/**
* The console command description.
*
* @var string
*/
protected $description = '获取对应域名的ai复制站域名';
public $url = 'https://www.cmer.site/api/globalso_site';
/**
* @remark :执行方法
* @name :handle
* @author :lyh
* @method :post
* @time :2025/6/19 11:32
*/
public function handle(){
$pageSize = 300;
$page = 1;
$res = http_get($this->url.'?pagesize='.$pageSize.'&page='.$page);
if($res['status'] != 200){
echo date('Y-m-d H:i:s').'请求失败,状态码错误'.PHP_EOL;
return false;
}
if(empty($res['data']['data'])){
echo date('Y-m-d H:i:s').'请求失败,未拉取到数据'.PHP_EOL;
return false;
}
$data = $res['data']['data'];
while($page <= $res['data']['last_page']){
$res = http_get($this->url.'?pagesize='.$pageSize.'&page='.$page);
if($res['status'] != 200){
echo date('Y-m-d H:i:s').'第'.$page.'请求失败,未拉取到数据'.PHP_EOL;
return false;
}
$data = array_values(array_merge($data,$res['data']['data']));
$page++;
}
//处理数据
$this->handleData($data);
echo 'end'.PHP_EOL;
return true;
}
/**
* @remark :处理数据
* @name :handleData
* @author :lyh
* @method :post
* @time :2025/6/19 11:21
*/
public function handleData($data){
$domainInfoModel = new DomainInfo();
foreach ($data as $item){
$info = $domainInfoModel->read(['domain'=>$item['domain']],'id');
if($info === false){
$info = $domainInfoModel->read(['domain'=>$item['globalso_domain']],'id');
if($info !== false){
$domainInfoModel->edit(['ai_domain'=>$item['domain']],['id'=>$info['id']]);
}
}else{
$domainInfoModel->edit(['ai_domain'=>$item['globalso_domain']],['id'=>$info['id']]);
}
}
return true;
}
}
<?php
/**
* @remark :
* @name :AiVideoAutoPublish.php
* @author :lyh
* @method :post
* @time :2025/8/1 15:19
*/
namespace App\Console\Commands\Ai;
use App\Models\Ai\AiVideo;
use App\Models\AyrShare\AyrShare;
use App\Models\Domain\DomainInfo;
use App\Models\Product\Keyword;
use App\Models\Product\Product;
use App\Models\Project\AiBlogTask as AiBlogTaskModel;
use App\Models\Project\AiVideoAutoLog;
use App\Models\Project\DeployOptimize;
use App\Models\Project\Project;
use App\Services\AiVideoService;
use App\Services\MidJourneyService;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Models\Project\AiVideoTask;
use Illuminate\Support\Facades\Redis;
/**
* @remark :ai视频自动发布
* @name :AiVideoAutoPublish
* @author :lyh
* @method :post
* @time :2025/8/1 15:19
*/
class AiVideoAutoPublish extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'ai_video_auto_publish {action}';
/**
* The console command description.
*
* @var string
*/
protected $description = '自动发布AI Video';
public function handle(){
$action = $this->argument('action');
if($action == 'auto_publish'){
$this->auto_publish();
}
if($action == 'auto_send_video'){
$this->auto_send_video();
}
if($action == 'auto_save_video_task'){
$this->auto_save_video_task();
}
}
/**
* @remark :自动发布aiVideo组装数据(写入一条记录)
* @name :auto_six_publish
* @author :lyh
* @method :post
* @time :2025/8/1 15:22
*/
public function auto_publish(){
$this->output('开始自动发布Video文章');
$projectModel = new Project();
$optimizeModel = new DeployOptimize();
$projectList = $projectModel->list(['is_ai_video'=>1,'type'=>['in',[1,2,3,4,6]],'delete_status'=>0,'site_status'=>0,'extend_type'=>0],'id',['id','project_type']);
foreach ($projectList as $item){
$this->output("项目{$item['id']}开始自动发布");
//获取当前是否开启自动发布aiVideo
$opInfo = $optimizeModel->read(['project_id'=>$item['id']],['is_ai_video_send','send_ai_video_frequency','start_date']);
if($opInfo['is_ai_video_send'] != 1){
$this->output("项目{$item['id']}未开启自动发布" . $opInfo['start_date']);
continue;
}
if(($opInfo['start_date'] > date('Y-m-d')) || empty($opInfo['start_date'])){
$this->output("项目{$item['id']}未到推广时间" . $opInfo['start_date']);
continue;
}
$aiVideoTaskModel = new AiVideoTask();
$next_auto_date = $aiVideoTaskModel->formatQuery(['project_id'=>$item['id'],'next_auto_date'=>['!=',null]])->orderBy('id', 'desc')->value('next_auto_date');
if($next_auto_date && ($next_auto_date > date('Y-m-d'))){
$this->output("项目{$item['id']}未到执行时间" . $next_auto_date);
continue;
}
if($item['project_type'] == 1){
//todo::页面上获取数据
$data = $this->getAiVideoParam($item['id']);
}else{
//获取当前网站的标题
ProjectServer::useProject($item['id']);
$data = $this->getVideoInfo();
DB::disconnect('custom_mysql');
}
if(!empty($data)){
//写入一条零时生成视频记录
$aiVideoAutoLogModel = new AiVideoAutoLog();
$aiVideoAutoLogModel->addReturnId(
['project_id'=>$item['id'],'title'=>$data['title'],'remark'=>$data['remark'],'images'=>json_encode($data['images'],true),'date'=>date('Y-m-d')]
);
}
}
return true;
}
/**
* @remark :获取产品标题+产品描述
* @name :getProduct
* @author :lyh
* @method :post
* @time :2025/8/1 16:09
*/
public function getVideoInfo(){
$data = [];
$random = rand(1, 2);
if($random == 1){//取产品
$productModel = new Product();
$info = $productModel->formatQuery(['status'=>1,'title'=>['!=',null],'intro'=>['!=',null]])->select(['title','gallery','intro'])->inRandomOrder()->first();
if(empty($info)){
return $data;
}
$data['title'] = $info['title'];
$data['remark'] = $info['intro'];
$data['images'] = array_filter(array_map(function ($item) use ($data) {
if (!empty($item['url'])) {
return [
'alt' => $item['title'] ?? $data['title'],
'url' => getImageUrl($item['url']),
];
}
return null;
}, $info['gallery']));
return $data;
}else{
//聚合页获取当前关联产品的图片
$keywordModel = new Keyword();
$keywordInfo = $keywordModel->formatQuery(['keyword_title'=>['!=',null],'keyword_content'=>['!=',null]])->select(['keyword_title','keyword_content'])->inRandomOrder()->first();
if(empty($keywordInfo)){
return $data;
}
$data['title'] = $keywordInfo['keyword_title'];
$data['remark'] = $keywordInfo['keyword_content'];
$data['remark'] = strip_tags($keywordInfo['intro']);
if(empty($data['remark'])){
$data['remark'] = $data['title'];
}
$data['images'] = [];
$productModel = new Product();
$productList = $productModel->list(['keyword_id'=>['like','%,'.$keywordInfo['id'].',%']],'id',['gallery'],'desc',10);
foreach ($productList as $info){
$images = array_filter(array_map(function ($item) use ($data) {
if (!empty($item['url'])) {
return [
'alt' => $item['title'] ?? $data['title'],
'url' => getImageUrl($item['url']),
];
}
return null; // 返回 null 让 array_filter 去除
}, $info['gallery']));
$data['images'] = array_merge($data['images'],$images);
}
return $data;
}
}
/**
* @remark :组装缺少图片数据-推送至发送平台
* @name :send_video
* @author :lyh
* @method :post
* @time :2025/8/2 10:37
*/
public function auto_send_video(){
$number = Redis::get('ai_video_image') ?? 0;
$aiVideoAutoLogModel = new AiVideoAutoLog();
while (true){
if($number > 5){
echo date('Y-m-d H:i:s').':当前生成图片数量已达到最大限度。'.$number.PHP_EOL;
sleep(300);
continue;
}
$item = $aiVideoAutoLogModel->read(['status'=>0,'trigger_id'=>null]);
if($item === false){
sleep(60);
continue;
}
if(count($item['images']) < 6){
echo date('Y-m-d H:i:s').':提交生成图片。'.$item['project_id'].PHP_EOL;
//需要生成图片
$content = "{$item['remark']}{$item['title']}4K,高清 --no logo --ar 16:9";
$midJourneyService = new MidJourneyService();
$result = $midJourneyService->imagine($content);
if($result && !empty($result['trigger_id'])){
echo '提交的数据详情。'.json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES).$item['project_id'].PHP_EOL;
Redis::incr('ai_video_image');
$aiVideoAutoLogModel->edit(['trigger_id'=>$result['trigger_id']],['id'=>$item['id']]);
}
}else{
//提交到待执行
$aiVideoAutoLogModel->edit(['status'=>1],['id'=>$item['id']]);
}
}
}
/**
* @remark :状态为1的数据推送至生成视频任务表
* @name :auto_save_video_task
* @author :lyh
* @method :post
* @time :2025/8/4 9:39
*/
public function auto_save_video_task(){
$aiVideoAutoLogModel = new AiVideoAutoLog();
while (true){
//获取任务id
$task_id = $this->getAutoTaskId();
if(empty($task_id)){
sleep(300);
continue;
}
$info = $aiVideoAutoLogModel->read(['id'=>$task_id]);
if($info === false){
$this->output(date('Y-m-d H:i:s').':当前数据不存在或已被删除'.$task_id);
continue;
}
try {
$aiVideoTaskModel = new AiVideoTask();
$aiVideoService = new AiVideoService($info['project_id']);
$projectModel = new DeployOptimize();
$video_setting = $projectModel->getValue(['project_id'=>$info['project_id']],'video_setting');
$frequency_setting = $projectModel->getValue(['project_id'=>$info['project_id']],'send_ai_video_frequency');
$storage = $aiVideoTaskModel->videoSetting()[$video_setting ?? 1];
$frequency = $aiVideoTaskModel->videoFrequency()[$frequency_setting ?? 1];
$frequencyArr = explode('-',$frequency);
if($storage == 'YOUTUBE'){
//查看是否有ayr账号
$ayrModel = new AyrShare();
$ayrInfo = $ayrModel->read(['project_id'=>$this->param['project_id'],'bind_platforms'=>['like','%"youtube"%'],'profile_key'=>['!=',null]]);
if($ayrInfo !== false){
$ayrshare_profile_key = $ayrInfo['profile_key'];
}
}
$result = $aiVideoService->createTask($info['title'],$info['remark'],array_slice($info['images'], 0, 8),[],$storage,$ayrshare_profile_key ?? '');
if($result['status'] == 200){
$next_auto_date = date('Y-m-d', strtotime('+' . mt_rand($frequencyArr[0] ?? 5,$frequencyArr[1] ?? 7) . 'days')); //每5-7天自动发布
$aiVideoTaskModel->addReturnId(['next_auto_date'=>$next_auto_date,'task_id'=>$result['data']['task_id'],'project_id'=>$info['project_id'],'storage'=>$storage]);
ProjectServer::useProject($info['project_id']);
$aiVideoModel = new AiVideo();
$aiVideoModel->addReturnId(['title'=>$info['title'],'task_id'=>$result['data']['task_id'],'description'=>$info['remark'],'project_id'=>$info['project_id'],'images'=>json_encode($info['images'],true),'anchor'=>json_encode([],true)]);
DB::disconnect('custom_mysql');
$aiVideoAutoLogModel->edit(['status'=>2],['id'=>$info['id']]);
}else{
$aiVideoAutoLogModel->edit(['status'=>3],['id'=>$info['id']]);
}
}catch (\Exception $e){
$this->output( date('Y-m-d H:i:s').':当前数据不存在或已被删除'.$task_id);
continue;
}
}
}
/**
* @remark :火锅自动发布任务id
* @name :getAutoTaskId
* @author :lyh
* @method :post
* @time :2025/8/4 9:44
*/
public function getAutoTaskId()
{
$task_id = Redis::rpop('auto_ai_video_task');
if (empty($task_id)) {
$aiVideoAutoLogModel = new AiVideoAutoLog();
$ids = $aiVideoAutoLogModel->formatQuery(['status'=>1])->pluck('id');
if(!empty($ids)){
foreach ($ids as $id) {
Redis::lpush('auto_ai_video_task', $id);
}
}
$task_id = Redis::rpop('auto_ai_video_task');
}
return $task_id;
}
/**
* @remark :页面获取
* @name :getAiVideoParam
* @author :lyh
* @method :post
* @time :2025/8/1 16:25
*/
public function getAiVideoParam($project_id)
{
//获取当前网站域名
$domainModel = new DomainInfo();
$domain = $domainModel->getValue(['project_id'=>$project_id],'domain');
if(empty($domain)){
return true;
}
$domain = str_replace('blog.', 'www.', $domain);
//todo::看是否获取建站的产品数据
try {
$sitemap_url = 'https://' . $domain . '/sitemap_post_tag.xml';
$sitemap_string = file_get_contents($sitemap_url);
$xml = new \SimpleXMLElement($sitemap_string);
$json = json_encode($xml);
$array = json_decode($json, true);
$urls = array_column($array['url'], 'loc');
$num = 0;
if ($num >= 10) {
return false;
}
AGAIN:
$url = $urls[array_rand($urls)];
$dom = file_get_html($url);
$h1 = $dom->find('.layout .global_section h1', 0);
$title = $h1 ? trim($h1->plaintext) : '';
$p = $dom->find('.layout .global_section p', 0);
$content = $p ? trim($p->plaintext) : '';
$img = $dom->find('.layout .global_section img');
$images = [];
foreach ($img as $item) {
if (empty($item->src) || empty($item->alt)){
continue;
}
array_push($images, ['url' => $item->src, 'alt' => $item->alt]);
}
if (empty($title) || empty($content) || empty($images)) {
$num++;
goto AGAIN;
}
return ['title'=>$title,'remark'=>$content,'images'=>$images];
} catch (\Exception $e) {
$this->output('project_id: ' . $project_id . ', domain: ' . $domain . ', error: ' . $e->getMessage());
echo 'project_id: ' . $project_id . ', domain: ' . $domain . ', error: ' . $e->getMessage() . PHP_EOL;
return [];
}
}
/**
* @remark :日志
* @name :output
* @author :lyh
* @method :post
* @time :2025/8/1 15:28
*/
public function output($message)
{
Log::channel('ai_video')->info($message);
echo date('Y-m-d H:i:s') . ' ' . $message . PHP_EOL;
}
}
<?php
/**
* @remark :
* @name :AiBlogTask.php
* @author :lyh
* @method :post
* @time :2025/2/14 11:14
*/
namespace App\Console\Commands\Ai;
use App\Models\Ai\AiBlog;
use App\Models\Ai\AiBlogAuthor;
use App\Models\Ai\AiBlogList;
use App\Models\Ai\AiVideoList;
use App\Models\Domain\DomainInfo;
use App\Models\Project\ProjectAiSetting;
use App\Models\RouteMap\RouteMap;
use App\Services\AiBlogService;
use App\Services\AiVideoService;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use App\Models\Project\AiBlogTask as AiBlogTaskModel;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use function Symfony\Component\String\s;
/***
* @remark :根据项目更新blog列表
* @name :AiBlogListProjectTask
* @author :lyh
* @method :post
* @time :2025/3/6 9:45
*/
class AiVideoListTask extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'save_ai_video_list {project_id}';
/**
* The console command description.
*
* @var string
*/
protected $description = '生成video列表';
public function handle(){
$project_id = $this->argument('project_id');
@file_put_contents(storage_path('logs/lyh_error.log'), var_export('执行的项目id->'.$project_id, true) . PHP_EOL, FILE_APPEND);
ProjectServer::useProject($project_id);
$this->updateBlogList($project_id);
$this->curlDelRoute($project_id);
DB::disconnect('custom_mysql');
return true;
}
/**
* @remark :更新列表页数据
* @name :updateBlogList
* @author :lyh
* @method :post
* @time :2025/3/5 11:07
*/
public function updateBlogList($project_id){
$aiVideoService = new AiVideoService($project_id);
$page = 1;
$saveData = [];
$result = $aiVideoService->getAiVideoList($page,15);
if(!isset($result['status']) && $result['status'] != 200){
return true;
}
$total_page = $result['data']['total_page'];
//组装数据保存
$saveData[] = [
'route'=>$page,
'text'=>$result['data']['section'],
];
while ($total_page > $page){
$page++;
$result = $aiVideoService->getAiVideoList($page,15);
if(isset($result['status']) && $result['status'] == 200){
$saveData[] = [
'route'=>$page,
'text'=>$result['data']['section'],
];
}
}
$aiVideoListModel = new AiVideoList();
if(!empty($saveData)){
//写一条路由信息
$aiVideoListModel->truncate();
$aiVideoListModel->insertAll($saveData);
}
return true;
}
/**
* @remark :通知C端生成界面
* @name :sendNotice
* @author :lyh
* @method :post
* @time :2025/3/6 11:51
*/
public function curlDelRoute($project_id){
$domainModel = new DomainInfo();
//获取项目域名
$domain = $domainModel->getProjectIdDomain($project_id);
if(!empty($domain)){
$c_url = $domain.'api/update_page/';
$param = [
'project_id' => $project_id,
'type' => 1,
'route' => 3,
'url' => ['top-blog'],
'language'=> [],
'is_sitemap' => 0
];
http_post($c_url, json_encode($param));
}
return true;
}
}
<?php
/**
* @remark :
* @name :AiVideoTask.php
* @author :lyh
* @method :post
* @time :2025/4/30 11:18
*/
namespace App\Console\Commands\Ai;
use App\Helper\Arr;
use App\Models\Ai\AiBlogAuthor;
use App\Models\Ai\AiVideo;
use App\Models\Ai\AiVideoList;
use App\Models\Com\Notify;
use App\Models\Devops\ServerConfig;
use App\Models\Devops\ServersIp;
use App\Models\Domain\DomainInfo;
use App\Models\Project\AiVideoTask as AiVideoTaskModel;
use App\Models\Project\Project;
use App\Models\RouteMap\RouteMap;
use App\Services\AiBlogService;
use App\Services\AiVideoService;
use App\Services\DingService;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;
class AiVideoTask extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'save_ai_video';
public $updateProject = [];//需更新的列表
public $routes = [];//需要更新的路由
/**
* The console command description.
*
* @var string
*/
protected $description = '查询ai_video是否已经生成';
/**
* @return bool
* @throws \Exception
*/
public function handle(){
while (true){
//获取任务id
$task_id = $this->getTaskId();
if(empty($task_id)){
sleep(300);
continue;
}
$this->_action($task_id);
}
return true;
}
/**
* 获取任务id
* @param int $finish_at
* @return mixed
*/
public function getTaskId($finish_at = 2)
{
$task_id = Redis::rpop('ai_video_task');
if (empty($task_id)) {
if(!empty($this->updateProject)){
$this->updateProject($this->updateProject);
$this->updateProject = [];
}
if(!empty($this->routes)){
$this->updateRoutes($this->routes);
$this->routes = [];
}
$aiVideoTaskModel = new AiVideoTaskModel();
$finish_at = date('Y-m-d H:i:s', strtotime('-' . $finish_at . ' hour'));
$ids = $aiVideoTaskModel->formatQuery(['status'=>$aiVideoTaskModel::STATUS_RUNNING,'updated_at'=>['<=',$finish_at]])->pluck('id');
if(!empty($ids)){
foreach ($ids as $id) {
Redis::lpush('ai_video_task', $id);
}
}
$task_id = Redis::rpop('ai_video_task');
}
return $task_id;
}
/**
* @remark :请求
* @name :sendRequest
* @author :lyh
* @method :post
* @time :2025/4/30 11:31
*/
public function _action($task_id){
$aiVideoTaskModel = new AiVideoTaskModel();
$item = $aiVideoTaskModel->read(['id'=>$task_id]);
$this->output('ai_video->start:project ID: ' . $item['project_id'] . ',task ID: ' . $task_id);
$aiVideoService = new AiVideoService($item['project_id']);
$aiVideoService->task_id = $item['task_id'];
//拉取文章数据
$result = $aiVideoService->getVideoDetail();
if(empty($result['status']) || ($result['status'] != 200)){
if($item['number'] < 5){
$aiVideoTaskModel->edit(['number'=>$item['number'] + 1],['id'=>$item['id']]);
}else{
$aiVideoTaskModel->edit(['status'=>9],['id'=>$item['id']]);
// 钉钉通知
$dingService = new DingService();
$body = [
'keyword' => 'AI_VIDEO获取失败',
'msg' => '任务ID:' . $item['task_id'] . PHP_EOL . '返回信息:' . json_encode($result,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
'isAtAll' => false, // 是否@所有人
];
$dingService->handle($body);
}
$this->output('error: 数据获取失败,status:' . $result['status'] . ',message: ' . ($result['message'] ?? 'null'));
return false;
}
//保存当前项目ai_blog数据
ProjectServer::useProject($item['project_id']);
$aiVideoModel = new AiVideo();
$aiVideoInfo = $aiVideoModel->read(['task_id'=>$item['task_id']],['id','route']);
if($aiVideoInfo === false){
// 钉钉通知
$dingService = new DingService();
$body = [
'keyword' => 'AI_VIDEO生成错误',
'msg' => '任务ID:' . $item['task_id'] . ', 子库获取数据失败, 检查子库数据是否被删除!',
'isAtAll' => false, // 是否@所有人
];
$dingService->handle($body);
$this->output('error: 子库获取数据失败, task id: ' . $task_id);
$aiVideoTaskModel->edit(['status'=>9],['id'=>$item['id']]);
DB::disconnect('custom_mysql');
return false;
}
//拿到返回的路由查看是否重复
$route = RouteMap::setRoute($result['data']['url'], RouteMap::SOURCE_AI_VIDEO, $aiVideoInfo['id'], $item['project_id']);
if($route != $result['data']['url']){
$aiVideoService->updateDetail(['url'=>$route,'task_id'=>$item['task_id']]);
}
$saveData = [
'title'=>$result['data']['title'],
'image'=>$result['data']['thumb'],
'video_url'=>$result['data']['video_url'],
'route'=>$route,
'author_id'=>$result['data']['author_id'],
'keyword'=>json_encode($result['data']['keyword'],true),
'content'=>$result['data']['content'],
'text'=>$result['data']['section'],
'status'=>$aiVideoTaskModel::STATUS_FINISH,
'seo_title'=>$result['data']['title'],
'seo_keyword'=>implode(',',$result['data']['keyword']),
'seo_description'=>$result['data']['description'] ?? '',
];
$aiVideoModel->edit($saveData,['task_id'=>$item['task_id']]);
//需要更新的路由
if (!in_array($result['data']['author_id'], $this->updateProject[$item['project_id']] ?? [])) {
$this->updateProject[$item['project_id']][] = $result['data']['author_id'];
}
if (!in_array($route, $this->routes[$item['project_id']] ?? [])) {
$this->routes[$item['project_id']][] = $route;
}
DB::disconnect('custom_mysql');
$aiVideoTaskModel->edit(['status'=>$aiVideoTaskModel::STATUS_FINISH],['id'=>$item['id']]);
$this->output('success: task id: ' . $task_id);
return true;
}
/**
* @remark :更新项目作者页面及列表页
* @name :updateProject
* @author :lyh
* @method :post
* @time :2025/4/30 15:43
*/
public function updateProject($updateProject){
if(empty($updateProject)){
return true;
}
foreach ($updateProject as $project_id => $author){
ProjectServer::useProject($project_id);
$this->output('sync: list start, project_id: ' . $project_id);
$this->updateBlogList($project_id);
$this->output('sync: list end');
//更新作者
$this->output('sync: author start, project_id: ' . $project_id);
foreach ($author as $val){
$this->updateAiBlogAuthor($val,$project_id);
}
$this->output('sync: author end');
DB::disconnect('custom_mysql');
}
return true;
}
/**
* @remark :更新作者页面
* @name :updateAiBlogAuthor
* @author :lyh
* @method :post
* @time :2025/4/30 15:52
*/
public function updateAiBlogAuthor($author_id,$project_id){
if(empty($author_id)){
return true;
}
$aiBlogService = new AiBlogService($project_id);
$aiBlogService->author_id = $author_id;
$result = $aiBlogService->getAuthorDetail();
if(isset($result['status']) && $result['status'] == 200){
//当前作者的页面
$aiBlogAuthorModel = new AiBlogAuthor();
$authorInfo = $aiBlogAuthorModel->read(['author_id'=>$author_id],['id','route']);
if($authorInfo !== false && !empty($result['data']['section'])){
//需要更新的路由
if (!in_array($authorInfo['route'], $this->routes[$project_id] ?? [])) {
$this->routes[$project_id][] = $authorInfo['route'];
}
$aiBlogAuthorModel->edit(['text'=>$result['data']['section']],['author_id'=>$author_id]);
}
}
return true;
}
/**
* @remark :更新
* @name :updateBlogList
* @author :lyh
* @method :post
* @time :2025/4/30 15:45
*/
public function updateBlogList($project_id){
$aiVideoService = new AiVideoService($project_id);
$page = 1;
$saveData = [];
$result = $aiVideoService->getAiVideoList($page,15);
if(!isset($result['status']) && $result['status'] != 200){
return true;
}
$total_page = $result['data']['total_page'];
//组装数据保存
$saveData[] = [
'route'=>$page,
'text'=>$result['data']['section'],
];
while ($total_page > $page){
$page++;
$result = $aiVideoService->getAiVideoList($page,15);
if(isset($result['status']) && $result['status'] == 200){
$saveData[] = [
'route'=>$page,
'text'=>$result['data']['section'],
];
}
}
$aiVideoListModel = new AiVideoList();
if(!empty($saveData)){
//写一条路由信息
RouteMap::setRoute('top-video',RouteMap::SOURCE_AI_VIDEO_LIST,0,$project_id);//写一条列表页路由
$aiVideoListModel->truncate();
$aiVideoListModel->insertAll($saveData);
}
return true;
}
/**
* 输入日志
* @param $message
* @return bool
*/
public function output($message)
{
$message = date('Y-m-d H:i:s') . ' ' . $message . PHP_EOL;
echo $message;
return true;
}
/**
* 通知C端生成界面
* @param $project_id
* @return bool
*/
public function updateRoutes($routes){
$domainModel = new DomainInfo();
$project_model = new Project();
foreach ($routes as $project_id => $route){
$route[] = 'top-video';
$domain = $domainModel->getProjectIdDomain($project_id);
if (empty($domain)) {
$this->output('send: 域名不存在, project id: ' . $project_id);
continue;
}
//判断是否是自建站服务器,如果是,不请求C端接口,数据直接入库
$project_info = $project_model->read(['id'=>$project_id],['serve_id']);
if(!$project_info){
$this->output('send: 项目不存在, project id: ' . $project_id);
continue;
}
$serve_ip_model = new ServersIp();
$serve_ip_info = $serve_ip_model->read(['id'=>$project_info['serve_id']],['servers_id']);
$servers_id = $serve_ip_info ? $serve_ip_info['servers_id'] : 0;
if($servers_id == ServerConfig::SELF_SITE_ID){
//判断是否已有更新进行中
$notify_model = new Notify();
$data = [
'project_id' => $project_id,
'type' => Notify::TYPE_MASTER,
'route' => Notify::ROUTE_AI_BLOG,
'server_id' => ServerConfig::SELF_SITE_ID,
'status' => ['!=',Notify::STATUS_FINISH_SITEMAP]
];
$notify = $notify_model->read($data,['id']);
if(!$notify){
$domain_array = parse_url($domain);
$data['data'] = Arr::a2s(['domain'=>$domain_array['host'],'url'=>$route,'language'=>[]]);
$data['status'] = Notify::STATUS_INIT;
$data['sort'] = 2;
$notify_model->add($data);
}
$this->output('send: 自建站项目, project id: ' . $project_id);
}else{
$c_url = $domain.'api/update_page/';
$param = [
'project_id' => $project_id,
'type' => 1,
'route' => 3,
'url' => $route,
'language'=> [],
'is_sitemap' => 0
];
$res = http_post($c_url, json_encode($param,true));
$this->output('notify: project id: ' . $project_id . ', result: ' . json_encode($res,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
}
}
return true;
}
}
<?php
/**
* @remark :
* @name :AuthorityScore.php
* @author :lyh
* @method :post
* @time :2025/7/1 16:43
*/
namespace App\Console\Commands\AuthorityScore;
use App\Models\AuthorityScore\AuthorityScore as AuthorityScoreModel;
use App\Models\Domain\DomainInfo;
use App\Models\Project\Project;
use Illuminate\Console\Command;
class AuthorityScore extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'authority_score';
/**
* The console command description.
*
* @var string
*/
protected $description = '白帽外链数据详情,每月统计一次';
/**
* @remark :执行方法
* @name :handle
* @author :lyh
* @method :post
* @time :2025/7/1 16:46
*/
public function handle(){
$projectModel = new Project();
$projectIdArr = $projectModel->selectField(['project_type'=>1,'delete_status' => 0,'extend_type'=>0,'type'=>2],'id');
$domainModel = new DomainInfo();
$url = 'https://www.cmer.site/api/domain/organic?domain=';
foreach ($projectIdArr as $item){
$domainInfo = $domainModel->read(['project_id'=>$item],['domain']);
if($domainInfo === false){
continue;
}
echo '执行的项目id'.$item.PHP_EOL;
$urls = $url.$domainInfo['domain'];
echo $urls.PHP_EOL;
$data = http_get($urls);
if(!empty($data) && !empty($data['data'])){
echo json_encode($data).PHP_EOL;
$data = $data['data'];
$this->saveHandleData($data,$item);
}
}
return true;
}
/**
* @remark :保存数据
* @name :handleData
* @author :lyh
* @method :post
* @time :2025/7/1 17:23
*/
public function saveHandleData($data,$project_id){
$authorityScoreModel = new AuthorityScoreModel();
return $authorityScoreModel->addReturnId([
'project_id'=>$project_id,
'ascore'=>(int)($data['ascore'] ?? 0),
'total'=>(int)($data['total'] ?? 0),
'domains_num'=>(int)($data['domains_num'] ?? 0),
'rank'=>(int)($data['Rank'] ?? 0),
'organic_keywords'=>(int)($data['Organic_Keywords'] ?? 0),
'organic_traffic'=>(int)($data['Organic_Traffic'] ?? 0),
'date'=>date('Y-m-d')
]);
}
}
<?php
namespace App\Console\Commands\AyrShare;
use App\Helper\AyrShare as AyrShareHelper;
use App\Models\AyrShare\AyrShare as AyrShareModel;
use Illuminate\Console\Command;
class ShareConfig extends Command
{
public $error = 0;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'share_config';
/**
* The console command description.
*
* @var string
*/
protected $description = '更新用户Ayr_share配置';
/**
* @name :(定时执行更新用户配置)handle
* @author :lyh
* @method :post
* @time :2023/5/12 14:48
*/
public function handle()
{
$ayrShareModel = new AyrShareModel();
//更新用户配置
$lists = $ayrShareModel->lists($this->map,$this->page,$this->row,'id',['id','profile_key','bind_plat_from']);
foreach ($lists['list'] as $k => $v){
if(empty($v['profile_key'])){
continue;
}
//获取当前用户配置
$ayrShareHelper = new AyrShareHelper();
$share_info = $ayrShareHelper->get_profiles_users($v['profile_key']);
if(!isset($share_info['activeSocialAccounts'])){
$ayrShareModel->edit(['bind_plat_from'=>''],['id'=>$v['id']]);
continue;
}
$str = json_encode($share_info['activeSocialAccounts']);
if($str != $v['bind_plat_from']){
$rs = $ayrShareModel->edit(['bind_plat_from'=>$str],['id'=>$v['id']]);
if($rs === false){
$this->error++;
}
}
}
echo $this->error;
}
}
<?php
namespace App\Console\Commands\AyrShare;
use App\Helper\AyrShare as AyrShareHelper;
use App\Models\Ai\AiVideo;
use App\Models\AyrShare\AyrRelease as AyrReleaseModel;
use App\Models\Project\AiVideoTask;
use App\Services\ProjectServer;
use Carbon\Carbon;
use App\Models\AyrShare\AyrShare as AyrShareModel;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class ShareUser extends Command
{
public $error = 0;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'share_user';
/**
* The console command description.
*
* @var string
*/
protected $description = '用户一周内无记录清除Ayr_share';
/**
* @name :(定时执行)handle
* @author :lyh
* @method :post
* @time :2023/5/12 14:48
*/
public function handle()
{
$this->output('start');
$this->user_operator_record();
return true;
}
/**
* @name : 检测用户是否无操作记录
* @author :lyh
* @method :post
* @time :2023/5/12 14:55
*/
protected function user_operator_record(){
//获取所有ayr_share用户
$ayr_share_model = new AyrShareModel();
$ayr_release = new AyrReleaseModel();
$ayr_share_list = $ayr_share_model->list(['profile_key'=>['!=','']]);
foreach ($ayr_share_list as $v){
$this->output('执行数据的邮箱--'.$v['title']);
$time = Carbon::now()->modify('-1 days')->toDateString();
//创建时间小于7天前的当前时间
if($v['created_at'] > $time){
$this->output('创建时间小于7天跳过--'.$v['title']);
continue;
}
//查询当前用户是否有未推送的博文
$release_info = $this->release_info($ayr_release,$v);
//有推文时,直接跳出循环
if($release_info !== false){
$this->output('有未推送的推文直接跳过--'.$v['title']);
continue;
}
//查询7天是否发送博文
$release_info = $this->release_seven_info($ayr_release,$v);
//有发送博文,则跳出循环
if($release_info !== false){
$this->output('7天内有推文跳过--'.$v['title']);
continue;
}
$aiVideoInfo = $this->aiVideoInfo($v['project_id'] ?? 0);
if($aiVideoInfo !== false){
$this->output('7天内有ai视频推送跳过--'.$v['title']);
continue;
}
//删除用户第三方配置
if(!empty($v['profile_key'])){
$res = $this->del_profiles($v);
if($res === false){
continue;
}
}
//更新数据库
$this->save_ayr_share($ayr_share_model,$v);
}
return $this->error;
}
/**
* @name :(删除第三方配置)del_profiles
* @author :lyh
* @method :post
* @time :2023/6/14 16:10
*/
public function del_profiles($v){
$ayr_share_helper = new AyrShareHelper();
$data_profiles = [
'title'=>$v['title'],
'profileKey'=>$v['profile_key']
];
$res = $ayr_share_helper->deleted_profiles($data_profiles);
if($res['status'] == 'fail'){
$this->output('第三方删除失败'.json_encode($data_profiles,true));
return false;
}
return true;
}
/**
* @name :(更新数据库)save_ayr_share
* @author :lyh
* @method :post
* @time :2023/6/14 16:14
*/
public function save_ayr_share(&$ayr_share_model,$v){
//更新数据库
$data = [
'title'=>'',
'bind_platforms'=>'',
'profile_key'=>'',
'ref_id'=>'',
];
$res = $ayr_share_model->edit($data,['id'=>$v['id']]);
if($res == false){
echo '更新数据库失败';
return true;
}
return true;
}
/**
* @name :(查询是否有定时发送报文)info
* @author :lyh
* @method :post
* @time :2023/6/14 16:17
*/
public function release_info(&$ayr_release,$v){
//查询当前用户是否有未推送的博文
$release_info = $ayr_release->read(['schedule_date'=>['>',date('Y-m-d H:i:s',time())],'share_id'=>$v['id']]);
return $release_info;
}
/**
* @param $ayr_release
* @name :7天内无发送记录release_seven_info
* @author :lyh
* @method :post
* @time :2023/6/14 16:28
*/
public function release_seven_info(&$ayr_release,$v){
//查看用户是否在一周内有发送博客
$start_at = Carbon::now()->modify('-7 days')->toDateString();
$end_at = Carbon::now()->toDateString();
$release_info = $ayr_release->read(['created_at'=>['between',[$start_at,$end_at]],'share_id'=>$v['id']]);
return $release_info;
}
/**
* @remark :7天内是否推送了ai视频
* @name :aiVidoe
* @author :lyh
* @method :post
* @time :2025/9/22 17:13
*/
public function aiVideoInfo($project_id)
{
if($project_id == 0){
return false;
}
$start_at = Carbon::now()->modify('-7 days')->toDateString();
$end_at = Carbon::now()->toDateString();
$aiVideoModel = new AiVideoTask();
$videoInfo = $aiVideoModel->read(['project_id'=>$project_id,'next_auto_date'=>null,'created_at'=>['between',[$start_at,$end_at]]]);
return $videoInfo;
}
/**
* 输入日志
* @param $message
* @return bool
*/
public function output($message)
{
$message = date('Y-m-d H:i:s') . ' ' . $message . PHP_EOL;
echo $message;
file_put_contents(storage_path('logs/share_user/') . date('Ymd') . '.log', $message, FILE_APPEND);
return true;
}
}
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
/**
* TODO:: 如果想要在终止 任务时不让数据丢失或者异常,请使用此类
* @author:dc
* @time 2023/8/21 11:03
* Class CmdSignal
* @package App\Console\Commands
*/
trait CmdSignal
{
/**
* 是否停止
* @var bool
*/
public $isStop = false;
/**
* 超时未退出,强制退出 暂时未实现
* @var int
*/
public $stopTimeOut = 30;
public $debugLogFile = null;
/**
* 调试输出
* @param $msg
* @author:dc
* @time 2023/8/21 11:22
*/
public function debug_echo($msg){
if($this->debugLogFile){
@file_put_contents($this->debugLogFile,date('Y-m-d H:i:s')." ===> ".print_r($msg,1).PHP_EOL,FILE_APPEND);
}else{
echo date('Y-m-d H:i:s')." ===> ".print_r($msg,1).PHP_EOL;
}
}
/**
* @return bool
*/
public function handle()
{
if($this->isRunning()){
$this->debug_echo('脚本已运行,请无重复运行');
return 1;
}
$this->debug_echo('已启动脚本');
// 启动时
if(method_exists($this,'init')){
$this->init();
}
// 注册信号处理程序
// SIGHUP:终端控制进程时终止或挂起进程
//SIGINT:中断进程(通常由CTRL+C发出)
//SIGQUIT:退出进程并生成核心转储
//SIGILL:非法指令
//SIGABRT:由调试程序触发的异常终止信号
//SIGFPE:浮点异常
//SIGKILL:无条件终止进程
//SIGSEGV:无效的内存引用
//SIGPIPE:写入已关闭的FIFO或套接字时产生的信号
//SIGTERM:要求终止进程的信号
//SIGUSR1:用户定义的信号1
//SIGUSR2:用户定义的信号2
$handler = function ($signal){
// 可以处理其他程序
$this->isStop = true;
};
pcntl_signal(SIGTERM, $handler);
pcntl_signal(SIGINT, $handler);
// pcntl_signal(SIGHUP, $handler);
// 检查是否接收到信号
pcntl_signal_dispatch();
$tryNum = 0;
// 无限循环,模拟进程运行
while (true) {
// 做一些工作... 异常超过5次就重启下进程
if($this->isStop || $tryNum>5){
break;
}
try {
$this->start();
}catch (\Throwable $e){
$tryNum++;
// 保证此程序正常
$this->debug_echo('异常消息:'.$e->getMessage());
$this->debug_echo('异常文件:'.$e->getFile().':'.$e->getLine());
$this->debug_echo($e->getTraceAsString());
}
}
$this->debug_echo('已退出程序');
return Command::SUCCESS;
}
/**
* 获取进程启动名称
* @return mixed
* @throws \Exception
* @author:dc
* @time 2023/8/21 11:43
*/
public function getSignature(){
if(empty($this->signature)){
throw new \Exception('无法获取到启动命令');
}
return $this->signature;
}
/**
* 是否已运行
* @param int $max 最大运行多少进程
* @return bool
* @throws \Exception
* @author:dc
* @time 2023/8/21 11:54
*/
public function isRunning($max=1):bool {
$ps = "ps -ef | grep \"artisan ".$this->getSignature()."\" | grep -v grep | wc -l";
$num = exec($ps);
if(property_exists($this,'maxRunNumber')){
$max = $this->maxRunNumber;
}
if($num>$max){
return true;
}
return false;
}
}
<?php
/**
* @remark :
* @name :CropImage.php
* @author :lyh
* @method :post
* @time :2025/5/8 9:19
*/
namespace App\Console\Commands\CropImage;
use App\Enums\Common\Code;
use App\Models\Domain\DomainInfo;
use App\Models\File\Image;
use App\Models\WebSetting\AggregationSetting;
use App\Models\WebSetting\WebSettingImage;
use App\Services\CosService;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
class CropImage extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'crop_image {project_id}';
/**
* The console command description.
*
* @var string
*/
protected $description = '裁剪图片';
public function handle(){
echo '测试裁剪->cs-crop:'.PHP_EOL;
$project_id = $this->argument('project_id');
ProjectServer::useProject($project_id);
$data = $this->_keywordAction($project_id);
$this->_aiAction($project_id,$data[0] ?? []);
DB::disconnect('custom_mysql');
}
/**
* @remark :执行的方法
* @name :_action
* @author :lyh
* @method :post
* @time :2025/5/8 9:21
*/
public function _keywordAction($project_id){
$resData = [];
//聚合页裁剪
$data = $this->getKeywordImage($project_id);
$cosService = new CosService();
if(!empty($data)){
foreach ($data as $val){
//处理图片为相对路径
$image = str_replace_url($val);
$height = $cosService->getImageHeight($image);
if(empty($height)){
echo '未获取到图片高度。'.PHP_EOL;
continue;
}
echo '返回的图片高度:'.$height.PHP_EOL;
if($height > 220){
$result = $cosService->cropCosImage($image);
if(empty($result)){
continue;
}
$resData[] = $result['path'];
$this->saveMysql($project_id,$result['size'],$result['type'],$result['path'],$result['mime']);
}else{
$resData[] = $image;
}
}
}
$this->saveAggregationSetting($project_id,$resData);
return $resData;
}
/**
* @remark :ai执行方法
* @name :_aiAction
* @author :lyh
* @method :post
* @time :2025/5/8 16:12
*/
public function _aiAction($project_id,$keywordImage){
$cosService = new CosService();
//ai_blog裁剪
$ai_image = $this->getAiBlogImage($project_id,$keywordImage ?? []);
if(empty($ai_image)){
echo '当前图片不需要裁剪。'.PHP_EOL;
return true;
}
$height = $cosService->getImageHeight($ai_image);
if(empty($height)){
echo '未获取到AI_BLOG图片高度。'.PHP_EOL;
return true;
}
echo '返回的图片高度:'.$height.PHP_EOL;
if($height > 220){
$result = $cosService->cropCosImage($ai_image);
if(empty($result)){
return true;
}
$this->saveMysql($project_id,$result['size'],$result['type'],$result['path'],$result['mime']);
$webSettingImageModel = new WebSettingImage();
$webSettingImageModel->edit(['image'=>$result['path']],['project_id' => $project_id, 'type' => 4]);
}
return true;
}
/**
* @remark :保存数据
* @name :saveAggregationSetting
* @author :lyh
* @method :post
* @time :2025/5/8 16:24
*/
public function saveAggregationSetting($project_id,$data){
if(empty($data)){
return true;
}
//存全路径
foreach ($data as $key => $val){
$val = getImageUrl($val);
$data[$key] = $val;
}
$aggregationSettingModel = new AggregationSetting();
$info = $aggregationSettingModel->read(['project_id'=>$project_id]);
if($info === false){
$aggregationSettingModel->addReturnId(['project_id'=>$project_id,'top_banner'=>json_encode($data,true)]);
}else{
$aggregationSettingModel->edit(['top_banner'=>json_encode($data,true)],['id'=>$info['id']]);
}
return true;
}
/**
* @remark :获取aiBlog图片
* @name :getAiBlogImage
* @author :lyh
* @method :post
* @time :2025/5/8 10:42
*/
public function getAiBlogImage($project_id,$keywordImage){
// AI博客banner type:1:产品,2:博客,3:新闻,4:AIBlog
$webSettingImageModel = new WebSettingImage();
$aiBlogInfo = $webSettingImageModel->read(['project_id' => $project_id, 'type' => 4],['image']);
if($aiBlogInfo === false && !empty($keywordImage)){
$webSettingImageModel->addReturnId(['project_id'=>$project_id,'image'=>$keywordImage,'type'=>4]);
return '';
}
if(empty($aiBlogInfo['image']) && !empty($keywordImage)){
$webSettingImageModel->edit(['image'=>$keywordImage],['id'=>$aiBlogInfo['id']]);
return '';
}
$ai_image = str_replace_url($aiBlogInfo['image']);
return $ai_image;
}
/**
* @remark :获取聚合页图片
* @name :getImage
* @author :lyh
* @method :post
* @time :2025/5/8 9:21
*/
public function getKeywordImage($project_id){
$data = [];
// 聚合页banner
$aggregationSettingModel = new AggregationSetting();
$aggregationSettingInfo = $aggregationSettingModel->read(['project_id' => $project_id],['id','top_banner']);
if($aggregationSettingInfo !== false && !empty($aggregationSettingInfo['top_banner'])){
foreach ($aggregationSettingInfo['top_banner'] as $val){
if($val != 'jpg' && $val != 'png' && $val != 'webp'){
$data[] = $val;
}
}
}
if(empty($data)){
//重页面上获取首页banner
$data = $this->getDomImage($project_id);
}
return $data;
}
/**
* @remark :页面上获取图片
* @name :getDomImage
* @author :lyh
* @method :post
* @time :2025/5/8 10:32
*/
public function getDomImage($project_id){
$data = [];
echo '获取首页banner:' . $project_id . PHP_EOL;
$domainModel = new DomainInfo();
$domainInfo = $domainModel->read(['project_id' => $project_id, 'status' => 1]);
if ($domainInfo !== false) {
$dom = @file_get_html('https://' . $domainInfo['domain'] . '/');
if (empty($dom)) {
$this->output('获取HTML失败: ' . $project_id);
}else{
$banner_dom = $dom->find('main .section-banner-wrap-block img', 0);
$data[] = $banner_dom ? $banner_dom->src : '';
$dom->clear();
unset($dom);
}
}else{
$this->output('域名不存在: ' . $project_id);
}
return $data;
}
/**
* @remark :写入数据库
* @name :saveMysql
* @author :lyh
* @method :post
* @time :2025/5/8 14:59
*/
public function saveMysql($project_id,$size,$image_type,$path,$mime = ''){
$hash = md5($path);
$imageModel = new Image();
$info = $imageModel->read(['hash'=>$hash,'project_id'=>$project_id]);
$data = [
'path' => $path,
'size' => $size,
'hash' => $hash,
'type' => $image_type,
'refer'=> 0,
'mime' => $mime,
'project_id'=>$project_id,
'name'=>basename($path),
'en_name'=>basename($path)
];
if($info === false){
$imageModel->addReturnId($data);
}else{
$imageModel->edit($data,['id'=>$info['id']]);
}
return true;
}
/**
* @remark :记录日志
* @name :output
* @author :lyh
* @method :post
* @time :2025/5/8 9:57
*/
public function output($message, $log_file = 'logs/crop_image.log')
{
$message = date('Y-m-d H:i:s') . ' ' . $message . PHP_EOL;
echo $message;
file_put_contents(storage_path($log_file), $message, FILE_APPEND);
return true;
}
}
<?php
/**
* @remark :
* @name :AfterDayCount.php
* @author :lyh
* @method :post
* @time :2025/3/26 15:28
*/
namespace App\Console\Commands\DayCount;
use App\Models\ASide\APublicModel;
use App\Models\Channel\Channel;
use App\Models\Manage\ManageHr;
use App\Models\Project\Project;
use App\Models\RankData\RankDataLog;
use Carbon\Carbon;
use App\Models\HomeCount\AfterCount as AfterCountModel;
use Illuminate\Console\Command;
class AfterDayCount extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'after_count';
protected $managerHrModel;
public $after_manager = [
1 => ['许璐','王袁袁'],
2 => ['陈思蓓'],
3 => ['张国英']
];
/**
* The console command description.
*
* @var string
*/
protected $description = '统计昨日售后数据';
public function handle(){
echo date('Y-m-d H:i:s').'统计start->'.PHP_EOL;
$saveData = $this->_action();
$afterModel = new AfterCountModel();
//保存数据
$afterModel->insertAll($saveData);
echo date('Y-m-d H:i:s').'->统计end'.PHP_EOL;
return true;
}
/**
* @remark :执行方法
* @name :_action
* @author :lyh
* @method :post
* @time :2025/3/26 15:29
*/
public function _action(){
$this->managerHrModel = new ManageHr();
$projectModel = new Project();
$rankDataLogModel = new RankDataLog();
$date = date('Y-m-d');
$saveData = [];
// $projectIdArr = $rankDataLogModel->selectField(['is_compliance'=>1,'lang'=>'','date'=>date('Y-m-d', strtotime('-3 months'))],'project_id');//3个月前达标的项目id
foreach ($this->after_manager as $key => $valM){
$idArr = $this->managerHrModel->selectField(['name'=>['in',$valM]],'id');
echo '对应优化师id:'.json_encode($idArr).PHP_EOL;
$project_count = $projectModel->where('gl_project.extend_type',0)
->where('gl_project.delete_status',0)
->where('gl_project.old_project_id',0)
->where('gl_project_deploy_optimize.start_date','<=',$date)
->whereIn('gl_project_deploy_optimize.optimist_mid',$idArr)
->whereIn('gl_project.type',[2,4,6])
->leftJoin('gl_project_deploy_optimize', 'gl_project.id', '=', 'gl_project_deploy_optimize.project_id')
->whereRaw("FIND_IN_SET('2', gl_project.level) = 0 AND FIND_IN_SET('3', gl_project.level) = 0")
->whereRaw("FIND_IN_SET('7', gl_project_deploy_optimize.special) = 0 AND FIND_IN_SET('8', gl_project_deploy_optimize.special) = 0")
->count();
$qualified_count = $projectModel->where('gl_project.extend_type',0)
->where('gl_project.delete_status',0)
->where('gl_project.old_project_id',0)
->where('gl_project_deploy_optimize.start_date','<=',$date)
->where('gl_project.is_remain_today',1)
->where('gl_project_deploy_build.plan','!=',0)
->whereIn('gl_project_deploy_optimize.optimist_mid',$idArr)
->whereIn('gl_project.type',[2,4,6])
->leftJoin('gl_project_deploy_optimize', 'gl_project.id', '=', 'gl_project_deploy_optimize.project_id')
->leftJoin('gl_project_deploy_build', 'gl_project.id', '=', 'gl_project_deploy_build.project_id')
->whereRaw("FIND_IN_SET('2', gl_project.level) = 0 AND FIND_IN_SET('3', gl_project.level) = 0")
->whereRaw("FIND_IN_SET('7', gl_project_deploy_optimize.special) = 0 AND FIND_IN_SET('8', gl_project_deploy_optimize.special) = 0")
->count();
$rate = number_format($qualified_count / $project_count, 2);
$threeMonthsAgo = date('Y-m', strtotime('-3 months'));
echo '3个月前的时间:'.$threeMonthsAgo.PHP_EOL;
$three_project_count = $projectModel->where('gl_project.extend_type',0)
->where('gl_project.delete_status',0)
->where('gl_project.old_project_id',0)
->where('gl_project_deploy_optimize.start_date','>=',$threeMonthsAgo.'-01')
->where('gl_project_deploy_optimize.start_date','<=',$threeMonthsAgo.'-31')
->whereIn('gl_project_deploy_optimize.optimist_mid',$idArr)
->whereIn('gl_project.type',[2,4,6])
->leftJoin('gl_project_deploy_optimize', 'gl_project.id', '=', 'gl_project_deploy_optimize.project_id')
->whereRaw("FIND_IN_SET('2', gl_project.level) = 0 AND FIND_IN_SET('3', gl_project.level) = 0")
->whereRaw("FIND_IN_SET('7', gl_project_deploy_optimize.special) = 0 AND FIND_IN_SET('8', gl_project_deploy_optimize.special) = 0")
->count();
$three_qualified_count = $projectModel->where('gl_project.extend_type',0)
->where('gl_project.delete_status',0)
->where('gl_project.old_project_id',0)
->where('gl_project.is_remain_today',1)
->where('gl_project_deploy_optimize.start_date','>=',$threeMonthsAgo.'-01')
->where('gl_project_deploy_optimize.start_date','<=',$threeMonthsAgo.'-31')
->whereIn('gl_project_deploy_optimize.optimist_mid',$idArr)
->whereIn('gl_project.type',[2,4,6])
->where('gl_project_deploy_build.plan','!=',0)
->leftJoin('gl_project_deploy_optimize', 'gl_project.id', '=', 'gl_project_deploy_optimize.project_id')
->leftJoin('gl_project_deploy_build', 'gl_project.id', '=', 'gl_project_deploy_build.project_id')
->whereRaw("FIND_IN_SET('2', gl_project.level) = 0 AND FIND_IN_SET('3', gl_project.level) = 0")
->whereRaw("FIND_IN_SET('7', gl_project_deploy_optimize.special) = 0 AND FIND_IN_SET('8', gl_project_deploy_optimize.special) = 0")
->count();
if($three_project_count != 0){
$three_rate = number_format($three_qualified_count / $three_project_count, 2);
}else{
$three_rate = 0;
}
$data = $projectModel->where('gl_project.extend_type',0)
->where('gl_project.delete_status',0)
->where('gl_project.old_project_id',0)
->where('gl_project_deploy_optimize.start_date','>=',$threeMonthsAgo.'-01')
->where('gl_project_deploy_optimize.start_date','<=',$threeMonthsAgo.'-31')
->where('gl_project.is_remain_today',1)
->whereIn('gl_project_deploy_optimize.optimist_mid',$idArr)
->whereIn('gl_project.type',[2,4,6])
->leftJoin('gl_project_payment', 'gl_project.id', '=', 'gl_project_payment.project_id')
->leftJoin('gl_project_deploy_build', 'gl_project.id', '=', 'gl_project_deploy_build.project_id')
->leftJoin('gl_domain_info', 'gl_project.id', '=', 'gl_domain_info.project_id')
->leftJoin('gl_project_deploy_optimize', 'gl_project.id', '=', 'gl_project_deploy_optimize.project_id')
->leftJoin('gl_project_online_check', 'gl_project.id', '=', 'gl_project_online_check.project_id')
->whereRaw("FIND_IN_SET('2', gl_project.level) = 0 AND FIND_IN_SET('3', gl_project.level) = 0")
->whereRaw("FIND_IN_SET('7', gl_project_deploy_optimize.special) = 0 AND FIND_IN_SET('8', gl_project_deploy_optimize.special) = 0")
->select($this->selectParam())->get()->toArray();
foreach ($data as $k=>$val){
$this->handleParam($val);
$data[$k] = $val;
}
$saveData[] = [
'date'=>date('Y-m-d'),
'type'=> $key,
'project_count'=>$project_count,
'qualified_count'=>$qualified_count,
'rate'=>$rate,
'three_project_count'=>$three_project_count,
'three_qualified_count'=>$three_qualified_count,
'three_rate'=>$three_rate,
'data' => json_encode($data,true)
];
}
return $saveData;
}
public function selectParam(){
$select = [
'gl_project.id AS id',
'gl_project.title AS title',
'gl_project.level AS level',
'gl_project.channel AS channel',
'gl_project.company AS company',
'gl_project.type AS type',
'gl_project.created_at AS created_at',
'gl_project.is_language AS is_language',
'gl_project.cooperate_date AS cooperate_date',
'gl_project.finish_remain_day AS finish_remain_day',
'gl_project.is_remain_today AS is_remain_today',
'gl_project.remain_day AS remain_day',
'gl_project.seo_remain_day AS seo_remain_day',
'gl_project.robots AS robots',
'gl_project.is_minor_languages AS is_minor_languages',
'gl_project.is_translate AS is_translate',
'gl_project.is_translate_tag AS is_translate_tag',
'gl_project.is_upgrade AS is_upgrade',
'gl_project.site_status AS site_status',
'gl_project_online_check.id AS online_check_id',
'gl_project_online_check.question AS question',
'gl_project_online_check.go_question AS go_question',
'gl_project_online_check.optimist_status AS optimist_status',
'gl_project_online_check.qa_status AS qa_status',
'gl_project_online_check.updated_at AS online_updated_at',
'gl_project_payment.amount AS amount',
'gl_project_deploy_build.dept_id AS dept_id',
'gl_project_deploy_build.keyword_num AS key',
'gl_project_deploy_build.service_duration AS day',
'gl_project_deploy_build.leader_mid AS leader_mid',
'gl_project_deploy_build.manager_mid AS manager_mid',
'gl_project_deploy_build.designer_mid AS designer_mid',
'gl_project_deploy_build.tech_mid AS tech_mid',
'gl_project_deploy_build.test_domain AS test_domain',
'gl_project_deploy_build.plan AS plan',
'gl_project_deploy_build.seo_plan AS seo_plan',
'gl_project_deploy_optimize.dept_id AS optimize_dept_id',
'gl_project_deploy_optimize.manager_mid AS optimize_manager_mid',
'gl_project_deploy_optimize.optimist_mid AS optimize_optimist_mid',
'gl_project_deploy_optimize.assist_mid AS optimize_assist_mid',
'gl_project_deploy_optimize.tech_mid AS optimize_tech_mid',
'gl_project_deploy_optimize.design_mid AS design_mid',
'gl_project_deploy_optimize.tech_leader AS tech_leader',
'gl_project_deploy_optimize.quality_mid AS quality_mid',
'gl_project_deploy_optimize.design_mid AS design_mid',
'gl_project_deploy_optimize.start_date AS start_date',
'gl_project_deploy_optimize.backlink AS backlink',
'gl_project_deploy_optimize.ai_video AS ai_video',
'gl_project_deploy_optimize.api_no AS api_no',
'gl_project_deploy_optimize.first_compliance_time AS first_compliance_time',
'gl_domain_info.amp_status AS amp_status',
'gl_domain_info.domain AS domain',
];
return $select;
}
public function handleParam(&$item){
$data = APublicModel::getNumByProjectId($item['id']);
$manageModel = new ManageHr();
$plan = Project::planMap();
$seo_plan = Project::seoMap();
$item['plan'] = $plan[$item['plan']] ?? $seo_plan[1];
$item['channel'] = Channel::getChannelText($item['channel']['user_id'] ?? 0);
$item['build_leader'] = $manageModel->getName($item['leader_mid']);
$item['build_manager'] = $manageModel->getName($item['manager_mid']);
$item['build_designer'] = $manageModel->getName($item['designer_mid']);
$item['build_tech'] = $manageModel->getName($item['tech_mid']);
$item['optimize_manager'] = $manageModel->getName($item['optimize_manager_mid']);
$item['optimize_optimist'] = $manageModel->getName($item['optimize_optimist_mid']);
$item['optimize_assist'] = $manageModel->getName($item['optimize_assist_mid']);
$item['optimize_tech'] = $manageModel->getName($item['optimize_tech_mid']);
$item['quality_mid_name'] = $manageModel->getName($item['quality_mid']);
$item['created_at'] = date('Y年m月d日', strtotime($item['cooperate_date']));
$item['autologin_code'] = getAutoLoginCode($item['id']);
$item['domain'] = 'https://'.$item['domain'].'/';
if(!empty($item['domain']) && $item['amp_status'] == 1){
$item['amp_domain'] = str_replace('www','m',$item['domain']);
}
$item['product_num'] = $data['product'] ?? 0;
$item['keyword_num'] = $item['key'] ?? 0;
$item['inquiry_num'] = $data['inquiry'] ?? 0;
$item['autologin_code'] = getAutoLoginCode($item['id']);
return $item;
}
}
<?php
namespace App\Console\Commands\DayCount;
use App\Helper\FormGlobalsoApi;
use App\Models\Domain\DomainInfo;
use App\Models\Inquiry\InquiryFormData;
use App\Models\Project\Project;
use App\Services\ProjectServer;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class Count extends Command
{
const STATUS_ERROR = 400;
public $error = 0;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'count';
/**
* The console command description.
*
* @var string
*/
protected $description = '统计昨日数据';
/**
* @name :(定时执行生成昨日数据统计)handle
* @author :lyh
* @method :post
* @time :2023/5/12 14:48
*/
public function handle()
{
$list = DB::table('gl_project')->where('gl_project.extend_type',0)->where('gl_project.delete_status',0)
->whereIn('gl_project.type',[1,2,3,4,6])
->leftJoin('gl_project_deploy_build', 'gl_project.id', '=', 'gl_project_deploy_build.project_id')
->leftJoin('gl_project_deploy_optimize', 'gl_project.id', '=', 'gl_project_deploy_optimize.project_id')
->select($this->selectParam())->get();
try {
if(!empty($list)){
$list = $list->toArray();
$yesterday = Carbon::yesterday()->toDateString();
$domainInfo = new DomainInfo();
foreach ($list as $v){
$v = (array)$v;
echo date('Y-m-d H:i:s') . 'project_id:'.$v['id'] . PHP_EOL;
if($v['type'] == Project::TYPE_ZERO){
continue;
}
if(!empty($v['domain'])){
$info = $domainInfo->read(['id'=>$v['domain']]);
if($info !== false){
$v['test_domain'] = $info['domain'];
}
}
$arr = [];
//统计时间
$arr['date'] = $yesterday;
ProjectServer::useProject($v['id']);
//pv统计
$arr['pv_num'] = $this->pv_num($yesterday);
//ip统计
$arr['ip_num'] = $this->ip_num($yesterday);
DB::disconnect('custom_mysql');
//服务达标天数
$arr['compliance_day'] = $v['finish_remain_day'];
//剩余服务时常
$arr['service_day'] = ($v['remain_day'] - 1) < 0 ? 0: $v['remain_day'] - 1;
//项目id
$arr['project_id'] = $v['project_id'];
$arr['created_at'] = date('Y-m-d H:i:s');
$arr['updated_at'] = date('Y-m-d H:i:s');
//询盘统计
$arr = $this->inquiry($arr,$v['test_domain'], $v['id'] , $v['is_upgrade'] ?? 0);
//查询当天数据是否存在 存在则更新
$countModel = new \App\Models\HomeCount\Count();
$info = $countModel->read(['date'=>$arr['date'],'project_id'=>$v['id']]);
if($info === false){
DB::table('gl_count')->insert($arr);
}else{
$countModel->edit($arr,['id'=>$info['id']]);
}
Log::channel('day_count')->error('日期:'.$arr['created_at'].'success: ' .$v['test_domain']);
}
}
}catch (\Exception $e){
Log::channel('day_count')->error('day_count:->error ' . $e->getMessage());
}
Log::channel('day_count')->error('success:end');
echo $this->error;
}
/**
* @name :(统计pv)pv_num
* @author :lyh
* @method :post
* @time :2023/6/14 15:40
*/
public function pv_num($yesterday){
$pv = DB::connection('custom_mysql')->table('gl_customer_visit_item')->whereDate('updated_date', $yesterday)->count();
return $pv;
}
/**
* @name :(统计ip)ip_num
* @author :lyh
* @method :post
* @time :2023/6/14 15:40
*/
public function ip_num($yesterday){
$ip = DB::connection('custom_mysql')->table('gl_customer_visit')->whereDate('updated_date', $yesterday)->count();
return $ip;
}
/**
* @param $arr
* @param $domain
* @name :(询盘统计)inquiry
* @author :lyh
* @method :post
* @time :2023/6/14 15:44
*/
public function inquiry($arr,$domain,$project_id,$is_upgrade = 0){
$inquiry_list = (new FormGlobalsoApi())->getInquiryAll($domain,$is_upgrade);
if($inquiry_list == false){
return $arr;
}
if($inquiry_list['status'] == self::STATUS_ERROR){
$arr['inquiry_num'] = 0;
$countryArr = [];
}else{
$arr['inquiry_num'] = $inquiry_list['data']['count'];
//询盘国家统计
$countryArr = $inquiry_list['data']['country'];
}
//加上其他询盘
ProjectServer::useProject($project_id);
$arr['inquiry_num'] += InquiryFormData::getCount();
$countryData = InquiryFormData::getCountryCount();
foreach ($countryData as $v1){
if(isset($countryArr[$v1['country']])){
$countryArr[$v1['country']] += $v1['count'];
}else{
$countryArr[$v1['country']] = $v1['count'];
}
}
arsort($countryArr);
$top20 = array_slice($countryArr, 0, 20, true);
$arr['country'] = json_encode($top20);
return $arr;
}
/**
* @name :(查询参数设置)selectParam
* @author :lyh
* @method :post
* @time :2023/6/14 15:00
*/
public function selectParam(){
$select = [
'gl_project.id AS id',
'gl_project.type AS type',
'gl_project.extend_type AS extend_type',
'gl_project.is_upgrade AS is_upgrade',
'gl_project.remain_day AS remain_day',
'gl_project.finish_remain_day AS finish_remain_day',
'gl_project_deploy_build.test_domain AS test_domain',
'gl_project_deploy_optimize.domain AS domain',
'gl_project_deploy_build.project_id AS project_id',
'gl_project.cooperate_date AS cooperate_date',
'gl_project_deploy_build.service_duration AS service_duration',
];
return $select;
}
}
<?php
/**
* @remark :
* @name :CountProject.php
* @author :lyh
* @method :post
* @time :2024/1/8 9:03
*/
namespace App\Console\Commands\DayCount;
use App\Helper\FormGlobalsoApi;
use App\Models\Inquiry\InquiryFormData;
use App\Models\Project\Project;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use App\Models\HomeCount\Count;
class CountAll extends Command
{
const STATUS_ERROR = 400;
public $error = 0;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'count_all';
/**
* The console command description.
*
* @var string
*/
protected $description = '所有项目统计';
public function handle(){
$projectModel = new Project();
$list = $projectModel->list(['delete_status'=>0,'type'=>['in',[1,2,3,4,6]]]);
foreach ($list as $v) {
echo date('Y-m-d H:i:s') . '项目id:'.$v['id'] . PHP_EOL;
ProjectServer::useProject($v['id']);
$this->count($v['id']);
DB::disconnect('custom_mysql');
}
return true;
}
/**
* @remark :日统计记录
* @name :count
* @author :lyh
* @method :post
* @time :2024/1/8 9:05
*/
public function count($project_id){
$list = DB::connection('custom_mysql')->table('gl_customer_visit')->select('updated_date')
->groupBy('updated_date')->get()->toArray();
$project = new Project();
$projectInfo = $project->read(['id'=>$project_id]);
if(!empty($list)){
$arr = [];
foreach ($list as $k=>$v){
$v = (array)$v;
if($v['updated_date'] == date('Y-m-d')){
continue;
}
echo date('Y-m-d H:i:s') . '时间:'.$v['updated_date'] . PHP_EOL;
$count = new Count();
$arr['project_id'] = $project_id;
$arr['date'] = $v['updated_date'];
$arr['pv_num'] = $this->pv_num($v['updated_date']);
$arr['ip_num'] = $this->ip_num($v['updated_date']);
$arr['inquiry_num'] = $this->inquiry_num($v['updated_date']);
//服务达标天数
$arr['compliance_day'] = $projectInfo['finish_remain_day'];
//剩余服务时常
$arr['service_day'] = $projectInfo['remain_day'];
$arr['country'] = json_encode([]);
//查询当天数据是否存在 存在则更新
$info = $count->read(['date'=>$v['updated_date'],'project_id'=>$project_id]);
if($info === false){
$arr['created_at'] = $v['updated_date'].' 01:00:00';
$arr['updated_at'] = $v['updated_date'].' 01:00:00';
$count->insert($arr);
}else{
$count->edit($arr,['id'=>$info['id']]);
}
}
}
echo date('Y-m-d H:i:s') . 'end' . PHP_EOL;
}
/**
* @param $arr
* @param $domain
* @name :(询盘统计)inquiry
* @author :lyh
* @method :post
* @time :2023/6/14 15:44
*/
public function inquiry($arr,$domain,$project_id,$is_upgrade = 0){
$inquiry_list = (new FormGlobalsoApi())->getInquiryAll($domain,$is_upgrade);
if($inquiry_list == false){
return $arr;
}
if($inquiry_list['status'] == self::STATUS_ERROR){
$arr['inquiry_num'] = 0;
$countryArr = [];
}else{
$arr['inquiry_num'] = $inquiry_list['data']['count'];
//询盘国家统计
$countryArr = $inquiry_list['data']['country'];
}
//加上其他询盘
ProjectServer::useProject($project_id);
$arr['inquiry_num'] += InquiryFormData::getCount();
$countryData = InquiryFormData::getCountryCount();
foreach ($countryData as $v1){
if(isset($countryArr[$v1['country']])){
$countryArr[$v1['country']] += $v1['count'];
}else{
$countryArr[$v1['country']] = $v1['count'];
}
}
arsort($countryArr);
$top20 = array_slice($countryArr, 0, 20, true);
$arr['country'] = json_encode($top20);
return $arr;
}
/**
* @remark :询盘数量
* @name :inquiry_num
* @author :lyh
* @method :post
* @time :2024/1/8 9:24
*/
public function inquiry_num($day){
$count = DB::connection('custom_mysql')->table('gl_customer_visit')->whereDate('updated_date', $day)->where('is_inquiry',1)->count();
return $count;
}
/**
* @name :(统计pv)pv_num
* @author :lyh
* @method :post
* @time :2023/6/14 15:40
*/
public function pv_num($day){
//$pv = DB::connection('custom_mysql')->table('gl_customer_visit_item')->whereDate('updated_date', $day)->count();
$pv = DB::connection('custom_mysql')->table('gl_customer_visit')->whereDate('updated_date', $day)->sum('depth');
return $pv;
}
/**
* @name :(统计ip)ip_num
* @author :lyh
* @method :post
* @time :2023/6/14 15:40
*/
public function ip_num($day){
$ip = DB::connection('custom_mysql')->table('gl_customer_visit')->whereDate('updated_date', $day)->count();
return $ip;
}
}
<?php
namespace App\Console\Commands\DayCount;
use App\Helper\FormGlobalsoApi;
use App\Models\Domain\DomainInfo;
use App\Models\Inquiry\InquiryFormData;
use App\Models\Project\Project;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
class CountDate extends Command
{
const STATUS_ERROR = 400;
public $error = 0;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'count_data {date}';
/**
* The console command description.
*
* @var string
*/
protected $description = '按时间统计所有项目记录';
/**
* @name :(定时执行生成昨日数据统计)handle
* @author :lyh
* @method :post
* @time :2023/5/12 14:48
*/
public function handle()
{
$date = $this->argument('date');
$list = DB::table('gl_project')->where('gl_project.extend_type','=',0)
->whereIn('gl_project.type',[1,2,3,4,6])
->leftJoin('gl_project_deploy_build', 'gl_project.id', '=', 'gl_project_deploy_build.project_id')
->leftJoin('gl_project_deploy_optimize', 'gl_project.id', '=', 'gl_project_deploy_optimize.project_id')
->select($this->selectParam())->get();
try {
if(!empty($list)){
$list = $list->toArray();
// $yesterday = Carbon::yesterday()->toDateString();
$yesterday = $date;
$domainInfo = new DomainInfo();
foreach ($list as $v){
$v = (array)$v;
echo date('Y-m-d H:i:s') . 'project_id:'.$v['id'] . PHP_EOL;
if($v['type'] == Project::TYPE_ZERO){
continue;
}
if(!empty($v['domain'])){
$info = $domainInfo->read(['id'=>$v['domain']]);
if($info !== false){
$v['test_domain'] = $info['domain'];
}
}
$arr = [];
//统计时间
$arr['date'] = $yesterday;
ProjectServer::useProject($v['id']);
//pv统计
$arr['pv_num'] = $this->pv_num($yesterday);
//ip统计
$arr['ip_num'] = $this->ip_num($yesterday);
DB::disconnect('custom_mysql');
//服务达标天数
$arr['compliance_day'] = $v['finish_remain_day'];
//剩余服务时常
$arr['service_day'] = ($v['remain_day'] - 1) < 0 ? 0: $v['remain_day'] - 1;
//项目id
$arr['project_id'] = $v['project_id'];
$arr['created_at'] = date('Y-m-d H:i:s');
$arr['updated_at'] = date('Y-m-d H:i:s');
//询盘统计
$arr = $this->inquiry($arr,$v['test_domain'], $v['id'],$v['is_upgrade'] ?? 0);
if($arr === false){
continue;
}
//查询当天数据是否存在 存在则更新
$countModel = new \App\Models\HomeCount\Count();
$info = $countModel->read(['date'=>$arr['date'],'project_id'=>$v['id']]);
if($info === false){
DB::table('gl_count')->insert($arr);
}else{
$countModel->edit($arr,['id'=>$info['id']]);
}
Log::channel('day_count')->error('日期:'.$arr['created_at'].'success: ' .$v['test_domain']);
}
}
}catch (\Exception $e){
Log::channel('day_count')->error('day_count:->error ' . $e->getMessage());
}
Log::channel('day_count')->error('success:end');
echo $this->error;
}
/**
* @name :(统计pv)pv_num
* @author :lyh
* @method :post
* @time :2023/6/14 15:40
*/
public function pv_num($yesterday){
$pv = DB::connection('custom_mysql')->table('gl_customer_visit_item')->whereDate('updated_date', $yesterday)->count();
return $pv;
}
/**
* @name :(统计ip)ip_num
* @author :lyh
* @method :post
* @time :2023/6/14 15:40
*/
public function ip_num($yesterday){
$ip = DB::connection('custom_mysql')->table('gl_customer_visit')->whereDate('updated_date', $yesterday)->count();
return $ip;
}
/**
* @param $arr
* @param $domain
* @name :(询盘统计)inquiry
* @author :lyh
* @method :post
* @time :2023/6/14 15:44
*/
public function inquiry($arr,$domain,$project_id,$is_upgrade = 0){
$inquiry_list = (new FormGlobalsoApi())->getInquiryAll($domain,$is_upgrade);
if($inquiry_list == false){
return $arr;
}
if($inquiry_list['status'] == self::STATUS_ERROR){
$arr['inquiry_num'] = 0;
$countryArr = [];
}else{
$arr['inquiry_num'] = $inquiry_list['data']['count'];
//询盘国家统计
$countryArr = $inquiry_list['data']['country'];
}
//加上其他询盘
ProjectServer::useProject($project_id);
$arr['inquiry_num'] += InquiryFormData::getCount();
$countryData = InquiryFormData::getCountryCount();
foreach ($countryData as $v1){
if(isset($countryArr[$v1['country']])){
$countryArr[$v1['country']] += $v1['count'];
}else{
$countryArr[$v1['country']] = $v1['count'];
}
}
arsort($countryArr);
$top20 = array_slice($countryArr, 0, 20, true);
$arr['country'] = json_encode($top20);
return $arr;
}
/**
* @name :(查询参数设置)selectParam
* @author :lyh
* @method :post
* @time :2023/6/14 15:00
*/
public function selectParam(){
$select = [
'gl_project.id AS id',
'gl_project.type AS type',
'gl_project.extend_type AS extend_type',
'gl_project.is_upgrade AS is_upgrade',
'gl_project.remain_day AS remain_day',
'gl_project.finish_remain_day AS finish_remain_day',
'gl_project_deploy_build.test_domain AS test_domain',
'gl_project_deploy_optimize.domain AS domain',
'gl_project_deploy_build.project_id AS project_id',
'gl_project.cooperate_date AS cooperate_date',
'gl_project_deploy_build.service_duration AS service_duration',
];
return $select;
}
}
<?php
/**
* @remark :
* @name :CountProject.php
* @author :lyh
* @method :post
* @time :2024/1/8 9:03
*/
namespace App\Console\Commands\DayCount;
use App\Helper\FormGlobalsoApi;
use App\Models\Domain\DomainInfo;
use App\Models\Inquiry\InquiryFormData;
use App\Models\Project\DeployOptimize;
use App\Models\Project\Project;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use App\Models\HomeCount\Count;
class CountProject extends Command
{
const STATUS_ERROR = 400;
public $error = 0;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'count_project {project_id}';
/**
* The console command description.
*
* @var string
*/
protected $description = '按项目统计日记录';
public function handle(){
$project_id = $this->argument('project_id');
ProjectServer::useProject($project_id);
$this->count($project_id);
DB::disconnect('custom_mysql');
}
/**
* @remark :日统计记录
* @name :count
* @author :lyh
* @method :post
* @time :2024/1/8 9:05
*/
public function count($project_id,$is_upgrade = 0){
$list = DB::connection('custom_mysql')->table('gl_customer_visit')->select('updated_date')
->groupBy('updated_date')->get()->toArray();
$project = new Project();
$projectInfo = $project->read(['id'=>$project_id]);
$projectOptimizeModel = new DeployOptimize();
$optimizeInfo = $projectOptimizeModel->read(['project_id'=>$project_id]);
$domain = '';
if(!empty($optimizeInfo['domain'])){
$domainInfoModel = new DomainInfo();
$domainInfo = $domainInfoModel->read(['id'=>$optimizeInfo['domain']]);
if($domainInfo !== false){
$domain = $domainInfo['domain'];
}
}
if(empty($domain)){
return false;
}
if(!empty($list)){
$arr = [];
foreach ($list as $k=>$v){
$v = (array)$v;
if($v['updated_date'] == date('Y-m-d')){
continue;
}
echo date('Y-m-d H:i:s') . '时间:'.$v['updated_date'] . PHP_EOL;
$count = new Count();
$arr['project_id'] = $project_id;
$arr['date'] = $v['updated_date'];
$arr['pv_num'] = $this->pv_num($v['updated_date']);
$arr['ip_num'] = $this->ip_num($v['updated_date']);
//服务达标天数
$arr['compliance_day'] = $projectInfo['finish_remain_day'];
//剩余服务时常
$arr['service_day'] = $projectInfo['remain_day'];
$arr = $this->inquiry($arr,$domain, $project_id,$projectInfo['is_upgrade'] ?? 0);
if($arr === false){
continue;
}
//查询当天数据是否存在 存在则更新
$info = $count->read(['date'=>$v['updated_date'],'project_id'=>$project_id]);
if($info === false){
$arr['created_at'] = $v['updated_date'].' 01:00:00';
$arr['updated_at'] = $v['updated_date'].' 01:00:00';
$count->insert($arr);
}else{
$count->edit($arr,['id'=>$info['id']]);
}
}
}
echo date('Y-m-d H:i:s') . 'end' . PHP_EOL;
}
/**
* @remark :询盘数量
* @name :inquiry_num
* @author :lyh
* @method :post
* @time :2024/1/8 9:24
*/
public function inquiry_num($day){
$count = DB::connection('custom_mysql')->table('gl_customer_visit')->whereDate('updated_date', $day)->where('is_inquiry',1)->count();
return $count;
}
/**
* @name :(统计pv)pv_num
* @author :lyh
* @method :post
* @time :2023/6/14 15:40
*/
public function pv_num($day){
$pv = DB::connection('custom_mysql')->table('gl_customer_visit')->whereDate('updated_date', $day)->sum('depth');
return $pv;
}
/**
* @name :(统计ip)ip_num
* @author :lyh
* @method :post
* @time :2023/6/14 15:40
*/
public function ip_num($day){
$ip = DB::connection('custom_mysql')->table('gl_customer_visit')->whereDate('updated_date', $day)->count();
return $ip;
}
/**
* @param $arr
* @param $domain
* @name :(询盘统计)inquiry
* @author :lyh
* @method :post
* @time :2023/6/14 15:44
*/
public function inquiry($arr,$domain,$project_id,$is_upgrade = 0){
$inquiry_list = (new FormGlobalsoApi())->getInquiryAll($domain,$is_upgrade);
if($inquiry_list == false){
return $arr;
}
// echo date('Y-m-d H:i:s') . '拉取询盘状态:' .json_encode($inquiry_list) . PHP_EOL;
if($inquiry_list['status'] == self::STATUS_ERROR){
$arr['inquiry_num'] = 0;
$countryArr = [];
}else{
$arr['inquiry_num'] = $inquiry_list['data']['count'];
//询盘国家统计
$countryArr = $inquiry_list['data']['country'];
}
//加上其他询盘
ProjectServer::useProject($project_id);
$arr['inquiry_num'] += InquiryFormData::getCount();
$countryData = InquiryFormData::getCountryCount();
foreach ($countryData as $v1){
if(isset($countryArr[$v1['country']])){
$countryArr[$v1['country']] += $v1['count'];
}else{
$countryArr[$v1['country']] = $v1['count'];
}
}
arsort($countryArr);
$top20 = array_slice($countryArr, 0, 20, true);
$arr['country'] = json_encode($top20);
return $arr;
}
}
<?php
namespace App\Console\Commands\DayCount;
use App\Models\Inquiry\InquiryCount as InquiryCountModel;
use App\Models\Inquiry\InquiryInfo;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
/**
* @remark :
* @class :InquiryCount.php
* @author :lyh
* @time :2023/7/14 16:20
*/
class InquiryCount extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'inquiry_count';
/**
* The console command description.
*
* @var string
*/
protected $description = '每天统计询盘数量';
/**
* @var :根据状态统计
*/
public $status = [
1=>'站群询盘',
2=>'ai站群询盘',
3=>'amp自建平台',
4=>'fb询盘',
5=>'fb广告',
6=>'广告采集建站',
7=>'黄金平台询盘',
8=>'内部统计',
9=>'GlobalImporter',
10=>'whatsapp',
11=>'Skype',
12=>'建站客户',
13=>'ChinaCn',
14=>'EC21',
15=>'邮件群发'
];
/**
* @remark :统计
* @name :handle
* @author :lyh
* @method :post
* @time :2023/7/14 16:21
*/
public function handle(){
$data = [];
//获取昨天的时间
$yesterday = Carbon::yesterday()->toDateString();
$inquiryInfoModel = new InquiryInfo();
try {
foreach ($this->status as $k=>$v){
$total = $inquiryInfoModel->formatQuery(['created_at'=>['between',[$yesterday.' 00:00:00',$yesterday.' 23:59:59']]])->count();
$untreated = $inquiryInfoModel->formatQuery(['created_at'=>['between',[$yesterday.' 00:00:00',$yesterday.' 23:59:59']],'status'=>1])->count();
$invalid = $inquiryInfoModel->formatQuery(['created_at'=>['between',[$yesterday.' 00:00:00',$yesterday.' 23:59:59']],'status'=>0])->count();
$data[] = [
'type'=>$k,
'day'=>$yesterday,
'total'=>$total ?? 0,
'untreated'=>$untreated ?? 0,
'invalid'=>$invalid ?? 0
];
}
$inquiryCount = new InquiryCountModel();
$inquiryCount->insert($data);
}catch (\Exception $e){
Log::error('inquiry_count : error');
}
return true;
}
}
<?php
namespace App\Console\Commands\DayCount;
use App\Models\Inquiry\InquiryInfo;
use Illuminate\Console\Command;
/**
* @remark :
* @class :InquiryDelay.php
* @author :lyh
* @time :2023/7/14 10:16
*/
class InquiryDelay extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'inquiry_delay';
/**
* The console command description.
*
* @var string
*/
protected $description = '延时询盘转发(暂时弃用)';
/**
* @remark :延时询盘转发
* @name :handle
* @author :lyh
* @method :post
* @time :2023/7/14 10:17
*/
public function handle()
{
// $inquiryInfoModel = new InquiryInfo();
// $param = $inquiryInfoModel->formatQuery(['status'=>$inquiryInfoModel::STATUS_FOUR])->orderBy('send_time','asc')->first();
// if(!empty($param)){
// $time = date('Y-m-d H:i:s');
// if($time >= $param['send_time']){
// $data = [];
// //TODO::处理转发的url
// $arr_url = explode(',',$param['forward_url']);
// foreach ($arr_url as $v){
// $data['url'] = $v;
// $this->inquiryForward($data);
// }
// $inquiryInfoModel->edit(['status'=>$inquiryInfoModel::STATUS_THREE],['id'=>$param['id']]);
// }
// }
return true;
}
/**
* @remark :询盘转发
* @name :inquiryForward
* @author :lyh
* @method :post
* @time :2023/7/13 14:39
*/
public function inquiryForward($post_data){
$url = 'https://www.globalso.site/api/external-interface/add/fa043f9cbec6b38f';
$post_data_new = [];
$post_data_new['refer'] = $post_data['url'];
$post_data_new['name'] = $post_data['name'];
$post_data_new['email'] = $post_data['email'];
$post_data_new['phone'] = $post_data['phone'];
$post_data_new['ip'] = $post_data['ip'];
$post_data_new['message'] = $post_data['message'];
$post_data_new['submit_time'] = date('Y-m-d H:i:s',time()+20);
$token = md5($post_data_new['refer'].$post_data_new['name'].$post_data_new['ip'].date("Y-m-d",time()));
$post_data_new['token'] = $token;
$header = array(
'CLIENT-IP: '.$post_data['ip'],
'X-FORWARDED-FOR: '.$post_data['ip']
);
return http_post($url,$post_data_new,$header);
}
}
<?php
/**
* @remark :
* @name :DeleteProductCategory.php
* @author :lyh
* @method :post
* @time :2024/5/16 14:59
*/
namespace App\Console\Commands\DeleteCategory;
use App\Helper\Arr;
use App\Models\Blog\Blog;
use App\Models\Blog\BlogCategory;
use App\Models\Com\NoticeLog;
use App\Models\Project\Project;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
/**
* @remark :删除分类
* @name :DeleteProductCategory
* @author :lyh
* @method :post
* @time :2024/5/16 15:00
*/
class DeleteBlogCategory extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'delete_blog_category';
/**
* The console command description.
*
* @var string
*/
protected $description = '删除博客分类';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* @remark :批量处理
* @name :handle
* @author :lyh
* @method :post
* @time :2024/5/16 15:02
*/
public function handle(){
while (true){
$noticeLogModel = new NoticeLog();
$list = $noticeLogModel->list(['status'=>NoticeLog::STATUS_PENDING,'type'=>NoticeLog::DELETE_BLOG_CATEGORY],'id',['*'],'asc',100);
if(empty($list)){
sleep(10);
continue;
}
foreach ($list as $item){
echo 'start:' . $item['id'] . PHP_EOL;
try {
$projectModel = new Project();
$projectInfo = $projectModel->read(['id'=>$item['data']['project_id']]);
if($projectInfo === false){
continue;
}
ProjectServer::useProject($projectInfo['id']);
$this->updateCategory();
DB::disconnect('custom_mysql');
$noticeLogModel->edit(['status'=>NoticeLog::STATUS_SUCCESS],['id'=>$item['id']]);
echo 'success:' . $item['id'] . '执行时间:'. date('Y-m-d H:i:s') . PHP_EOL;
}catch (\Exception $e){
echo 'error:' . $item['id'] . $e->getMessage() . '执行时间:'.date('Y-m-d H:i:s') . PHP_EOL;
errorLog('delete_blog_category删除失败'.date('Y-m-d H:i:s'), $item, $e);
}
}
return true;
}
}
/**
* @remark :更新分类
* @name :updateProductCategory
* @author :lyh
* @method :post
* @time :2024/5/16 15:38
*/
public function updateCategory(){
$page = 1;
$blogModel = new Blog();
while (true){
$blogList = $blogModel->lists(['status'=>1],$page,1000,'id',['id','category_id']);
if(empty($blogList) || empty($blogList['list'])){
return false;
}
foreach ($blogList['list'] as $v){
$category_id_arr = Arr::setToArr(trim($v['category_id'],','));
if(empty($category_id_arr)){
continue;
}
$categoryModel = new BlogCategory();
foreach ($category_id_arr as $k=>$cate_id){
$cateInfo = $categoryModel->read(['id'=>$cate_id],['id']);
if($cateInfo == false){
//删除关联表
unset($category_id_arr[$k]);
}
}
$str = !empty($category_id_arr) ? ','.Arr::arrToSet($category_id_arr).',' : '';
$blogModel->edit(['category_id'=>$str],['id'=>$v['id']]);
}
$page++;
}
return true;
}
}
<?php
/**
* @remark :
* @name :DeleteProductCategory.php
* @author :lyh
* @method :post
* @time :2024/5/16 14:59
*/
namespace App\Console\Commands\DeleteCategory;
use App\Helper\Arr;
use App\Models\Com\NoticeLog;
use App\Models\CustomModule\CustomModuleCategory;
use App\Models\CustomModule\CustomModuleContent;
use App\Models\Project\Project;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
/**
* @remark :删除分类
* @name :DeleteProductCategory
* @author :lyh
* @method :post
* @time :2024/5/16 15:00
*/
class DeleteCustomCategory extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'delete_custom_category';
/**
* The console command description.
*
* @var string
*/
protected $description = '删除扩展模块分类';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* @remark :批量处理
* @name :handle
* @author :lyh
* @method :post
* @time :2024/5/16 15:02
*/
public function handle(){
while (true){
$noticeLogModel = new NoticeLog();
$list = $noticeLogModel->list(['status'=>NoticeLog::STATUS_PENDING,'type'=>NoticeLog::DELETE_CUSTOM_CATEGORY],'id',['*'],'asc',100);
if(empty($list)){
sleep(10);
continue;
}
foreach ($list as $item){
echo 'start:' . $item['id'] . PHP_EOL;
try {
$projectModel = new Project();
$projectInfo = $projectModel->read(['id'=>$item['data']['project_id']]);
if($projectInfo === false){
continue;
}
ProjectServer::useProject($projectInfo['id']);
$this->updateCategory();
DB::disconnect('custom_mysql');
$noticeLogModel->edit(['status'=>NoticeLog::STATUS_SUCCESS],['id'=>$item['id']]);
echo 'success:' . $item['id'] . '执行时间:'. date('Y-m-d H:i:s') . PHP_EOL;
}catch (\Exception $e){
echo 'error:' . $item['id'] . $e->getMessage() . '执行时间:'. date('Y-m-d H:i:s') . PHP_EOL;
errorLog('delete_custom_category删除失败', $item, $e);
}
}
return true;
}
}
/**
* @remark :更新分类
* @name :updateProductCategory
* @author :lyh
* @method :post
* @time :2024/5/16 15:38
*/
public function updateCategory(){
$page = 1;
$customModel = new CustomModuleContent();
while (true){
$customList = $customModel->lists(['status'=>0],$page,1000,'id',['id','category_id']);
if(empty($customList) || empty($customList['list'])){
return false;
}
foreach ($customList['list'] as $v){
$category_id_arr = $v['category_id'];
if(empty($category_id_arr)){
continue;
}
$categoryModel = new CustomModuleCategory();
foreach ($category_id_arr as $k=>$cate_id){
$cateInfo = $categoryModel->read(['id'=>$cate_id],['id']);
if($cateInfo == false){
//删除关联表
unset($category_id_arr[$k]);
}
}
$str = !empty($category_id_arr) ? ','.Arr::arrToSet($category_id_arr).',' : '';
$customModel->edit(['category_id'=>$str],['id'=>$v['id']]);
}
$page++;
}
return true;
}
}
<?php
/**
* @remark :
* @name :DeleteProductCategory.php
* @author :lyh
* @method :post
* @time :2024/5/16 14:59
*/
namespace App\Console\Commands\DeleteCategory;
use App\Helper\Arr;
use App\Models\Com\NoticeLog;
use App\Models\News\News;
use App\Models\News\NewsCategory;
use App\Models\Project\Project;
use App\Services\ProjectServer;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
/**
* @remark :删除分类
* @name :DeleteProductCategory
* @author :lyh
* @method :post
* @time :2024/5/16 15:00
*/
class DeleteNewsCategory extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'delete_news_category';
/**
* The console command description.
*
* @var string
*/
protected $description = '删除新闻分类';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* @remark :批量处理
* @name :handle
* @author :lyh
* @method :post
* @time :2024/5/16 15:02
*/
public function handle(){
while (true){
$noticeLogModel = new NoticeLog();
$list = $noticeLogModel->list(['status'=>NoticeLog::STATUS_PENDING,'type'=>NoticeLog::DELETE_NEWS_CATEGORY],'id',['*'],'asc',100);
if(empty($list)){
sleep(10);
continue;
}
foreach ($list as $item){
echo 'start:' . $item['id'] . PHP_EOL;
try {
$projectModel = new Project();
$projectInfo = $projectModel->read(['id'=>$item['data']['project_id']]);
if($projectInfo === false){
continue;
}
ProjectServer::useProject($projectInfo['id']);
$this->updateCategory();
DB::disconnect('custom_mysql');
$noticeLogModel->edit(['status'=>NoticeLog::STATUS_SUCCESS],['id'=>$item['id']]);
echo 'success:' . $item['id'] . '执行时间:'.date('Y-m-d H:i:s') . PHP_EOL;
}catch (\Exception $e){
echo 'error:' . $item['id'] . $e->getMessage() . '执行时间:'.date('Y-m-d H:i:s') . PHP_EOL;
errorLog('delete_news_category删除失败', $item, $e);
}
}
return true;
}
}
/**
* @remark :更新分类
* @name :updateProductCategory
* @author :lyh
* @method :post
* @time :2024/5/16 15:38
*/
public function updateCategory(){
$page = 1;
$newsModel = new News();
while (true){
$newsList = $newsModel->lists(['status'=>1],$page,1000,'id',['id','category_id']);
if(empty($newsList) || empty($newsList['list'])){
return false;
}
foreach ($newsList['list'] as $v){
$category_id_arr = Arr::setToArr(trim($v['category_id'],','));
if(empty($category_id_arr)){
continue;
}
$categoryModel = new NewsCategory();
foreach ($category_id_arr as $k=>$cate_id){
$cateInfo = $categoryModel->read(['id'=>$cate_id],['id']);
if($cateInfo === false){
//删除关联表
unset($category_id_arr[$k]);
}
}
$str = !empty($category_id_arr) ? ','.Arr::arrToSet($category_id_arr).',' : '';
$newsModel->edit(['category_id'=>$str],['id'=>$v['id']]);
}
$page++;
}
return true;
}
}