作者 zhl

geo改版

  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: zhl
  5 + * Date: 2025/10/23
  6 + * Time: 17:29
  7 + */
  8 +namespace App\Http\Controllers\Api;
  9 +
  10 +use App\Models\Geo\GeoConfirm;
  11 +use App\Models\Geo\GeoWritings;
  12 +use App\Models\Project\Project;
  13 +use Illuminate\Http\Request;
  14 +use Illuminate\Support\Facades\Crypt;
  15 +
  16 +/**
  17 + * GEO相关
  18 + * Class GeoController
  19 + * @package App\Http\Controllers\Api
  20 + */
  21 +class GeoController extends BaseController
  22 +{
  23 + /**
  24 + * 获取确认文章列表
  25 + * @param Request $request
  26 + * @return false|string
  27 + */
  28 + public function getWritingsList(Request $request)
  29 + {
  30 + try {
  31 + $token = trim($request->input('token'));
  32 + $param = Crypt::decrypt($token);
  33 + if ($param['send_at'] + 86400 < time()) {}
  34 + $project_id = $param['project_id'];
  35 + } catch (\Exception $e) {
  36 + return $this->error('非法请求');
  37 + }
  38 +
  39 + $project = Project::select('title', 'version')->where(['project_id' => $this->param['project_id']])->first();
  40 + $list = GeoWritings::select(['title', 'status', 'uniqid', 'confirm_at'])->where(['project_id' => $project_id, 'is_del' => GeoWritings::IS_DEL_FALSE])->get();
  41 + $result = [
  42 + 'project' => $project,
  43 + 'list' => $list
  44 + ];
  45 + return $this->success($result);
  46 + }
  47 +
  48 + /**
  49 + * 获取详情
  50 + * @param Request $request
  51 + * @return false|string
  52 + */
  53 + public function getWritingsDetail(Request $request)
  54 + {
  55 + $token = trim($request->input('token'));
  56 + $detail = GeoWritings::select(['title', 'content', 'status'])->where(['uniqid' => $token])->first();
  57 + return $this->success($detail);
  58 + }
  59 +
  60 +
  61 + /**
  62 + * 确认核心文章数据
  63 + * @param Request $request
  64 + * @return false|string
  65 + */
  66 + public function confirmWritings(Request $request)
  67 + {
  68 + $request->validate([
  69 + 'token' => 'required',
  70 + 'title' => 'required|max:120',
  71 + 'content' => 'required|max:5000'
  72 + ], [
  73 + 'token.required' => '非法请求',
  74 + 'title.required' => '标题不能为空',
  75 + 'title.max' => '最大长度不能超过120字符',
  76 + 'content.required' => '内容不能为空',
  77 + 'content.max' => '内容过长保存失败',
  78 + ]);
  79 + $token = trim($request->input('token'));
  80 + $data = GeoWritings::where(['uniqid' => $token])->first();
  81 + if (empty($data))
  82 + return $this->error('非法请求');
  83 + if ($data->status != GeoWritings::STATUS_RUNNING)
  84 + return $this->error('当前文章已确认,不可再次确认');
  85 +
  86 + // FIXME 验证完成,保存数据,计算内容长度,处理内容中的资源, IP 确认时间 状态
  87 + return $data;
  88 + }
  89 +
  90 + /**
  91 + * 获取确认数据
  92 + * @param Request $request
  93 + * @return false|string
  94 + */
  95 + public function getConfirm(Request $request)
  96 + {
  97 + $token = trim($request->input('token'));
  98 + $data = GeoConfirm::where(['uniqid' => $token])->first();
  99 + if (empty($data))
  100 + return $this->error('当前授权已失效');
  101 + $content = explode("\n", $data->content);
  102 + $confirm = explode("\n", $data->confirm);
  103 + $type = $data->type;
  104 + $status = $data->status;
  105 + $result = compact('content', 'confirm', 'type', 'status');
  106 + return $this->success($result);
  107 + }
  108 +
  109 + /**
  110 + * 保存确认数据
  111 + * 验证当前确认数据状态, 不可重复确认
  112 + * @param Request $request
  113 + */
  114 + public function saveConfirm(Request $request)
  115 + {}
  116 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: zhl
  5 + * Date: 2025/10/23
  6 + * Time: 10:23
  7 + */
  8 +namespace App\Http\Controllers\Aside\Geo;
  9 +
  10 +use App\Enums\Common\Code;
  11 +use App\Http\Controllers\Aside\BaseController;
  12 +use App\Models\Geo\GeoConf;
  13 +use App\Models\Geo\GeoConfirm;
  14 +use App\Models\Manage\ManageHr;
  15 +use App\Models\Project\KeywordPrefix;
  16 +use App\Models\Project\Project;
  17 +use App\Models\ProjectAssociation\ProjectAssociation;
  18 +use Illuminate\Http\Request;
  19 +
  20 +/**
  21 + * Class GeoController
  22 + * @package App\Http\Controllers\Aside\Geo
  23 + */
  24 +class GeoController extends BaseController
  25 +{
  26 + /**
  27 + * 获取GEO相关配置
  28 + * @param Request $request
  29 + */
  30 + public function getConfig(Request $request)
  31 + {
  32 + $this->request->validate([
  33 + 'project_id' => 'required',
  34 + ], [
  35 + 'project_id.required' => '项目ID不能为空',
  36 + ]);
  37 +
  38 + $project_geo_conf = Project::select('title', 'version', 'geo_status', 'geo_qualify_num')->where(['project_id' => $this->param['project_id']])->first();
  39 + $geo_conf = GeoConf::where(['project_id' => $this->param['project_id']])->first();
  40 + $geo_manage_list = GeoConf::geoManage();
  41 +
  42 + // geo配置管理员,已经移除管理员列表,补充管理员信息
  43 + if ($geo_conf && $geo_conf->manager_id && empty($geo_manage_list[$geo_conf->manager_id])) {
  44 + $manage = ManageHr::where(['id' => $geo_conf->manager_id])->pluck('name', 'id')->toArray();
  45 + $geo_manage_list = array_merge($geo_manage_list, $manage);
  46 + }
  47 +
  48 + $result = [
  49 + 'project_geo_conf' => $project_geo_conf,
  50 + 'geo_conf' => $geo_conf,
  51 + 'geo_manage_list' => $geo_manage_list,
  52 + 'geo_keyword' => [
  53 + 'prefix' => KeywordPrefix::getKeyword($this->param['project_id'], KeywordPrefix::TYPE_GEO_PREFIX),
  54 + 'suffix' => KeywordPrefix::getKeyword($this->param['project_id'], KeywordPrefix::TYPE_GEO_SUFFIX),
  55 + ],
  56 + ];
  57 + $this->response('success', Code::SUCCESS, $result);
  58 + }
  59 +
  60 + /**
  61 + * 保存GEO配置
  62 + * TODO 单独保存GEO开启状态, 达标数量
  63 + * @param Request $request
  64 + * @throws \App\Exceptions\AsideGlobalException
  65 + */
  66 + public function saveConfig(Request $request)
  67 + {
  68 + $this->request->validate([
  69 + 'project_id' => 'required',
  70 + 'manager_id' => 'nullable|integer',
  71 + 'company' => 'nullable|max:200',
  72 + 'brand' => 'nullable|max:200',
  73 + 'description' => 'nullable|max:500',
  74 + ], [
  75 + 'project_id.required' => '项目ID不能为空',
  76 + 'manager_id.integer' => '管理员参数非法',
  77 + 'company.max' => '公司名称不能超过200个字符',
  78 + 'brand.max' => '品牌名不能超过200个字符',
  79 + 'description.max' => '描述不能超过500个字符',
  80 + ]);
  81 +
  82 + try {
  83 + $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']);
  84 + # FIXME 保存GEO状态 达标数量
  85 + $this->response('success', Code::SUCCESS, $data);
  86 + } catch (\Exception $e) {
  87 + $this->fail('配置保存失败, error:' . $e->getMessage());
  88 + }
  89 + }
  90 +
  91 +
  92 + /**
  93 + * 保存确认数据, 并推送微信群
  94 + * @param Request $request
  95 + * @throws \App\Exceptions\AsideGlobalException
  96 + */
  97 + public function saveConfirmContent(Request $request)
  98 + {
  99 + $this->request->validate([
  100 + 'project_id' => 'required',
  101 + 'type' => 'required|integer',
  102 + 'content' => 'required',
  103 + 'max_num' => 'required',
  104 + ], [
  105 + 'project_id.required' => '项目ID不能为空',
  106 + 'type.required' => '确定数据类型不能为空',
  107 + 'type.integer' => '确定数据类型不正确',
  108 + 'content.required' => '确定数据不能为空',
  109 + 'max_num.required' => '最大确认数量不能为空',
  110 + ]);
  111 +
  112 + try {
  113 + $data = GeoConfirm::saveContent($this->param['project_id'], $this->param['type'], $this->param['content'], $this->param['max_num']);
  114 +
  115 + $friend = ProjectAssociation::where(['project_id' => $this->param['project_id']])->first();
  116 + if (empty($friend))
  117 + $this->fail('项目未绑定微信群, 推送消息失败!');
  118 +
  119 + $data = GeoConfirm::sendConfirmMessage($data->id, $friend->friend_id);
  120 +
  121 + $this->response('success', Code::SUCCESS, $data);
  122 + } catch (\Exception $e) {
  123 + $this->fail('操作失败, error:' . $e->getMessage());
  124 + }
  125 + }
  126 +
  127 + /**
  128 + * OA后台管理员,保存确认数据
  129 + * 客户可以进行确认, OA后台也可以进行确认,以及修改
  130 + * @param Request $request
  131 + */
  132 + public function saveConfirmData(Request $request)
  133 + {}
  134 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: zhl
  5 + * Date: 2025/10/22
  6 + * Time: 17:01
  7 + */
  8 +namespace App\Models\Geo;
  9 +
  10 +use App\Models\Base;
  11 +use App\Models\Manage\ManageHr;
  12 +use Illuminate\Support\Facades\Cache;
  13 +
  14 +/**
  15 + * GEO 相关配置
  16 + * Class GeoConf
  17 + * @package App\Models\Geo
  18 + */
  19 +class GeoConf extends Base
  20 +{
  21 + /**
  22 + * @var string table
  23 + */
  24 + protected $table = 'gl_project_geo_conf';
  25 +
  26 + /**
  27 + * 保存GEO相关配置
  28 + * @param $project_id
  29 + * @param $manager_id
  30 + * @param $company
  31 + * @param $brand
  32 + * @param $description
  33 + * @param $prefix
  34 + * @param $suffix
  35 + * @return GeoConf
  36 + */
  37 + public static function saveConf($project_id, $manager_id, $company, $brand, $description, $prefix, $suffix)
  38 + {
  39 + $data = self::where(compact('project_id'))->first();
  40 + if (empty($data)) {
  41 + $data = new self();
  42 + $data->project_id = $project_id;
  43 + }
  44 + $data->manager_id = $manager_id;
  45 + $data->company = $company;
  46 + $data->brand = $brand;
  47 + $data->description = $description;
  48 + $data->prefix = $prefix;
  49 + $data->suffix = $suffix;
  50 + $data->save();
  51 + return $data;
  52 + }
  53 +
  54 + /**
  55 + * GEO 负责人集合
  56 + * TODO 负责人:优化师 + 陶婵 + 艾媛媛
  57 + * @return array
  58 + */
  59 + public static function geoManage()
  60 + {
  61 + $key = 'geo_manage_list_' . date('Ymd');
  62 + $optimize = Cache::get($key);
  63 + if (empty($optimize)) {
  64 + $optimize = ManageHr::where(['status' => ManageHr::STATUS_ONE, 'entry_position' => 46])->pluck('name', 'id')->toArray();
  65 + $optimize[1] = '陶婵';
  66 + $optimize[875] = '艾媛媛';
  67 + ksort($optimize);
  68 + Cache::put($key, $optimize, 3600);
  69 + }
  70 + return $optimize;
  71 + }
  72 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: zhl
  5 + * Date: 2025/10/22
  6 + * Time: 17:03
  7 + */
  8 +namespace App\Models\Geo;
  9 +
  10 +use App\Models\Base;
  11 +use App\Models\Workchat\MessagePush;
  12 +
  13 +/**
  14 + * GEO 客户确认相关数据
  15 + * Class GeoConfirm
  16 + * @package App\Models\Geo
  17 + */
  18 +class GeoConfirm extends Base
  19 +{
  20 + /**
  21 + * @var string table
  22 + */
  23 + protected $table = 'gl_project_geo_confirm';
  24 +
  25 + /**
  26 + * 客户确认类型
  27 + */
  28 + const TYPE_TITLE = 1;
  29 + const TYPE_KEYWORD = 2;
  30 +
  31 + /**
  32 + * 数据状态
  33 + */
  34 + const STATUS_INIT = 1; # 初始化数据,仅保存完成
  35 + const STATUS_RUNNING = 2; # 已推送客户,等待客户确认
  36 + const STATUS_FINISH = 3; # 客户已确认完成
  37 +
  38 + /**
  39 + * 客户确认数据类型
  40 + * @return array
  41 + */
  42 + public static function typeMapping()
  43 + {
  44 + return [
  45 + self::TYPE_TITLE => '确认标题',
  46 + self::TYPE_KEYWORD => '确认关键词'
  47 + ];
  48 + }
  49 +
  50 + /**
  51 + * 客户确认数据状态
  52 + * @return array
  53 + */
  54 + public static function statusMapping()
  55 + {
  56 + return [
  57 + self::STATUS_INIT => '初始数据',
  58 + self::STATUS_RUNNING => '数据确认中',
  59 + self::STATUS_FINISH => '客户已确认'
  60 + ];
  61 + }
  62 +
  63 + /**
  64 + * @param $project_id
  65 + * @param $type
  66 + * @param $content
  67 + * @param $max_num
  68 + * @return GeoConfirm
  69 + */
  70 + public static function saveContent($project_id, $type, $content, $max_num)
  71 + {
  72 + $data = self::where(compact('project_id', 'type'))->first();
  73 + if (empty($data)) {
  74 + $data = new self();
  75 + $data->project_id = $project_id;
  76 + $data->type = $type;
  77 + }
  78 + $data->content = $content;
  79 + $data->max_num = $max_num;
  80 + $data->save();
  81 + return $data;
  82 + }
  83 +
  84 + /**
  85 + * 保存确认数据
  86 + * @param $project_id
  87 + * @param $type
  88 + * @param $confirm
  89 + * @param $confirm_num
  90 + * @param $confirm_ip
  91 + * @return bool
  92 + */
  93 + public static function saveConfirm($project_id, $type, $confirm, $confirm_num, $confirm_ip)
  94 + {
  95 + $data = self::where(compact('project_id', 'type'))->first();
  96 + if (empty($data))
  97 + return false;
  98 + $data->confirm = $confirm;
  99 + $data->confirm_ip = $confirm_ip;
  100 + $data->confirm_num = $confirm_num;
  101 + $data->confirm_at = now();
  102 + $data->status = self::STATUS_FINISH;
  103 + $data->save();
  104 + return $data;
  105 + }
  106 +
  107 + /**
  108 + * 推送确认消息
  109 + * @param $id
  110 + * @return bool
  111 + */
  112 + public static function sendConfirmMessage($id, $friend_id)
  113 + {
  114 + $data = self::where(compact('id'))->first();
  115 +
  116 + $project_id = $data->project_id;
  117 + $content_type = 'Link';
  118 + $send_time = now();
  119 + $type = MessagePush::TYPE_GEO_CONFIRM;
  120 + $token = uniqid();
  121 + $created_at = $updated_at = now();
  122 +
  123 + $content_array = [
  124 + 'title' => self::typeMapping()[$data->type],
  125 + 'desc' => self::typeMapping()[$data->type],
  126 + 'size' => 0,
  127 + 'thumbSize' => 0,
  128 + 'thumbUrl' => 'https://hub.globalso.com/logocm.png',
  129 + 'url' => 'https://oa.quanqiusou.cn/public-geo-confirm?token=' . $token
  130 + ];
  131 + $content = json_encode($content_array, JSON_UNESCAPED_UNICODE);
  132 + MessagePush::insert(compact('project_id', 'friend_id', 'type', 'content_type', 'content', 'send_time', 'updated_at', 'created_at'));
  133 +
  134 + // 消息推送, 更新数据
  135 + $data->confirm = '';
  136 + $data->send_at = now();
  137 + $data->uniqid = $token;
  138 + $data->status = self::STATUS_RUNNING;
  139 + $data->save();
  140 +
  141 + return $data;
  142 + }
  143 +}
  1 +<?php
  2 +/**
  3 + * Created by PhpStorm.
  4 + * User: zhl
  5 + * Date: 2025/10/22
  6 + * Time: 17:25
  7 + */
  8 +namespace App\Models\Geo;
  9 +
  10 +use App\Models\Base;
  11 +use App\Models\ProjectAssociation\ProjectAssociation;
  12 +use App\Models\Workchat\MessagePush;
  13 +use Illuminate\Support\Facades\Crypt;
  14 +
  15 +/**
  16 + * GEO 文章相关
  17 + * Class GeoWritings
  18 + * @package App\Models\Geo
  19 + */
  20 +class GeoWritings extends Base
  21 +{
  22 + /**
  23 + * @var string $table
  24 + */
  25 + protected $table = 'gl_project_geo_writings';
  26 +
  27 + /**
  28 + * 文章来源类型
  29 + */
  30 + const TYPE_AI_CREATE = 1;
  31 + const TYPE_SUBMIT = 2;
  32 +
  33 + /**
  34 + * 文章状态类型
  35 + */
  36 + const STATUS_INIT = 1; # 文章仅保存完成,未推送给客户
  37 + const STATUS_RUNNING = 2; # 已推送客户,等待客户确认
  38 + const STATUS_FINISH = 3; # 客户已确认完成
  39 + const STATUS_AI_WAIT = 7; # 任务提交成功,等待AI生成
  40 + const STATUS_AI_RUNNING = 8; # AI生成中
  41 +
  42 + const IS_DEL_FALSE = 0;
  43 + const IS_DEL_TRUE = 1;
  44 +
  45 + /**
  46 + * @return array
  47 + */
  48 + public static function typeMapping()
  49 + {
  50 + return [
  51 + self::TYPE_AI_CREATE => 'AI生成文章',
  52 + self::TYPE_SUBMIT => '上传已有文章'
  53 + ];
  54 + }
  55 +
  56 + /**
  57 + * 状态隐私
  58 + * @return array
  59 + */
  60 + public static function statusMapping()
  61 + {
  62 + return [
  63 + self::STATUS_INIT => '已就绪,待推送',
  64 + self::STATUS_RUNNING => '已推送,待确认',
  65 + self::STATUS_FINISH => '已确认',
  66 + self::STATUS_AI_WAIT => '等待生成',
  67 + self::STATUS_AI_RUNNING => '生成中',
  68 + ];
  69 + }
  70 +
  71 + /**
  72 + * 推送确认消息
  73 + * TODO 通过项目ID,时间生成推送token,页面打开后, 回传token解码确定展示项目数据
  74 + * @param $project_id
  75 + * @return bool
  76 + * @throws \Exception
  77 + */
  78 + public static function sendConfirmMessage($project_id)
  79 + {
  80 + $friend = ProjectAssociation::where(['project_id' => $project_id])->first();
  81 + if (empty($friend)) {
  82 + throw new \Exception('项目未绑定微信群');
  83 + }
  84 + $content_type = 'Link';
  85 + $send_time = now();
  86 + $type = MessagePush::TYPE_GEO_CONFIRM;
  87 + $friend_id = $friend->friend_id;
  88 + $created_at = $updated_at = now();
  89 +
  90 + $param = [
  91 + 'project_id' => $project_id,
  92 + 'send_at' => time()
  93 + ];
  94 + $token = Crypt::encrypt($param);
  95 +
  96 + $content_array = [
  97 + 'title' => "确认核心文章",
  98 + 'desc' => '确认核心文章',
  99 + 'size' => 0,
  100 + 'thumbSize' => 0,
  101 + 'thumbUrl' => 'https://hub.globalso.com/logocm.png',
  102 + 'url' => 'https://oa.quanqiusou.cn/public-geo-article-list?token=' . $token
  103 + ];
  104 + $content = json_encode($content_array, JSON_UNESCAPED_UNICODE);
  105 + MessagePush::insert(compact('project_id', 'friend_id', 'type', 'content_type', 'content', 'send_time', 'updated_at', 'created_at'));
  106 + return true;
  107 + }
  108 +
  109 +}
@@ -10,6 +10,7 @@ @@ -10,6 +10,7 @@
10 namespace App\Models\Project; 10 namespace App\Models\Project;
11 11
12 use App\Models\Base; 12 use App\Models\Base;
  13 +use Illuminate\Support\Facades\Cache;
13 14
14 /** 15 /**
15 * @remark :关键字前缀/后缀 16 * @remark :关键字前缀/后缀
@@ -21,4 +22,68 @@ use App\Models\Base; @@ -21,4 +22,68 @@ use App\Models\Base;
21 class KeywordPrefix extends Base 22 class KeywordPrefix extends Base
22 { 23 {
23 protected $table = 'gl_project_keyword_prefix'; 24 protected $table = 'gl_project_keyword_prefix';
  25 +
  26 + /**
  27 + * 前后缀类型
  28 + */
  29 + const TYPE_OPTIMIZE_PREFIX = 1;
  30 + const TYPE_OPTIMIZE_SUFFIX = 2;
  31 + const TYPE_GEO_PREFIX = 3;
  32 + const TYPE_GEO_SUFFIX = 4;
  33 +
  34 + /**
  35 + * 前后缀类型映射
  36 + * @return array
  37 + */
  38 + public static function typeMapping()
  39 + {
  40 + return [
  41 + self::TYPE_OPTIMIZE_PREFIX => '优化关键词前缀',
  42 + self::TYPE_OPTIMIZE_SUFFIX => '优化关键词后缀',
  43 + self::TYPE_GEO_PREFIX => 'GEO前缀',
  44 + self::TYPE_GEO_SUFFIX => 'GEO后缀',
  45 + ];
  46 + }
  47 +
  48 + /**
  49 + * 保存关键词前后缀
  50 + * @param $project_id
  51 + * @param $type
  52 + * @param $keyword
  53 + * @param $remark
  54 + * @return KeywordPrefix
  55 + */
  56 + public static function saveKeyword($project_id, $type, $keyword, $remark)
  57 + {
  58 + $data = self::where(['project_id' => $project_id, 'keyword' => $keyword])->first();
  59 + if (empty($data)) {
  60 + $data = new self();
  61 + $data->project_id = $project_id;
  62 + $data->type = $type;
  63 + $data->keyword = $keyword;
  64 + }
  65 + $data->remark = $remark;
  66 + $data->save();
  67 + Cache::forget('project_keyword_ps_' . $project_id . '_' . $type);
  68 + return $data;
  69 + }
  70 +
  71 + /**
  72 + * 获取关键词前后缀
  73 + * @param $project_id
  74 + * @param $type
  75 + * @return array|mixed
  76 + */
  77 + public static function getKeyword($project_id, $type)
  78 + {
  79 + $key = 'project_keyword_ps_' . $project_id . '_' . $type;
  80 + $list = Cache::get($key);
  81 + if (empty($list)) {
  82 + $list = self::select(['id', 'type', 'keyword', 'remark'])->where(['type' => $type])->whereIn('project_id', [0, $project_id])->orderBy('project_id', 'asc')->get();
  83 + $list = $list->isEmpty() ? [] : $list->toArray();
  84 + if ($list)
  85 + Cache::put($key, $list, 1800);
  86 + }
  87 + return $list;
  88 + }
24 } 89 }
@@ -30,6 +30,7 @@ class MessagePush extends Base @@ -30,6 +30,7 @@ class MessagePush extends Base
30 const TYPE_TICKET = 'Ticket'; 30 const TYPE_TICKET = 'Ticket';
31 const TYPE_DOMAIN = 'domain'; 31 const TYPE_DOMAIN = 'domain';
32 const TYPE_DOMAIN_V5 = 'domain_v5'; 32 const TYPE_DOMAIN_V5 = 'domain_v5';
  33 + const TYPE_GEO_CONFIRM = 'geo_confirm';
33 //设置关联表名 34 //设置关联表名
34 /** 35 /**
35 * @var mixed 36 * @var mixed