作者 zhl

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

  1 +<?php
  2 +/**
  3 + * @remark :
  4 + * @name :GeoWritingsTask.php
  5 + * @author :lyh
  6 + * @method :post
  7 + * @time :2025/10/27 14:12
  8 + */
  9 +
  10 +namespace App\Console\Commands\Geo;
  11 +
  12 +use App\Helper\Gpt;
  13 +use App\Models\Geo\GeoWritings;
  14 +use Illuminate\Console\Command;
  15 +use Illuminate\Support\Facades\Redis;
  16 +use App\Models\Geo\GeoWritingsTask as GeoWritingsTaskModel;
  17 +
  18 +class GeoWritingsTask extends Command
  19 +{
  20 + /**
  21 + * The name and signature of the console command.
  22 + *
  23 + * @var string
  24 + */
  25 + protected $signature = 'geo_writings_task';
  26 +
  27 + public $porject_id;//记录当时执行的project_id
  28 +
  29 + /**
  30 + * The console command description.
  31 + *
  32 + * @var string
  33 + */
  34 + protected $description = 'geoAi生成文章';
  35 +
  36 + public function handle(){
  37 + while (true){
  38 + $geoWritingsTaskModel = new GeoWritingsTaskModel();
  39 + $task_id = $this->getTaskId();
  40 + if(empty($task_id)){
  41 + sleep(60);
  42 + continue;
  43 + }
  44 + echo date("Y-m-d H:i:s").',执行的任务id'.$task_id.PHP_EOL;
  45 + $info = $geoWritingsTaskModel->read(['id'=>$task_id]);
  46 + if($info === false){
  47 + echo date("Y-m-d H:i:s").',任务id数据不存在:'.$task_id.PHP_EOL;
  48 + continue;
  49 + }
  50 + //生成引言
  51 + $aiCommand1 = "请根据这个文章标题:{$info['title']},并同时参考公司的介绍’{$info['description']}‘以及公司参与的事件内容’{$info['event_content']}‘,给我写一个英文Press Release前言内容,前言内容请参考并引用{$info['keyword']}行业的一些专业数据报告,只需要1个段落,大约150-200字,请一定要出现这个关键词“{$info['prefix']}{$info['keyword']}{$info['suffix']}”,所有内容一定要用英文, 只需要回复我引言内容,不需要别的内容(比如序号、你的提示、寒暄、解释、注释之类的)";
  52 + $gptHelper = new Gpt();
  53 + $introduction = $gptHelper->openai_chat_qqs($aiCommand1);
  54 + //生成内容
  55 + $aiCommand2 = "请根据这个文章标题:{$info['title']},并同时参考公司的介绍{$info['description']},以及公司参与的事件内容{$info['event_content']},给我写一篇英文Press Release内容正文(已经有前言内容了),内容请参考并引用“{$info['prefix']}{$info['keyword']}{$info['suffix']}”行业的一些专业数据报告,新闻内容需要 5-6 个大纲,每个大纲需要标题和 1-2 段内容,最后1-2个大纲主要介绍企业的核心优势、主营产品应用场景、主要客户案例,并最后附带内容{$info['footer']},最后只需要回复我新闻稿内容,整个新闻稿内容字数1000字左右,不需要别的内容(比如序号、你的提示、寒暄、解释、注释之类的)";
  56 + $main = $gptHelper->openai_chat_qqs($aiCommand2);
  57 + $images = explode(',',$info['img']);
  58 + //组装一条数据
  59 + try {
  60 + $geoWritingsModel = new GeoWritings();
  61 + $saveData = [
  62 + 'project_id'=>$info['project_id'],
  63 + 'type'=>$geoWritingsModel::TYPE_AI_CREATE,
  64 + 'title'=>$info['title'],
  65 + 'content'=>$introduction.($images[0] ?? '').PHP_EOL.$main.($images[1] ?? ''),
  66 + 'content_length'=>strlen($introduction.PHP_EOL.$main),
  67 + 'uniqid'=>md5(uniqid().$task_id.$info['project_id']),
  68 + ];
  69 + $id = $geoWritingsModel->addReturnId($saveData);
  70 + $data = [
  71 + 'introduction'=>$introduction,
  72 + 'main'=>$main,
  73 + 'status'=>2,
  74 + 'writings_id'=>$id,
  75 + ];
  76 + $geoWritingsTaskModel->edit($data,['task_id'=>$task_id]);
  77 + }catch (\Exception $e){
  78 + echo date('Y-m-d H:i:s').'保存失败:'.$task_id.$e->getMessage().PHP_EOL;
  79 + continue;
  80 + }
  81 + }
  82 + }
  83 +
  84 + /**
  85 + * @remark :获取任务id
  86 + * @name :getTaskId
  87 + * @author :lyh
  88 + * @method :post
  89 + * @time :2025/10/27 14:22
  90 + */
  91 + public function getTaskId(){
  92 + $task_id = Redis::rpop('geo_writings_task');
  93 + $geoWritingsTaskModel = new GeoWritingsTaskModel();
  94 + if (empty($task_id)) {
  95 + $ids = $geoWritingsTaskModel->formatQuery(['status'=>0])->limit(100)->pluck('id');
  96 + if(!empty($ids)){
  97 + foreach ($ids as $id) {
  98 + Redis::lpush('geo_writings_task', $id);
  99 + }
  100 + $task_id = Redis::rpop('geo_writings_task');
  101 + }
  102 + }else{
  103 + $geoWritingsTaskModel->edit(['status'=>1],['id'=>$task_id]);
  104 + }
  105 + return $task_id;
  106 + }
  107 +}
