作者 赵彬吉
... ... @@ -340,12 +340,11 @@ class GeoQuestionRes extends Command
$task_id = Redis::rpop($key);
if(empty($task_id)){
//todo::这里需要执行统计一次,统计当前项目当前日期的统计
# TODO 按照项目进行获取, 一个项目当天需要将所有跑完
$project_id = GeoQuestion::where('status', GeoQuestion::STATUS_OPEN)->where('next_time', '<=', date('Y-m-d'))->value('project_id');
if (!empty($project_id)){
$this->project_id = $project_id;
$ids = GeoQuestion::where(['project_id' => $project_id, 'status' => GeoQuestion::STATUS_OPEN])->where('current_time', '<>', date('Y-m-d'))->pluck('id');
$ids = GeoQuestion::where(['project_id' => $project_id, 'status' => GeoQuestion::STATUS_OPEN])->where('next_time', '<=', date('Y-m-d'))->pluck('id');
foreach ($ids as $id) {
Redis::lpush($key, $id);
}
... ...
... ... @@ -9,10 +9,7 @@
namespace App\Console\Commands\LyhTest;
use App\Models\CustomModule\CustomModuleCategory;
use App\Models\CustomModule\CustomModuleContent;
use App\Models\CustomModule\CustomModuleExtentContent;
use App\Models\News\News;
use App\Models\Product\Category;
use App\Models\Product\CategoryRelated;
use App\Models\Product\Column;
... ... @@ -57,7 +54,7 @@ class LyhImportTest extends Command
echo date('Y-m-d H:i:s') . 'start->1517' . PHP_EOL;
$url1 = 'https://ecdn6.globalso.com/upload/p/1517/file/2025-10/horse-racing-tkd-modification-1.xlsx';//改tdk
$url2 = 'https://v6-file.globalso.com/upload/p/1517/file/2025-10/horse-racing-url-modification.xlsx';//改url路由+tdk
$this->download_1517_action($url1);
$this->download_1517_action($url2);
DB::disconnect('custom_mysql');
echo date('Y-m-d H:i:s') . 'end' . PHP_EOL;
}
... ... @@ -71,22 +68,73 @@ class LyhImportTest extends Command
*/
public function download_1517_action($url)
{
// 下载到 Laravel storage 的临时路径
$tempPath = storage_path('app/temp_url.xlsx');
file_put_contents($tempPath, file_get_contents($url));
// 载入 Excel
// 临时文件路径(确保目录存在)
$tempDir = storage_path('app');
if (!is_dir($tempDir)) {
mkdir($tempDir, 0755, true);
}
$tempPath = $tempDir . '/temp_url.xlsx';
try {
// 使用 cURL 下载文件,防止403问题
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true, // 跟随重定向
CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; LaravelApp/1.0)', // 模拟浏览器
CURLOPT_TIMEOUT => 30, // 超时防止卡死
]);
$data = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// 检查下载是否成功
if ($httpCode !== 200 || !$data) {
echo "文件下载失败,HTTP状态码:{$httpCode}";
}
// 保存到临时文件
file_put_contents($tempPath, $data);
// 加载 Excel 文件
$spreadsheet = IOFactory::load($tempPath);
$sheet = $spreadsheet->getActiveSheet();
$rows = $sheet->toArray();
unlink($tempPath);
dd($rows);
}catch (\Exception $e){
echo '文件打不开'.PHP_EOL;
// 删除临时文件
if (file_exists($tempPath)) {
unlink($tempPath);
}
$d = [];
//todo::处理数据
$productModel = new Product();
foreach ($rows as $key => $row) {
if($key == 0){
continue;
}
$path = parse_url($row[1], PHP_URL_PATH);
$path = ltrim(parse_url($path, PHP_URL_PATH), '/');
$info = $productModel->read(['route'=>$path],['id','title','route','seo_mate']);
if($info === false){
echo '未找到数据->'.$row[0].PHP_EOL;
$d[] = $row[0];
continue;
}
$seo_mate = $info['seo_mate'];
$seo_mate['title'] = $row[2] ?? '';
$seo_mate['keyword'] = $row[3] ?? '';
//todo::重新生成路由
$route = RouteMap::setRoute($row[2],RouteMap::SOURCE_PRODUCT,$info['id'],$info['project_id']);
$productModel->edit(['route'=>$route,'old_route'=>$path,'seo_mate'=>json_encode($seo_mate,true),'title'=>$row[2]],['id'=>$info['id']]);
echo '执行的ID:'.$info['id'].PHP_EOL;
}
} catch (\Exception $e) {
// 输出更清晰的错误信息
echo '文件下载或解析失败:' . $e->getMessage() . PHP_EOL;
// 清理资源
if (file_exists($tempPath)) {
unlink($tempPath);
}
DB::disconnect('custom_mysql');
}
}
/**
* @remark :3951项目导入产品
* @name :import3951Product
... ...
... ... @@ -86,8 +86,8 @@ class SendProduct extends Command
$start_date = date('Y-m-d 00:00:00');
$end_date = date('Y-m-d 23:59:59');
$productModel = new Product();
$arr = $productModel->formatQuery(['send_time'=>['between',[$start_date,$end_date]],'status'=>3])->pluck('route')->toArray();
$productModel->edit(['status'=>1],['send_time'=>['between',[$start_date,$end_date]],'status'=>3]);
$arr = $productModel->formatQuery(['send_time'=>['<=',$end_date],'status'=>3])->pluck('route')->toArray();
$productModel->edit(['status'=>1],['send_time'=>['<=',$end_date],'status'=>3]);
return $arr;
}
... ... @@ -102,8 +102,8 @@ class SendProduct extends Command
$start_date = date('Y-m-d 00:00:00');
$end_date = date('Y-m-d 23:59:59');
$blogModel = new Blog();
$arr = $blogModel->formatQuery(['release_at'=>['between',[$start_date,$end_date]],'status'=>3])->pluck('url')->toArray();
$blogModel->edit(['status'=>1],['release_at'=>['between',[$start_date,$end_date]],'status'=>3]);
$arr = $blogModel->formatQuery(['release_at'=>['<=',$end_date],'status'=>3])->pluck('url')->toArray();
$blogModel->edit(['status'=>1],['release_at'=>['<=',$end_date],'status'=>3]);
return $arr;
}
... ... @@ -118,8 +118,8 @@ class SendProduct extends Command
$start_date = date('Y-m-d 00:00:00');
$end_date = date('Y-m-d 23:59:59');
$newsModel = new News();
$arr = $newsModel->formatQuery(['release_at'=>['between',[$start_date,$end_date]],'status'=>3])->pluck('url')->toArray();
$newsModel->edit(['status'=>1],['release_at'=>['between',[$start_date,$end_date]],'status'=>3]);
$arr = $newsModel->formatQuery(['release_at'=>['<=',$end_date],'status'=>3])->pluck('url')->toArray();
$newsModel->edit(['status'=>1],['release_at'=>['<=',$end_date],'status'=>3]);
return $arr;
}
}
... ...
<?php
/**
* Created by PhpStorm.
* User: zhl
* Date: 2025/10/23
* Time: 17:29
*/
namespace App\Http\Controllers\Api;
use App\Models\Geo\GeoConfirm;
use App\Models\Geo\GeoWritings;
use App\Models\Project\Project;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Crypt;
/**
* GEO相关
* Class GeoController
* @package App\Http\Controllers\Api
*/
class GeoController extends BaseController
{
/**
* 获取确认文章列表
* @param Request $request
* @return false|string
*/
public function getWritingsList()
{
try {
$token = trim($this->param['token']);
$param = Crypt::decrypt($token);
if ($param['send_at'] + 86400 < time()) {}
$project_id = $param['project_id'];
} catch (\Exception $e) {
return $this->error('非法请求');
}
$project = Project::select('title', 'version')->where(['project_id' => $this->param['project_id']])->first();
$list = GeoWritings::select(['title', 'status', 'uniqid', 'confirm_at'])->where(['project_id' => $project_id, 'is_del' => GeoWritings::IS_DEL_FALSE])->get();
$result = [
'project' => $project,
'list' => $list
];
return $this->success($result);
}
/**
* 获取详情
* @param Request $request
* @return false|string
*/
public function getWritingsDetail(Request $request)
{
$token = trim($request->input('token'));
$detail = GeoWritings::select(['title', 'content', 'status'])->where(['uniqid' => $token])->first();
return $this->success($detail);
}
/**
* 确认核心文章数据
* @param Request $request
* @return false|string
*/
public function confirmWritings(Request $request)
{
$request->validate([
'token' => 'required',
'title' => 'required|max:120',
'content' => 'required|max:5000'
], [
'token.required' => '非法请求',
'title.required' => '标题不能为空',
'title.max' => '最大长度不能超过120字符',
'content.required' => '内容不能为空',
'content.max' => '内容过长保存失败',
]);
$token = trim($request->input('token'));
$data = GeoWritings::where(['uniqid' => $token])->first();
if (empty($data)){
return $this->error('非法请求');
}
if ($data->status != GeoWritings::STATUS_RUNNING){
return $this->error('当前文章已确认,不可再次确认');
}
// FIXME 验证完成,保存数据,计算内容长度,处理内容中的资源, IP 确认时间 状态
return $data;
}
/**
* 获取确认数据
* @param Request $request
* @return false|string
*/
public function getConfirm(Request $request)
{
$token = trim($request->input('token'));
$data = GeoConfirm::where(['uniqid' => $token])->first();
if (empty($data)){
return $this->error('当前授权已失效');
}
$content = explode("\n", $data->content);
$confirm = explode("\n", $data->confirm);
$type = $data->type;
$status = $data->status;
$result = compact('content', 'confirm', 'type', 'status');
return $this->success($result);
}
/**
* 保存确认数据
* 验证当前确认数据状态, 不可重复确认
* @param Request $request
*/
public function saveConfirm(Request $request)
{}
}
... ...
<?php
/**
* Created by PhpStorm.
* User: zhl
* Date: 2025/10/23
* Time: 10:23
*/
namespace App\Http\Controllers\Aside\Geo;
use App\Enums\Common\Code;
use App\Http\Controllers\Aside\BaseController;
use App\Models\Geo\GeoConf;
use App\Models\Geo\GeoConfirm;
use App\Models\Manage\ManageHr;
use App\Models\Project\KeywordPrefix;
use App\Models\Project\Project;
use App\Models\ProjectAssociation\ProjectAssociation;
use Illuminate\Http\Request;
/**
* Class GeoController
* @package App\Http\Controllers\Aside\Geo
*/
class GeoController extends BaseController
{
/**
* 获取GEO相关配置
* @param Request $request
*/
public function getConfig()
{
$this->request->validate([
'project_id' => 'required',
], [
'project_id.required' => '项目ID不能为空',
]);
$projectModel = new Project();
$project_geo_conf = $projectModel->read(['id' => $this->param['project_id']],['title', 'version', 'geo_status', 'geo_qualify_num']);
$geoConfModel = new GeoConf();
$geo_conf = $geoConfModel->read(['project_id' => $this->param['project_id']]);
if($geo_conf === false){//数据未初始化
$geo_conf = [
'project_id' => $this->param['project_id'],
'manager_id'=>0,
'company'=>$project_geo_conf['title'],
'brand'=>'',
'description'=>''
];
}
//负责人集合
$geo_manage_list = $geoConfModel->geoManage();
// geo配置管理员,已经移除管理员列表,补充管理员信息
if ($geo_conf && $geo_conf['manager_id'] && empty($geo_manage_list[$geo_conf['manager_id']])) {
$manage = ManageHr::where(['id' => $geo_conf['manager_id']])->pluck('name', 'id')->toArray();
$geo_manage_list = array_merge($geo_manage_list, $manage);
}
$result = [
'project_geo_conf' => $project_geo_conf,
'geo_conf' => $geo_conf,
'geo_manage_list' => $geo_manage_list,
'geo_keyword' => [
'prefix' => KeywordPrefix::getKeyword($this->param['project_id'], KeywordPrefix::TYPE_GEO_PREFIX),
'suffix' => KeywordPrefix::getKeyword($this->param['project_id'], KeywordPrefix::TYPE_GEO_SUFFIX),
],
];
$this->response('success', Code::SUCCESS, $result);
}
/**
* 保存GEO配置
* TODO 单独保存GEO开启状态, 达标数量
* @param Request $request
* @throws \App\Exceptions\AsideGlobalException
*/
public function saveConfig()
{
$this->request->validate([
'project_id' => 'required',
'manager_id' => 'nullable|integer',
'company' => 'nullable|max:200',
'brand' => 'nullable|max:200',
'description' => 'nullable|max:500',
], [
'project_id.required' => '项目ID不能为空',
'manager_id.integer' => '管理员参数非法',
'company.max' => '公司名称不能超过200个字符',
'brand.max' => '品牌名不能超过200个字符',
'description.max' => '描述不能超过500个字符',
]);
try {
$data = GeoConf::saveConf($this->param['project_id'], $this->param['manager_id'], $this->param['company'], $this->param['brand'], $this->param['description'], $this->param['prefix'], $this->param['suffix']);
# FIXME 保存GEO状态 达标数量
$this->response('success', Code::SUCCESS, $data);
} catch (\Exception $e) {
$this->fail('配置保存失败, error:' . $e->getMessage());
}
}
/**
* 保存确认数据, 并推送微信群
* @param Request $request
* @throws \App\Exceptions\AsideGlobalException
*/
public function saveConfirmContent()
{
$this->request->validate([
'project_id' => 'required',
'type' => 'required|integer',
'content' => 'required',
'max_num' => 'required',
], [
'project_id.required' => '项目ID不能为空',
'type.required' => '确定数据类型不能为空',
'type.integer' => '确定数据类型不正确',
'content.required' => '确定数据不能为空',
'max_num.required' => '最大确认数量不能为空',
]);
try {
$data = GeoConfirm::saveContent($this->param['project_id'], $this->param['type'], $this->param['content'], $this->param['max_num']);
$friend = ProjectAssociation::where(['project_id' => $this->param['project_id']])->first();
if (empty($friend)){
$this->fail('项目未绑定微信群, 推送消息失败!');
}
$data = GeoConfirm::sendConfirmMessage($data->id, $friend->friend_id);
$this->response('success', Code::SUCCESS, $data);
} catch (\Exception $e) {
$this->fail('操作失败, error:' . $e->getMessage());
}
}
/**
* OA后台管理员,保存确认数据
* 客户可以进行确认, OA后台也可以进行确认,以及修改
* @param Request $request
*/
public function saveConfirmData(Request $request)
{
}
}
... ...
<?php
/**
* @remark :
* @name :GeoWritingTaskController.php
* @author :lyh
* @method :post
* @time :2025/10/25 10:40
*/
namespace App\Http\Controllers\Aside\Geo;
use App\Http\Controllers\Aside\BaseController;
/**
* @remark :文章任务(收集数据)
* @name :GeoWritingTaskController
* @author :lyh
* @method :post
* @time :2025/10/25 10:40
*/
class GeoWritingTaskController extends BaseController
{
/**
* @remark :文章任务列表
* @name :lists
* @author :lyh
* @method :post
* @time :2025/10/25 10:41
*/
public function lists(){
}
}
... ...
<?php
/**
* @remark :
* @name :GeoWritingsController.php
* @author :lyh
* @method :post
* @time :2025/10/25 10:41
*/
namespace App\Http\Controllers\Aside\Geo;
use App\Http\Controllers\Aside\BaseController;
/**
* @remark :geo文章
* @name :GeoWritingsController
* @author :lyh
* @method :post
* @time :2025/10/25 10:41
*/
class GeoWritingsController extends BaseController
{
}
... ...
... ... @@ -10,7 +10,6 @@ use App\Http\Logic\Aside\Project\OnlineCheckLogic;
use App\Http\Logic\Aside\Project\ProcessRecordsLogic;
use App\Http\Logic\Aside\Project\ProjectLogic;
use App\Http\Requests\Aside\Project\ProcessRecordsRequest;
use App\Models\Ai\AiVideo;
use App\Models\ASide\APublicModel;
use App\Models\Channel\Channel;
use App\Models\Channel\User;
... ... @@ -23,7 +22,10 @@ use App\Models\Devops\ServersIp;
use App\Models\Domain\DomainCreateTask;
use App\Models\Domain\DomainInfo;
use App\Models\Domain\DomainInfo as DomainInfoModel;
use App\Models\Geo\GeoArticle;
use App\Models\Geo\GeoConf;
use App\Models\Geo\GeoLink;
use App\Models\Geo\GeoQuestionResult;
use App\Models\HomeCount\Count;
use App\Models\Industry\ProjectIndustry;
use App\Models\Inquiry\InquirySet;
... ... @@ -31,7 +33,6 @@ use App\Models\Manage\BelongingGroup;
use App\Models\Manage\ManageHr;
use App\Models\Project\AiVideoTask;
use App\Models\Project\DeployBuild;
use App\Models\Project\DeployOptimize;
use App\Models\Project\Payment;
use App\Models\Project\ProcessRecords;
use App\Models\Project\Project;
... ... @@ -43,7 +44,6 @@ use App\Models\Task\Task;
use App\Models\WebSetting\WebLanguage;
use App\Models\WorkOrder\TicketProject;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
/**
... ... @@ -226,7 +226,7 @@ class ProjectController extends BaseController
if($this->map['domain_type'] == 'domain'){
$parsedUrl = parse_url($this->map['domain_search']);
$this->map['domain_search'] = $parsedUrl['host'] ?? $this->map['domain_search'];
$ids = DomainInfo::where('domain', 'like', '%'.$this->map['domain_search'].'%')->pluck('id')->toArray();
$ids = DomainInfoModel::where('domain', 'like', '%'.$this->map['domain_search'].'%')->pluck('id')->toArray();
$query->whereIn('gl_project_deploy_optimize.domain', $ids);
}else{
$query->where('gl_project_deploy_build.test_domain','like','%'.$this->map['domain_search'].'%');
... ... @@ -320,8 +320,12 @@ class ProjectController extends BaseController
});
}
}
if(isset($this->map['seo_plan'])){
$query = $query->whereNotIn('gl_project_deploy_build.seo_plan',[0,9])->where('gl_project_deploy_build.plan',0);
if (isset($this->map['seo_plan'])) {
$query = $query->where('gl_project_deploy_build.seo_plan', '!=', 0)
->where(function ($subQuery) {
$subQuery->where('gl_project_deploy_build.plan', '=', 0)
->orWhere('gl_project_deploy_build.seo_plan', '!=', 9);
});
}
if(isset($this->map['site_status'])){
$query = $query->where('gl_project.site_status',$this->map['site_status']);
... ... @@ -445,32 +449,45 @@ class ProjectController extends BaseController
$item['type'] = $item['extend_type'];
}
$manageModel = new ManageHr();
$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']);
//geo项目
if(($item['plan'] == 0) && ($item['seo_plan'] != 0)){
//geo项目负责人
$geoConfModel = new GeoConf();
$manage_id = $geoConfModel->getValue(['project_id'=>$item['id']],'manager_id');
$item['geo_manage_name'] = $manageModel->getName($manage_id);
$geoArticleModel = new GeoArticle();
$item['geo_article_num'] = $geoArticleModel->counts(['project_id'=>$item['id']]);//文章数量
$geoLinkModel = new GeoLink();
$item['geo_link_num'] = $geoLinkModel->counts(['project_id'=>$item['id']]);//权威新闻数量
$questionResModel = new GeoQuestionResult();
$item['geo_qualify_num'] = $questionResModel->counts(['project_id'=>$item['id'],'hit'=>['!=',0],'platform'=>['in',['openai', 'gemini','google_ai_overview']]]);//排名
}
$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']);
$planMap = Project::planMap();
$seoPlanMap = Project::seoMap();
$item['plan'] = $planMap[$item['plan']] ?? '';
$item['seo_plan'] = $seoPlanMap[$item['seo_plan']] ?? '';
$item['created_at'] = date('Y年m月d日', strtotime($item['cooperate_date']));
$item['autologin_code'] = getAutoLoginCode($item['id']);
$domainModel = new DomainInfo();
$domainModel = new DomainInfoModel();
$item['domain'] = !empty($item['domain']) ? $domainModel->getDomain($item['domain']) : '';
$item['uuid'] = TicketProject::where('table_id', $item['id'])->where('project_cate', 2)->value('uuid') ?? null;
$item['friend_id'] = ProjectAssociation::where('project_id', $item['id'])->where('status', ProjectAssociation::STATUS_NORMAL)->where('binding_app', ProjectAssociation::ENTERPRISE_WECHAT)->value('friend_id') ?? null;
$item['autologin_code'] = getAutoLoginCode($item['id']);
$item['created_at'] = date('Y年m月d日', strtotime($item['cooperate_date']));
$item['product_num'] = $data['product'] ?? 0;
$item['keyword_num'] = $data['key'] ?? 0;
$item['article_num'] = ($data['blog'] ?? 0) + ($data['news'] ?? 0);
$item['task_finish_num'] = Task::getNumByProjectId($item['id'], Task::STATUS_DOWN);
$item['task_pending_num'] = Task::getNumByProjectId($item['id'], [Task::STATUS_DONGING, Task::STATUS_WAIT]);
$item['collect_time'] = $item['is_upgrade'] ? UpdateLog::getProjectUpdate($item['id']) : '';
$item['uuid'] = TicketProject::where('table_id', $item['id'])->where('project_cate', 2)->value('uuid') ?? null;
$item['friend_id'] = ProjectAssociation::where('project_id', $item['id'])->where('status', ProjectAssociation::STATUS_NORMAL)->where('binding_app', ProjectAssociation::ENTERPRISE_WECHAT)->value('friend_id') ?? null;
$item['channel'] = Channel::getChannelText($item['channel']['user_id'] ?? 0);
return $item;
}
... ... @@ -793,7 +810,6 @@ class ProjectController extends BaseController
$order_by_sort = $request->input('order_by_sort', 'desc');
$start_time = $this->param['start_time'] ?? '';
$end_time = $this->param['end_time'] ?? '';
if(!$source_id && !$id){
$this->response('参数异常',Code::SYSTEM_ERROR);
}
... ... @@ -887,7 +903,6 @@ class ProjectController extends BaseController
$param['yesterday_ip_count'] = $yesterday_count['ip_num'] ?? 0;
$param['today_ip_count'] = $today_count['ip_num'] ?? 0;
$param['inquiry_num'] = $today_count['inquiry_num'] ?? 0;
$list[] = $param;
}
$data['list'] = $list;
... ... @@ -1178,7 +1193,6 @@ class ProjectController extends BaseController
'id.required' => '项目id不能为空',
'site_status.required' => '状态不能为空',
]);
//获取项目数据
$projectModel = new Project();
$projectInfo = $projectModel->read(['id'=>$this->param['id']],['project_type','serve_id','site_status','site_token']);
... ... @@ -1188,14 +1202,12 @@ class ProjectController extends BaseController
if($projectInfo['site_status'] == $this->param['site_status']){
$this->response('success');
}
//获取服务器数据
$serverIpModel = new ServersIp();
$serversIpInfo = $serverIpModel->read(['id' => $projectInfo['serve_id']], ['servers_id']);
if(!$serversIpInfo){
$this->fail('获取项目所属服务器失败');
}
if($serversIpInfo['servers_id'] == ServerConfig::SELF_SITE_ID){
//自建站项目
if($this->param['site_status'] == 1){
... ... @@ -1205,7 +1217,6 @@ class ProjectController extends BaseController
//开启站点
$site_token = str_replace('_expired','',$projectInfo['site_token']);
}
$projectModel->edit(['site_status'=>$this->param['site_status'],'site_token'=>$site_token],['id'=>$this->param['id']]);
}else{
//普通项目
... ... @@ -1215,7 +1226,6 @@ class ProjectController extends BaseController
if(!$domainInfo){
$this->fail('获取域名数据失败');
}
if($this->param['site_status'] == 1){
//关闭站点:通知C端
$re = curl_get('https://'.$domainInfo['domain'].'/api/stop_or_start_website');
... ... @@ -1256,10 +1266,8 @@ class ProjectController extends BaseController
}
}
}
$projectModel->edit(['site_status'=>$this->param['site_status']],['id'=>$this->param['id']]);
}
$this->response('success');
}
... ... @@ -1339,6 +1347,7 @@ class ProjectController extends BaseController
*/
public function getSpAdsLists()
{
$params = $this->param;
$url = 'https://oa.cmer.com/api/sp_ads_lists';
// 发送 GET 请求(附带 token)
$params['token'] = md5('qqs' . date('Y-m-d'));
... ...
... ... @@ -21,6 +21,9 @@ class AiBlogController extends BaseController
* @time :2025/2/14 13:59
*/
public function getAiBlog(AiBlog $aiBlog){
if(isset($this->map['new_title']) && !empty($this->map['new_title'])){
$this->map['new_title'] = ['like', '%'.$this->map['new_title'].'%'];
}
$lists = $aiBlog->lists($this->map,$this->page,$this->row,'id',['id','keyword','new_title','route','image','task_id','status','created_at','updated_at']);
if(!empty($lists) && !empty($lists['list'])){
foreach ($lists['list'] as $k => $v){
... ...
... ... @@ -389,14 +389,17 @@ class FileController
*/
public function getFileList(){
if(isset($this->cache['project_id']) && !empty($this->cache['project_id'])){
$this->map['project_id'] = $this->cache['project_id'];
$this->param['project_id'] = $this->cache['project_id'];
}
$fileModel = new File();
$this->map['type'] = 'mp4';
$lists = $fileModel->list($this->map,'id',['id','hash','type','path','created_at','name']);
foreach ($lists as $k => $v){
$this->param['type'] = 'mp4';
$page = $this->param['page'] ?? 1;
$row = $this->param['row'] ?? 20;
unset($this->param['page'],$this->param['row']);
$lists = $fileModel->lists($this->param,$page,$row,'id',['id','hash','type','path','created_at','name']);
foreach ($lists['list'] as $k => $v){
$v['file_link'] = getFileUrl($v['path'],$this->cache['storage_type'] ?? 0,$this->cache['project_location'] ?? 0,$this->cache['file_cdn'] ?? 0);
$lists[$k] = $v;
$lists['list'][$k] = $v;
}
$this->response('success',Code::SUCCESS,$lists);
}
... ...
<?php
/**
* @remark :
* @name :GeoWritingsLogic.php
* @author :lyh
* @method :post
* @time :2025/10/25 10:43
*/
namespace App\Http\Logic\Aside\Geo;
use App\Http\Logic\Aside\BaseLogic;
use App\Models\Geo\GeoWritings;
/**
* @remark :文章任务
* @name :GeoWritingsLogic
* @author :lyh
* @method :post
* @time :2025/10/25 10:44
*/
class GeoWritingsLogic extends BaseLogic
{
public function __construct()
{
parent::__construct();
$this->param = $this->requestAll;
$this->model = new GeoWritings();
}
}
... ...
<?php
/**
* @remark :
* @name :GeoWritingsTaskLogic.php
* @author :lyh
* @method :post
* @time :2025/10/25 10:45
*/
namespace App\Http\Logic\Aside\Geo;
use App\Http\Logic\Aside\BaseLogic;
use App\Models\Geo\GeoWritings;
use App\Models\Geo\GeoWritingsTask;
class GeoWritingsTaskLogic extends BaseLogic
{
public function __construct()
{
parent::__construct();
$this->param = $this->requestAll;
$this->model = new GeoWritingsTask();
}
}
... ...
... ... @@ -34,9 +34,20 @@ class GeoQuestionResLogic extends BaseLogic
* @time :2025/7/8 17:16
*/
public function getCount(){
$total = $this->model->counts(['project_id'=>$this->user['project_id']]);
$type_1 = $this->model->counts(['type'=>$this->model::BRAND_TYPE,'project_id'=>$this->user['project_id']]);
$type_2 = $this->model->counts(['type'=>$this->model::MARKETING_TYPE,'project_id'=>$this->user['project_id']]);
$total = $this->model
->where('project_id', $this->user['project_id'])
->distinct('question')
->count('question');
$type_1 = $this->model
->where('type', $this->model::BRAND_TYPE)
->where('project_id', $this->user['project_id'])
->distinct('question')
->count('question');
$type_2 = $this->model
->where('type', $this->model::MARKETING_TYPE)
->where('project_id', $this->user['project_id'])
->distinct('question')
->count('question');
return $this->success(['total'=>$total,'type_1'=>$type_1,'type_2'=>$type_2]);
}
... ...
<?php
/**
* Created by PhpStorm.
* User: zhl
* Date: 2025/10/22
* Time: 17:01
*/
namespace App\Models\Geo;
use App\Models\Base;
use App\Models\Manage\ManageHr;
use Illuminate\Support\Facades\Cache;
/**
* GEO 相关配置
* Class GeoConf
* @package App\Models\Geo
*/
class GeoConf extends Base
{
/**
* @var string table
*/
protected $table = 'gl_project_geo_conf';
/**
* 保存GEO相关配置
* @param $project_id
* @param $manager_id
* @param $company
* @param $brand
* @param $description
* @param $prefix
* @param $suffix
* @return GeoConf
*/
public static function saveConf($project_id, $manager_id, $company, $brand, $description, $prefix, $suffix)
{
$data = self::where(compact('project_id'))->first();
if (empty($data)) {
$data = new self();
$data->project_id = $project_id;
}
$data->manager_id = $manager_id;
$data->company = $company;
$data->brand = $brand;
$data->description = $description;
$data->prefix = $prefix;
$data->suffix = $suffix;
$data->save();
return $data;
}
/**
* GEO 负责人集合
* TODO 负责人:优化师 + 陶婵 + 艾媛媛
* @return array
*/
public function geoManage()
{
$key = 'geo_manage_list_' . date('Ymd');
$optimize = Cache::get($key);
if (empty($optimize)) {
$optimize = ManageHr::where(['status' => ManageHr::STATUS_ONE, 'entry_position' => 46])->pluck('name', 'id')->toArray();
$optimize[1] = '陶婵';
$optimize[875] = '艾媛媛';
ksort($optimize);
Cache::put($key, $optimize, 3600);
}
return $optimize;
}
}
... ...
<?php
/**
* Created by PhpStorm.
* User: zhl
* Date: 2025/10/22
* Time: 17:03
*/
namespace App\Models\Geo;
use App\Models\Base;
use App\Models\Workchat\MessagePush;
/**
* GEO 客户确认相关数据
* Class GeoConfirm
* @package App\Models\Geo
*/
class GeoConfirm extends Base
{
/**
* @var string table
*/
protected $table = 'gl_project_geo_confirm';
/**
* 客户确认类型
*/
const TYPE_TITLE = 1;
const TYPE_KEYWORD = 2;
/**
* 数据状态
*/
const STATUS_INIT = 1; # 初始化数据,仅保存完成
const STATUS_RUNNING = 2; # 已推送客户,等待客户确认
const STATUS_FINISH = 3; # 客户已确认完成
/**
* 客户确认数据类型
* @return array
*/
public static function typeMapping()
{
return [
self::TYPE_TITLE => '确认标题',
self::TYPE_KEYWORD => '确认关键词'
];
}
/**
* 客户确认数据状态
* @return array
*/
public static function statusMapping()
{
return [
self::STATUS_INIT => '初始数据',
self::STATUS_RUNNING => '数据确认中',
self::STATUS_FINISH => '客户已确认'
];
}
/**
* @param $project_id
* @param $type
* @param $content
* @param $max_num
* @return GeoConfirm
*/
public static function saveContent($project_id, $type, $content, $max_num)
{
$data = self::where(compact('project_id', 'type'))->first();
if (empty($data)) {
$data = new self();
$data->project_id = $project_id;
$data->type = $type;
}
$data->content = $content;
$data->max_num = $max_num;
$data->save();
return $data;
}
/**
* 保存确认数据
* @param $project_id
* @param $type
* @param $confirm
* @param $confirm_num
* @param $confirm_ip
* @return bool
*/
public static function saveConfirm($project_id, $type, $confirm, $confirm_num, $confirm_ip)
{
$data = self::where(compact('project_id', 'type'))->first();
if (empty($data))
return false;
$data->confirm = $confirm;
$data->confirm_ip = $confirm_ip;
$data->confirm_num = $confirm_num;
$data->confirm_at = now();
$data->status = self::STATUS_FINISH;
$data->save();
return $data;
}
/**
* 推送确认消息
* @param $id
* @return bool
*/
public static function sendConfirmMessage($id, $friend_id)
{
$data = self::where(compact('id'))->first();
$project_id = $data->project_id;
$content_type = 'Link';
$send_time = now();
$type = MessagePush::TYPE_GEO_CONFIRM;
$token = uniqid().$friend_id;
$created_at = $updated_at = now();
$content_array = [
'title' => self::typeMapping()[$data->type],
'desc' => self::typeMapping()[$data->type],
'size' => 0,
'thumbSize' => 0,
'thumbUrl' => 'https://hub.globalso.com/logocm.png',
'url' => 'https://oa.quanqiusou.cn/public-geo-confirm?token=' . $token
];
$content = json_encode($content_array, JSON_UNESCAPED_UNICODE);
MessagePush::insert(compact('project_id', 'friend_id', 'type', 'content_type', 'content', 'send_time', 'updated_at', 'created_at'));
// 消息推送, 更新数据
$data->confirm = '';
$data->send_at = now();
$data->uniqid = $token;
$data->status = self::STATUS_RUNNING;
$data->save();
return $data;
}
}
... ...
<?php
/**
* Created by PhpStorm.
* User: zhl
* Date: 2025/10/22
* Time: 17:25
*/
namespace App\Models\Geo;
use App\Models\Base;
use App\Models\ProjectAssociation\ProjectAssociation;
use App\Models\Workchat\MessagePush;
use Illuminate\Support\Facades\Crypt;
/**
* GEO 文章相关
* Class GeoWritings
* @package App\Models\Geo
*/
class GeoWritings extends Base
{
/**
* @var string $table
*/
protected $table = 'gl_project_geo_writings';
/**
* 文章来源类型
*/
const TYPE_AI_CREATE = 1;
const TYPE_SUBMIT = 2;
/**
* 文章状态类型
*/
const STATUS_INIT = 1; # 文章仅保存完成,未推送给客户
const STATUS_RUNNING = 2; # 已推送客户,等待客户确认
const STATUS_FINISH = 3; # 客户已确认完成
const STATUS_AI_WAIT = 7; # 任务提交成功,等待AI生成
const STATUS_AI_RUNNING = 8; # AI生成中
const IS_DEL_FALSE = 0;
const IS_DEL_TRUE = 1;
/**
* @return array
*/
public static function typeMapping()
{
return [
self::TYPE_AI_CREATE => 'AI生成文章',
self::TYPE_SUBMIT => '上传已有文章'
];
}
/**
* 状态隐私
* @return array
*/
public static function statusMapping()
{
return [
self::STATUS_INIT => '已就绪,待推送',
self::STATUS_RUNNING => '已推送,待确认',
self::STATUS_FINISH => '已确认',
self::STATUS_AI_WAIT => '等待生成',
self::STATUS_AI_RUNNING => '生成中',
];
}
/**
* 推送确认消息
* TODO 通过项目ID,时间生成推送token,页面打开后, 回传token解码确定展示项目数据
* @param $project_id
* @return bool
* @throws \Exception
*/
public static function sendConfirmMessage($project_id)
{
$friend = ProjectAssociation::where(['project_id' => $project_id])->first();
if (empty($friend)) {
throw new \Exception('项目未绑定微信群');
}
$content_type = 'Link';
$send_time = now();
$type = MessagePush::TYPE_GEO_CONFIRM;
$friend_id = $friend->friend_id;
$created_at = $updated_at = now();
$param = [
'project_id' => $project_id,
'send_at' => time()
];
$token = Crypt::encrypt($param);
$content_array = [
'title' => "确认核心文章",
'desc' => '确认核心文章',
'size' => 0,
'thumbSize' => 0,
'thumbUrl' => 'https://hub.globalso.com/logocm.png',
'url' => 'https://oa.quanqiusou.cn/public-geo-article-list?token=' . $token
];
$content = json_encode($content_array, JSON_UNESCAPED_UNICODE);
MessagePush::insert(compact('project_id', 'friend_id', 'type', 'content_type', 'content', 'send_time', 'updated_at', 'created_at'));
return true;
}
}
... ...
<?php
/**
* @remark :
* @name :GeoWritingsTask.php
* @author :lyh
* @method :post
* @time :2025/10/25 10:47
*/
namespace App\Models\Geo;
use App\Models\Base;
/**
* @remark :文章生成任务
* @name :GeoWritingsTask
* @author :lyh
* @method :post
* @time :2025/10/25 10:48
*/
class GeoWritingsTask extends Base
{
protected $table = 'gl_project_geo_writings_task';
}
... ...
... ... @@ -10,6 +10,7 @@
namespace App\Models\Project;
use App\Models\Base;
use Illuminate\Support\Facades\Cache;
/**
* @remark :关键字前缀/后缀
... ... @@ -21,4 +22,68 @@ use App\Models\Base;
class KeywordPrefix extends Base
{
protected $table = 'gl_project_keyword_prefix';
/**
* 前后缀类型
*/
const TYPE_OPTIMIZE_PREFIX = 1;
const TYPE_OPTIMIZE_SUFFIX = 2;
const TYPE_GEO_PREFIX = 3;
const TYPE_GEO_SUFFIX = 4;
/**
* 前后缀类型映射
* @return array
*/
public static function typeMapping()
{
return [
self::TYPE_OPTIMIZE_PREFIX => '优化关键词前缀',
self::TYPE_OPTIMIZE_SUFFIX => '优化关键词后缀',
self::TYPE_GEO_PREFIX => 'GEO前缀',
self::TYPE_GEO_SUFFIX => 'GEO后缀',
];
}
/**
* 保存关键词前后缀
* @param $project_id
* @param $type
* @param $keyword
* @param $remark
* @return KeywordPrefix
*/
public static function saveKeyword($project_id, $type, $keyword, $remark)
{
$data = self::where(['project_id' => $project_id, 'keyword' => $keyword])->first();
if (empty($data)) {
$data = new self();
$data->project_id = $project_id;
$data->type = $type;
$data->keyword = $keyword;
}
$data->remark = $remark;
$data->save();
Cache::forget('project_keyword_ps_' . $project_id . '_' . $type);
return $data;
}
/**
* 获取关键词前后缀
* @param $project_id
* @param $type
* @return array|mixed
*/
public static function getKeyword($project_id, $type)
{
$key = 'project_keyword_ps_' . $project_id . '_' . $type;
$list = Cache::get($key);
if (empty($list)) {
$list = self::select(['id', 'type', 'keyword', 'remark'])->where(['type' => $type])->whereIn('project_id', [0, $project_id])->orderBy('project_id', 'asc')->get();
$list = $list->isEmpty() ? [] : $list->toArray();
if ($list)
Cache::put($key, $list, 1800);
}
return $list;
}
}
... ...
... ... @@ -30,6 +30,7 @@ class MessagePush extends Base
const TYPE_TICKET = 'Ticket';
const TYPE_DOMAIN = 'domain';
const TYPE_DOMAIN_V5 = 'domain_v5';
const TYPE_GEO_CONFIRM = 'geo_confirm';
//设置关联表名
/**
* @var mixed
... ...
... ... @@ -107,4 +107,8 @@ Route::prefix('ticket_upload')->group(function () {
Route::any('/saveLayoutDesign', [\App\Http\Controllers\Api\WorkOrder\TicketUploadDataController::class, 'saveLayoutDesign'])->name('ticket_upload.saveLayoutDesign');
Route::any('/getLayoutDesignInfo', [\App\Http\Controllers\Api\WorkOrder\TicketUploadDataController::class, 'getLayoutDesignInfo'])->name('ticket_upload.getLayoutDesignInfo');
});
//geo设置
Route::prefix('geo')->group(function () {
Route::any('/getConfirm', [\App\Http\Controllers\Api\GeoController::class, 'getConfirm'])->name('geo.getConfirm');
});
... ...
... ... @@ -586,6 +586,12 @@ Route::middleware(['aloginauth'])->group(function () {
Route::any('/downloadGeoLink', [Aside\Geo\GeoLinkController::class, 'downloadGeoLink'])->name('admin.geo_link_downloadGeoLink');
Route::any('/daResultData', [Aside\Geo\GeoLinkController::class, 'daResultData'])->name('admin.geo_link_daResultData');
});
//geo设置
Route::prefix('conf')->group(function () {
Route::any('/getConfig', [Aside\Geo\GeoController::class, 'getConfig'])->name('admin.geo_conf_getConfig');
Route::any('/saveConfig', [Aside\Geo\GeoController::class, 'saveConfig'])->name('admin.geo_conf_saveConfig');
Route::any('/saveConfirmContent', [Aside\Geo\GeoController::class, 'saveConfirmContent'])->name('admin.geo_conf_saveConfirmContent');
});
});
// 任务相关
Route::prefix('task')->group(function () {
... ... @@ -652,6 +658,8 @@ Route::middleware(['aloginauth'])->group(function () {
Route::any('/save', [Aside\Ticket\TicketUploadDataController::class,'save'])->name('ticket_upload_save');
Route::any('/detail', [Aside\Ticket\TicketUploadDataController::class,'detail'])->name('ticket_upload_detail');
});
});
//无需登录验证的路由组
... ...