作者 zhl

geo改版

<?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(Request $request)
{
try {
$token = trim($request->input('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)
{}
}
\ No newline at end of file
... ...
<?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(Request $request)
{
$this->request->validate([
'project_id' => 'required',
], [
'project_id.required' => '项目ID不能为空',
]);
$project_geo_conf = Project::select('title', 'version', 'geo_status', 'geo_qualify_num')->where(['project_id' => $this->param['project_id']])->first();
$geo_conf = GeoConf::where(['project_id' => $this->param['project_id']])->first();
$geo_manage_list = GeoConf::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(Request $request)
{
$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(Request $request)
{
$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)
{}
}
\ No newline at end of file
... ...
<?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 static 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;
}
}
\ No newline at end of file
... ...
<?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();
$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;
}
}
\ No newline at end of file
... ...
<?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;
}
}
\ No newline at end of file
... ...
... ... @@ -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
... ...