@@ -124,6 +124,7 @@ class PostInquiryForward extends Command @@ -124,6 +124,7 @@ class PostInquiryForward extends Command
124 if ($res) { 124 if ($res) {
125 $form = InquiryInfo::find($detail['form_id']); 125 $form = InquiryInfo::find($detail['form_id']);
126 $form->success = $form->success + 1; 126 $form->success = $form->success + 1;
  127 + $form->timestamps = false;
127 $form->save(); 128 $form->save();
128 Log::channel('inquiry_forward')->info('询盘成功:', [$detail['form_id'], $val->id, getmypid()]); 129 Log::channel('inquiry_forward')->info('询盘成功:', [$detail['form_id'], $val->id, getmypid()]);
129 } 130 }
@@ -1597,18 +1597,24 @@ if (!function_exists('httpGetSsl')) { @@ -1597,18 +1597,24 @@ if (!function_exists('httpGetSsl')) {
1597 * @time :2025/9/22 14:46 1597 * @time :2025/9/22 14:46
1598 */ 1598 */
1599 function truncate_text($text, $limit = 300) { 1599 function truncate_text($text, $limit = 300) {
1600 - // 长度小于限制直接返回  
1601 if (mb_strlen($text, 'UTF-8') <= $limit) { 1600 if (mb_strlen($text, 'UTF-8') <= $limit) {
1602 return $text; 1601 return $text;
1603 } 1602 }
1604 - // 先取前 $limit 个字符  
1605 $truncated = mb_substr($text, 0, $limit, 'UTF-8'); 1603 $truncated = mb_substr($text, 0, $limit, 'UTF-8');
1606 - // 如果这一段包含空格(说明有英文单词),尽量在最后一个空格处截断 1604 + // 优先找空格
1607 $lastSpace = mb_strrpos($truncated, ' ', 0, 'UTF-8'); 1605 $lastSpace = mb_strrpos($truncated, ' ', 0, 'UTF-8');
1608 - if ($lastSpace !== false) {  
1609 - // 在最后一个空格处截断,避免英文单词被截断 1606 + if ($lastSpace === false) {
  1607 + // 没有空格则找 '-'
  1608 + $lastDash = mb_strrpos($truncated, '-', 0, 'UTF-8');
  1609 + if ($lastDash !== false && $lastDash > 0) {
  1610 + $lastSpace = $lastDash;
  1611 + }
  1612 + }
  1613 + if ($lastSpace !== false && $lastSpace > 0) {
1610 $truncated = mb_substr($truncated, 0, $lastSpace, 'UTF-8'); 1614 $truncated = mb_substr($truncated, 0, $lastSpace, 'UTF-8');
1611 } 1615 }
1612 return $truncated; 1616 return $truncated;
1613 } 1617 }
  1618 +
  1619 +
1614 } 1620 }
@@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
7 */ 7 */
8 namespace App\Http\Controllers\Api; 8 namespace App\Http\Controllers\Api;
9 9
  10 +use App\Enums\Common\Code;
10 use App\Models\Geo\GeoConfirm; 11 use App\Models\Geo\GeoConfirm;
11 use App\Models\Geo\GeoWritings; 12 use App\Models\Geo\GeoWritings;
12 use App\Models\Project\Project; 13 use App\Models\Project\Project;
@@ -35,13 +36,15 @@ class GeoController extends BaseController @@ -35,13 +36,15 @@ class GeoController extends BaseController
35 } catch (\Exception $e) { 36 } catch (\Exception $e) {
36 return $this->error('非法请求'); 37 return $this->error('非法请求');
37 } 38 }
38 - $project = Project::select('title', 'version')->where(['project_id' => $this->param['project_id']])->first();  
39 - $list = GeoWritings::select(['title', 'status', 'uniqid', 'confirm_at'])->where(['project_id' => $project_id, 'is_del' => GeoWritings::IS_DEL_FALSE])->get(); 39 + $projectModel = new Project();
  40 + $projectInfo = $projectModel->read(['project_id' => $project_id],['title','version']);
  41 + $geoWritingsModel = new GeoWritings();
  42 + $lists = $geoWritingsModel->list(['project_id' => $project_id, 'status' => 2 ,'is_del' => GeoWritings::IS_DEL_FALSE],'id',['title', 'status', 'uniqid', 'confirm_at']);
40 $result = [ 43 $result = [
41 - 'project' => $project,  
42 - 'list' => $list 44 + 'project' => $projectInfo,
  45 + 'list' => $lists
43 ]; 46 ];
44 - return $this->success($result); 47 + $this->response('success',Code::SUCCESS,$result);
45 } 48 }
46 49
47 /** 50 /**
@@ -49,11 +52,12 @@ class GeoController extends BaseController @@ -49,11 +52,12 @@ class GeoController extends BaseController
49 * @param Request $request 52 * @param Request $request
50 * @return false|string 53 * @return false|string
51 */ 54 */
52 - public function getWritingsDetail(Request $request) 55 + public function getWritingsDetail()
53 { 56 {
54 - $token = trim($request->input('token'));  
55 - $detail = GeoWritings::select(['title', 'content', 'status'])->where(['uniqid' => $token])->first();  
56 - return $this->success($detail); 57 + $geoWritingsModel = new GeoWritings();
  58 + $token = trim($this->param['token']);
  59 + $detail = $geoWritingsModel->read(['uniqid' => $token],['title', 'content', 'status']);
  60 + $this->response('success',Code::SUCCESS,$detail);
57 } 61 }
58 62
59 63
@@ -62,9 +66,9 @@ class GeoController extends BaseController @@ -62,9 +66,9 @@ class GeoController extends BaseController
62 * @param Request $request 66 * @param Request $request
63 * @return false|string 67 * @return false|string
64 */ 68 */
65 - public function confirmWritings(Request $request) 69 + public function confirmWritings()
66 { 70 {
67 - $request->validate([ 71 + $this->request->validate([
68 'token' => 'required', 72 'token' => 'required',
69 'title' => 'required|max:120', 73 'title' => 'required|max:120',
70 'content' => 'required|max:5000' 74 'content' => 'required|max:5000'
@@ -75,19 +79,21 @@ class GeoController extends BaseController @@ -75,19 +79,21 @@ class GeoController extends BaseController
75 'content.required' => '内容不能为空', 79 'content.required' => '内容不能为空',
76 'content.max' => '内容过长保存失败', 80 'content.max' => '内容过长保存失败',
77 ]); 81 ]);
78 - $token = trim($request->input('token'));  
79 - $data = GeoWritings::where(['uniqid' => $token])->first();  
80 - if (empty($data)){ 82 + $token = trim($this->param['token']);
  83 + $geoWritingsModel = new GeoWritings();
  84 + $info = $geoWritingsModel->read(['uniqid' => $token]);
  85 + if ($info === false){
81 return $this->error('非法请求'); 86 return $this->error('非法请求');
82 } 87 }
83 -  
84 - if ($data->status != GeoWritings::STATUS_RUNNING){ 88 + if ($info['status'] == GeoWritings::STATUS_FINISH){
85 return $this->error('当前文章已确认,不可再次确认'); 89 return $this->error('当前文章已确认,不可再次确认');
86 } 90 }
87 -  
88 -  
89 - // FIXME 验证完成,保存数据,计算内容长度,处理内容中的资源, IP 确认时间 状态  
90 - return $data; 91 + $this->param['confirm_ip'] = $this->request->ip();
  92 + $this->param['confirm_at'] = date('Y-m-d H:i:s');
  93 + $this->param['content_length'] = strlen($this->param['content']);
  94 + $this->param['status'] = GeoWritings::STATUS_FINISH;
  95 + $geoWritingsModel->edit($this->param,['uniqid' => $token]);
  96 + return true;
91 } 97 }
92 98
93 /** 99 /**
@@ -95,9 +101,9 @@ class GeoController extends BaseController @@ -95,9 +101,9 @@ class GeoController extends BaseController
95 * @param Request $request 101 * @param Request $request
96 * @return false|string 102 * @return false|string
97 */ 103 */
98 - public function getConfirm(Request $request) 104 + public function getConfirm()
99 { 105 {
100 - $token = trim($request->input('token')); 106 + $token = trim($this->param['token']);
101 $data = GeoConfirm::where(['uniqid' => $token])->first(); 107 $data = GeoConfirm::where(['uniqid' => $token])->first();
102 if (empty($data)){ 108 if (empty($data)){
103 return $this->error('当前授权已失效'); 109 return $this->error('当前授权已失效');
@@ -107,7 +113,7 @@ class GeoController extends BaseController @@ -107,7 +113,7 @@ class GeoController extends BaseController
107 $type = $data->type; 113 $type = $data->type;
108 $status = $data->status; 114 $status = $data->status;
109 $result = compact('content', 'confirm', 'type', 'status'); 115 $result = compact('content', 'confirm', 'type', 'status');
110 - return $this->success($result); 116 + $this->response('success',Code::SUCCESS,$result);
111 } 117 }
112 118
113 /** 119 /**
@@ -115,6 +121,20 @@ class GeoController extends BaseController @@ -115,6 +121,20 @@ class GeoController extends BaseController
115 * 验证当前确认数据状态, 不可重复确认 121 * 验证当前确认数据状态, 不可重复确认
116 * @param Request $request 122 * @param Request $request
117 */ 123 */
118 - public function saveConfirm(Request $request)  
119 - {} 124 + public function saveConfirm()
  125 + {
  126 + $this->request->validate([
  127 + 'uniqid' => 'required',
  128 + 'confirm' => 'required',
  129 + 'confirm_num' => 'required',
  130 + ], [
  131 + 'uniqid.required' => '非法请求',
  132 + 'confirm.required' => '客户确认内容不能为空',
  133 + 'confirm_num.max' => '客户确认数量不能为空',
  134 + ]);
  135 + $geoConfirmModel = new GeoConfirm();
  136 + $this->param['status'] = $geoConfirmModel::STATUS_FINISH;
  137 + $result = $geoConfirmModel->edit($this->param,['uniqid'=>$this->param['uniqid']]);
  138 + $this->response('success',Code::SUCCESS,$result);
  139 + }
120 } 140 }
@@ -23,8 +23,8 @@ use Illuminate\Http\Request; @@ -23,8 +23,8 @@ use Illuminate\Http\Request;
23 */ 23 */
24 class GeoConfirmController extends BaseController 24 class GeoConfirmController extends BaseController
25 { 25 {
26 - public function __construct(){  
27 - parent::__construct(); 26 + public function __construct(Request $request){
  27 + parent::__construct($request);
28 $this->logic = new GeoConfirmLogic(); 28 $this->logic = new GeoConfirmLogic();
29 } 29 }
30 30
@@ -24,8 +24,8 @@ use Illuminate\Http\Request; @@ -24,8 +24,8 @@ use Illuminate\Http\Request;
24 */ 24 */
25 class GeoController extends BaseController 25 class GeoController extends BaseController
26 { 26 {
27 - public function __construct(){  
28 - parent::__construct(); 27 + public function __construct(Request $request){
  28 + parent::__construct($request);
29 $this->logic = new GeoLogic(); 29 $this->logic = new GeoLogic();
30 } 30 }
31 31
@@ -68,16 +68,4 @@ class GeoController extends BaseController @@ -68,16 +68,4 @@ class GeoController extends BaseController
68 $data = $this->logic->saveConfig($this->param); 68 $data = $this->logic->saveConfig($this->param);
69 $this->response('success', Code::SUCCESS, $data); 69 $this->response('success', Code::SUCCESS, $data);
70 } 70 }
71 -  
72 -  
73 -  
74 - /**  
75 - * OA后台管理员,保存确认数据  
76 - * 客户可以进行确认, OA后台也可以进行确认,以及修改  
77 - * @param Request $request  
78 - */  
79 - public function saveConfirmData(Request $request)  
80 - {  
81 -  
82 - }  
83 } 71 }
@@ -9,7 +9,12 @@ @@ -9,7 +9,12 @@
9 9
10 namespace App\Http\Controllers\Aside\Geo; 10 namespace App\Http\Controllers\Aside\Geo;
11 11
  12 +use App\Enums\Common\Code;
  13 +use App\Helper\Gpt;
12 use App\Http\Controllers\Aside\BaseController; 14 use App\Http\Controllers\Aside\BaseController;
  15 +use App\Http\Logic\Aside\Geo\GeoWritingsTaskLogic;
  16 +use App\Http\Requests\Aside\Geo\GeoWritingsTaskRequest;
  17 +use Illuminate\Http\Request;
13 18
14 /** 19 /**
15 * @remark :文章任务(收集数据) 20 * @remark :文章任务(收集数据)
@@ -20,14 +25,82 @@ use App\Http\Controllers\Aside\BaseController; @@ -20,14 +25,82 @@ use App\Http\Controllers\Aside\BaseController;
20 */ 25 */
21 class GeoWritingTaskController extends BaseController 26 class GeoWritingTaskController extends BaseController
22 { 27 {
  28 + public function __construct(Request $request)
  29 + {
  30 + parent::__construct($request);
  31 + $this->logic = new GeoWritingsTaskLogic();
  32 + }
  33 +
23 /** 34 /**
24 - * @remark :文章任务列表 35 + * @remark :ai文章列表页
25 * @name :lists 36 * @name :lists
26 * @author :lyh 37 * @author :lyh
27 * @method :post 38 * @method :post
28 - * @time :2025/10/25 10:41 39 + * @time :2025/10/25 15:12
29 */ 40 */
30 public function lists(){ 41 public function lists(){
  42 + $data = $this->logic->listWritingTask($this->map,$this->page,$this->row,$this->order);
  43 + $this->response('success',Code::SUCCESS,$data);
  44 + }
  45 +
  46 + /**
  47 + * @remark :保存geoAi文章生成数据
  48 + * @name :lists
  49 + * @author :lyh
  50 + * @method :post
  51 + * @time :2025/10/25 10:41
  52 + */
  53 + public function saveWritingTask(){
  54 + $request = new GeoWritingsTaskRequest();
  55 + $request->validated();
  56 + $data = $this->logic->saveWritingTask();
  57 + $this->response('success',Code::SUCCESS,$data);
  58 + }
31 59
  60 + /**
  61 + * @remark :批量删除文章任务
  62 + * @name :delWritingTask
  63 + * @author :lyh
  64 + * @method :post
  65 + * @time :2025/10/25 15:03
  66 + */
  67 + public function delWritingTask(){
  68 + $this->request->validate([
  69 + 'id'=>'required|array',
  70 + ],[
  71 + 'id.required' => 'ID不能为空',
  72 + 'id.array' => 'ID为数组',
  73 + ]);
  74 + $data = $this->logic->delWritingTask();
  75 + $this->response('success',Code::SUCCESS,$data);
  76 + }
  77 +
  78 + /**
  79 + * @remark :Ai请求标题
  80 + * @name :sendAiTitle
  81 + * @author :lyh
  82 + * @method :post
  83 + * @time :2025/10/27 11:10
  84 + */
  85 + public function sendAiTitle(){
  86 + $this->request->validate([
  87 + 'company'=>'required',
  88 + 'number'=>'required',
  89 + 'prefix'=>'required',
  90 + 'keyword'=>'required',
  91 + 'suffix'=>'required',
  92 + 'event_title'=>'required',
  93 + ],[
  94 + 'company.required' => '公司简称不能为空',
  95 + 'number.required' => '生成数量不能为空',
  96 + 'prefix.required' => '关键词前缀为数组',
  97 + 'keyword.required' => '关键词不能为空',
  98 + 'suffix.requiredrequired' => '关键词后缀不能为空',
  99 + 'event_title.required' => '事件标题不能为空',
  100 + ]);
  101 + $aiCommand = "请根据公司简称{$this->param['company']}和这个公司产品的关键词:{$this->param['prefix']}{$this->param['keyword']}{$this->param['suffix']},以及{$this->param['event_title']},帮我写{$this->param['number']}个有吸引力的英文新闻标题;确保这个标题在Google上面唯一存在的,只需要回复我标题,不需要别的内容(比如序号、你的提示、寒暄、解释、注释之类的) 标题不能超过 100 字符数!,一行一个";
  102 + $gptHelper = new Gpt();
  103 + $data = $gptHelper->openai_chat_qqs($aiCommand);
  104 + $this->response('success',Code::SUCCESS,$data);
32 } 105 }
33 } 106 }
@@ -9,7 +9,12 @@ @@ -9,7 +9,12 @@
9 9
10 namespace App\Http\Controllers\Aside\Geo; 10 namespace App\Http\Controllers\Aside\Geo;
11 11
  12 +use App\Enums\Common\Code;
12 use App\Http\Controllers\Aside\BaseController; 13 use App\Http\Controllers\Aside\BaseController;
  14 +use App\Http\Logic\Aside\Geo\GeoWritingsLogic;
  15 +use App\Http\Requests\Aside\Geo\GeoWritingsRequest;
  16 +use App\Models\Geo\GeoWritings;
  17 +use Illuminate\Http\Request;
13 18
14 /** 19 /**
15 * @remark :geo文章 20 * @remark :geo文章
@@ -20,5 +25,70 @@ use App\Http\Controllers\Aside\BaseController; @@ -20,5 +25,70 @@ use App\Http\Controllers\Aside\BaseController;
20 */ 25 */
21 class GeoWritingsController extends BaseController 26 class GeoWritingsController extends BaseController
22 { 27 {
  28 + public function __construct(Request $request)
  29 + {
  30 + parent::__construct($request);
  31 + $this->logic = new GeoWritingsLogic();
  32 + }
23 33
  34 + /**
  35 + * @remark :文章列表数据
  36 + * @name :lists
  37 + * @author :lyh
  38 + * @method :post
  39 + * @time :2025/10/25 15:53
  40 + */
  41 + public function lists(){
  42 + $data = $this->logic->listWriting($this->map,$this->page,$this->row,$this->order);
  43 + $this->response('success',Code::SUCCESS,$data);
  44 + }
  45 +
  46 + /**
  47 + * @remark :保存geoAi文章生成数据
  48 + * @name :lists
  49 + * @author :lyh
  50 + * @method :post
  51 + * @time :2025/10/25 10:41
  52 + */
  53 + public function saveWriting(){
  54 + $request = new GeoWritingsRequest();
  55 + $request->validated();
  56 + $data = $this->logic->saveWriting();
  57 + $this->response('success',Code::SUCCESS,$data);
  58 + }
  59 +
  60 + /**
  61 + * @remark :批量删除文章任务
  62 + * @name :delWritingTask
  63 + * @author :lyh
  64 + * @method :post
  65 + * @time :2025/10/25 15:03
  66 + */
  67 + public function delWriting(){
  68 + $this->request->validate([
  69 + 'id'=>'required|array',
  70 + ],[
  71 + 'id.required' => 'ID不能为空',
  72 + 'id.array' => 'ID为数组',
  73 + ]);
  74 + $data = $this->logic->delWriting();
  75 + $this->response('success',Code::SUCCESS,$data);
  76 + }
  77 +
  78 + /**
  79 + * @remark :推送待审核列表消息
  80 + * @name :sendMessage
  81 + * @author :lyh
  82 + * @method :post
  83 + * @time :2025/10/28 09:59
  84 + */
  85 + public function sendWechatMessage(){
  86 + $this->request->validate([
  87 + 'project_id'=>'required',
  88 + ],[
  89 + 'project_id.required' => '项目ID不能为空',
  90 + ]);
  91 + $data = $this->logic->sendWechatMessage();
  92 + $this->response('success',Code::SUCCESS,$data);
  93 + }
24 } 94 }
@@ -160,7 +160,7 @@ class OptimizeController extends BaseController @@ -160,7 +160,7 @@ class OptimizeController extends BaseController
160 $manageModel = new ManageHr(); 160 $manageModel = new ManageHr();
161 $plan = Project::planMap(); 161 $plan = Project::planMap();
162 $seo_plan = Project::seoMap(); 162 $seo_plan = Project::seoMap();
163 - $item['plan'] = $plan[$item['plan']] ?? $seo_plan[1]; 163 + $item['plan'] = $plan[$item['plan']] ?? ($seo_plan[$item['seo_plan']] ?? '');
164 $item['channel'] = Channel::getChannelText($item['channel']['user_id'] ?? 0); 164 $item['channel'] = Channel::getChannelText($item['channel']['user_id'] ?? 0);
165 $item['build_leader'] = $manageModel->getName($item['leader_mid']); 165 $item['build_leader'] = $manageModel->getName($item['leader_mid']);
166 $item['build_manager'] = $manageModel->getName($item['manager_mid']); 166 $item['build_manager'] = $manageModel->getName($item['manager_mid']);
@@ -9,10 +9,8 @@ @@ -9,10 +9,8 @@
9 9
10 namespace App\Http\Logic\Aside\Geo; 10 namespace App\Http\Logic\Aside\Geo;
11 11
12 -use App\Enums\Common\Code;  
13 use App\Http\Logic\Aside\BaseLogic; 12 use App\Http\Logic\Aside\BaseLogic;
14 use App\Models\Geo\GeoConf; 13 use App\Models\Geo\GeoConf;
15 -use App\Models\Geo\GeoQuestion;  
16 use App\Models\Manage\ManageHr; 14 use App\Models\Manage\ManageHr;
17 use App\Models\Project\KeywordPrefix; 15 use App\Models\Project\KeywordPrefix;
18 use App\Models\Project\Project; 16 use App\Models\Project\Project;
@@ -67,7 +65,7 @@ class GeoLogic extends BaseLogic @@ -67,7 +65,7 @@ class GeoLogic extends BaseLogic
67 'suffix' => KeywordPrefix::getKeyword($project_id, KeywordPrefix::TYPE_GEO_SUFFIX), 65 'suffix' => KeywordPrefix::getKeyword($project_id, KeywordPrefix::TYPE_GEO_SUFFIX),
68 ], 66 ],
69 ]; 67 ];
70 - $this->success($result); 68 + return $this->success($result);
71 } 69 }
72 70
73 /** 71 /**
@@ -27,4 +27,69 @@ class GeoWritingsLogic extends BaseLogic @@ -27,4 +27,69 @@ class GeoWritingsLogic extends BaseLogic
27 $this->param = $this->requestAll; 27 $this->param = $this->requestAll;
28 $this->model = new GeoWritings(); 28 $this->model = new GeoWritings();
29 } 29 }
  30 +
  31 + /**
  32 + * @remark :列表数据
  33 + * @name :listWriting
  34 + * @author :lyh
  35 + * @method :post
  36 + * @time :2025/10/25 15:57
  37 + */
  38 + public function listWriting($map,$page,$row,$order){
  39 + $data = $this->model->lists($map,$page,$row,$order);
  40 + return $this->success($data);
  41 + }
  42 +
  43 + /**
  44 + * @remark :手动上传数据
  45 + * @name :saveWriting
  46 + * @author :lyh
  47 + * @method :post
  48 + * @time :2025/10/25 16:07
  49 + */
  50 + public function saveWriting(){
  51 + try {
  52 + $this->param['status'] = GeoWritings::STATUS_INIT;
  53 + if(isset($this->param['id']) &&!empty($this->param['id'])){
  54 + $id = $this->param['id'];
  55 + $this->model->edit($this->param,['id'=>$id]);
  56 + }else{
  57 + $this->param['uniqid'] = uniqid().$this->param['project_id'];
  58 + $id = $this->model->addReturnId($this->param);
  59 + }
  60 + }catch (\Exception $e){
  61 + $this->fail('保存数据失败,请联系管理员'.$e->getMessage());
  62 + }
  63 + return $this->success(['id'=>$id]);
  64 + }
  65 +
  66 + /**
  67 + * @remark :删除数据
  68 + * @name :delWritingTask
  69 + * @author :lyh
  70 + * @method :post
  71 + * @time :2025/10/25 15:05
  72 + */
  73 + public function delWriting()
  74 + {
  75 + $res = $this->model->del(['id'=>['in',$this->param['id']]]);
  76 + if($res === false){
  77 + $this->fail('删除失败,请联系管理员');
  78 + }
  79 + return $this->success();
  80 + }
  81 +
  82 + /**
  83 + * @remark :推送微信
  84 + * @name :sendWechatMessage
  85 + * @author :lyh
  86 + * @method :post
  87 + * @time :2025/10/28 10:15
  88 + */
  89 + public function sendWechatMessage()
  90 + {
  91 + $this->model->edit(['status'=>2],['status'=>1,'project_id'=>$this->param['project_id']]);
  92 + GeoWritings::sendConfirmMessage($this->param['project_id']);
  93 + return $this->success();
  94 + }
30 } 95 }
@@ -21,4 +21,55 @@ class GeoWritingsTaskLogic extends BaseLogic @@ -21,4 +21,55 @@ class GeoWritingsTaskLogic extends BaseLogic
21 $this->param = $this->requestAll; 21 $this->param = $this->requestAll;
22 $this->model = new GeoWritingsTask(); 22 $this->model = new GeoWritingsTask();
23 } 23 }
  24 +
  25 + /**
  26 + * @remark :
  27 + * @name :listWritingTask
  28 + * @author :lyh
  29 + * @method :post
  30 + * @time :2025/10/25 15:13
  31 + */
  32 + public function listWritingTask($map,$page,$row,$order){
  33 + $data = $this->model->lists($map,$page,$row,$order);
  34 + return $this->success($data);
  35 + }
  36 +
  37 + /**
  38 + * @remark :保存AI文章数据
  39 + * @name :saveWritingTask
  40 + * @author :lyh
  41 + * @method :post
  42 + * @time :2025/10/25 14:41
  43 + * @param :project_id->项目ID;company->公司名称;brand->品牌词;keyword->关键词;prefix->前缀;suffix->后缀;event_title->事件标题;
  44 + * event_content->事件内容;title->标题;description->描述;footer->结尾引用;img->图片;ai_model->ai_model
  45 + */
  46 + public function saveWritingTask(){
  47 + try {
  48 + if(isset($this->param['id']) &&!empty($this->param['id'])){
  49 + $id = $this->param['id'];
  50 + $this->model->edit($this->param,['id'=>$id]);
  51 + }else{
  52 + $id = $this->model->addReturnId($this->param);
  53 + }
  54 + }catch (\Exception $e){
  55 + $this->fail('保存数据失败,请联系管理员'.$e->getMessage());
  56 + }
  57 + return $this->success(['id'=>$id]);
  58 + }
  59 +
  60 + /**
  61 + * @remark :删除数据
  62 + * @name :delWritingTask
  63 + * @author :lyh
  64 + * @method :post
  65 + * @time :2025/10/25 15:05
  66 + */
  67 + public function delWritingTask()
  68 + {
  69 + $res = $this->model->del(['id'=>['in',$this->param['id']]]);
  70 + if($res === false){
  71 + $this->fail('删除失败,请联系管理员');
  72 + }
  73 + return $this->success();
  74 + }
24 } 75 }
@@ -401,7 +401,7 @@ class InquiryForwardLogic extends BaseLogic @@ -401,7 +401,7 @@ class InquiryForwardLogic extends BaseLogic
401 $text = Translate::tran($text, $lang); 401 $text = Translate::tran($text, $lang);
402 } 402 }
403 403
404 - return $this->success(['ai_message' => Common::deal_str($text)]); 404 + return $this->success(['ai_message' => str_replace('<br/>', PHP_EOL, Common::deal_str($text))]);
405 } 405 }
406 406
407 /** 407 /**
@@ -225,9 +225,7 @@ class NewsLogic extends BaseLogic @@ -225,9 +225,7 @@ class NewsLogic extends BaseLogic
225 if(isset($param['related_product_id'])){ 225 if(isset($param['related_product_id'])){
226 $param['related_product_id'] = implode(',',$param['related_product_id']); 226 $param['related_product_id'] = implode(',',$param['related_product_id']);
227 } 227 }
228 - if(!isset($param['seo_title']) || empty($param['seo_title'])){  
229 - $param['seo_title'] = truncate_text($param['name'],70);  
230 - } 228 + $param['seo_title'] = truncate_text($param['seo_title'] ?? $param['name'],70);
231 return $this->success($param); 229 return $this->success($param);
232 } 230 }
233 231
@@ -35,6 +35,9 @@ class WebSettingReceivingLogic extends BaseLogic @@ -35,6 +35,9 @@ class WebSettingReceivingLogic extends BaseLogic
35 */ 35 */
36 public function setting_receiving_save(){ 36 public function setting_receiving_save(){
37 $data = []; 37 $data = [];
  38 + if(!isset($this->param['data']) || empty($this->param['data'])){
  39 + $this->fail('参数错误,请联系管理员');
  40 + }
38 foreach ($this->param['data'] as $v){ 41 foreach ($this->param['data'] as $v){
39 if($v['type'] == 1){ 42 if($v['type'] == 1){
40 // 使用正则表达式匹配中国大陆手机号 43 // 使用正则表达式匹配中国大陆手机号
  1 +<?php
  2 +/**
  3 + * @remark :
  4 + * @name :GeoWritingsTaskRequest.php
  5 + * @author :lyh
  6 + * @method :post
  7 + * @time :2025/10/25 14:21
  8 + */
  9 +
  10 +namespace App\Http\Requests\Aside\Geo;
  11 +
  12 +use Illuminate\Foundation\Http\FormRequest;
  13 +
  14 +class GeoWritingsRequest extends FormRequest
  15 +{
  16 + /**
  17 + * Determine if the user is authorized to make this request.
  18 + *
  19 + * @return bool
  20 + */
  21 + public function authorize()
  22 + {
  23 + return true;
  24 + }
  25 +
  26 + /**
  27 + * Get the validation rules that apply to the request.
  28 + *
  29 + * @return array
  30 + */
  31 + public function rules()
  32 + {
  33 + return [
  34 + 'project_id' => 'required',
  35 + 'title' => 'required|string',
  36 + 'content' => 'required|string',
  37 + ];
  38 + }
  39 +}
  1 +<?php
  2 +/**
  3 + * @remark :
  4 + * @name :GeoWritingsTaskRequest.php
  5 + * @author :lyh
  6 + * @method :post
  7 + * @time :2025/10/25 14:21
  8 + */
  9 +
  10 +namespace App\Http\Requests\Aside\Geo;
  11 +
  12 +use Illuminate\Foundation\Http\FormRequest;
  13 +
  14 +class GeoWritingsTaskRequest extends FormRequest
  15 +{
  16 + /**
  17 + * Determine if the user is authorized to make this request.
  18 + *
  19 + * @return bool
  20 + */
  21 + public function authorize()
  22 + {
  23 + return true;
  24 + }
  25 +
  26 + /**
  27 + * Get the validation rules that apply to the request.
  28 + *
  29 + * @return array
  30 + */
  31 + public function rules()
  32 + {
  33 + return [
  34 + 'project_id' => 'required',
  35 + 'company' => 'required|string',
  36 + 'brand' => 'required|string',
  37 + 'keyword' => 'required|string',
  38 + 'prefix' => 'required|string',
  39 + 'suffix' => 'required|string',
  40 + 'event_title' => 'required|string',
  41 + 'event_content' => 'required|string',
  42 + 'title' => 'required|string|max:120',
  43 + 'description' => 'required|string',
  44 + 'footer' => 'required|string',
  45 + 'img' => 'required|string',
  46 + 'ai_model' => 'required|string',
  47 + ];
  48 + }
  49 +}
@@ -84,7 +84,7 @@ class RouteMap extends Base @@ -84,7 +84,7 @@ class RouteMap extends Base
84 } 84 }
85 $length = strlen($sign); 85 $length = strlen($sign);
86 if($length > $route_len){ 86 if($length > $route_len){
87 - $sign = trim(mb_substr($sign, 0, $route_len, 'UTF-8'),'-'); 87 + $sign = truncate_text($sign,$route_len);
88 } 88 }
89 $i=1;//路由重复时拼接 89 $i=1;//路由重复时拼接
90 $route = $sign.$suffix; 90 $route = $sign.$suffix;
@@ -509,6 +509,14 @@ class SyncSubmitTaskService @@ -509,6 +509,14 @@ class SyncSubmitTaskService
509 throw new InquiryFilterException( '被刷数据'); 509 throw new InquiryFilterException( '被刷数据');
510 } 510 }
511 511
  512 + //3373江苏石川岛丰东真空 ip荷兰 name >8 纯字母不含空格
  513 + if($project_id == 3373 && in_array($data['country']??'', ['荷兰', '俄罗斯'])
  514 + && strlen($data['data']['name']??"") >= 8
  515 + && preg_match('/^[a-zA-Z]+$/', $data['data']['name']??'')
  516 + ){
  517 + throw new InquiryFilterException( '被刷数据');
  518 + }
  519 +
512 //数据都是空的 520 //数据都是空的
513 $is_all_empty = true; 521 $is_all_empty = true;
514 foreach ($data['data'] as $item){ 522 foreach ($data['data'] as $item){
@@ -110,5 +110,10 @@ Route::prefix('ticket_upload')->group(function () { @@ -110,5 +110,10 @@ Route::prefix('ticket_upload')->group(function () {
110 //geo设置 110 //geo设置
111 Route::prefix('geo')->group(function () { 111 Route::prefix('geo')->group(function () {
112 Route::any('/getConfirm', [\App\Http\Controllers\Api\GeoController::class, 'getConfirm'])->name('geo.getConfirm'); 112 Route::any('/getConfirm', [\App\Http\Controllers\Api\GeoController::class, 'getConfirm'])->name('geo.getConfirm');
  113 + Route::any('/getWritingsList', [\App\Http\Controllers\Api\GeoController::class, 'getWritingsList'])->name('geo.getWritingsList');//确认文章数据
  114 + Route::any('/getWritingsDetail', [\App\Http\Controllers\Api\GeoController::class, 'getWritingsDetail'])->name('geo.getWritingsDetail');//文章数据详情
  115 + Route::any('/saveConfirm', [\App\Http\Controllers\Api\GeoController::class, 'saveConfirm'])->name('geo.saveConfirm');//保存用户确认信息
  116 + Route::any('/getWritingsList', [\App\Http\Controllers\Api\GeoController::class, 'getWritingsList'])->name('geo.getWritingsList');//文章确认列表
  117 + Route::any('/confirmWritings', [\App\Http\Controllers\Api\GeoController::class, 'confirmWritings'])->name('geo.confirmWritings');//确认文章信息
113 }); 118 });
114 119
@@ -595,6 +595,20 @@ Route::middleware(['aloginauth'])->group(function () { @@ -595,6 +595,20 @@ Route::middleware(['aloginauth'])->group(function () {
595 Route::prefix('confirm')->group(function () { 595 Route::prefix('confirm')->group(function () {
596 Route::any('/saveConfirmContent', [Aside\Geo\GeoConfirmController::class, 'saveConfirmContent'])->name('admin.geo_confirm_saveConfirmContent'); 596 Route::any('/saveConfirmContent', [Aside\Geo\GeoConfirmController::class, 'saveConfirmContent'])->name('admin.geo_confirm_saveConfirmContent');
597 }); 597 });
  598 + //geoai文章任务管理
  599 + Route::prefix('writing_task')->group(function () {
  600 + Route::any('/', [Aside\Geo\GeoWritingTaskController::class, 'lists'])->name('admin.geo_writing_task_lists');
  601 + Route::any('/saveWritingTask', [Aside\Geo\GeoWritingTaskController::class, 'saveWritingTask'])->name('admin.geo_writing_task_saveWritingTask');
  602 + Route::any('/delWritingTask', [Aside\Geo\GeoWritingTaskController::class, 'delWritingTask'])->name('admin.geo_writing_task_delWritingTask');
  603 + Route::any('/sendAiTitle', [Aside\Geo\GeoWritingTaskController::class, 'sendAiTitle'])->name('admin.geo_writing_task_sendAiTitle');
  604 + });
  605 + //geo文章管理
  606 + Route::prefix('writing')->group(function () {
  607 + Route::any('/', [Aside\Geo\GeoWritingsController::class, 'lists'])->name('admin.geo_writing_task');
  608 + Route::any('/saveWriting', [Aside\Geo\GeoWritingsController::class, 'saveWriting'])->name('admin.geo_writing_saveWriting');
  609 + Route::any('/delWriting', [Aside\Geo\GeoWritingsController::class, 'delWriting'])->name('admin.geo_writing_delWriting');
  610 + Route::any('/sendWechatMessage', [Aside\Geo\GeoWritingsController::class, 'sendWechatMessage'])->name('admin.geo_writing_sendWechatMessage');
  611 + });
598 }); 612 });
599 // 任务相关 613 // 任务相关
600 Route::prefix('task')->group(function () { 614 Route::prefix('task')->group(function () {