feat: support full community post editing
This commit is contained in:
@@ -21,10 +21,10 @@ class CommunityPostController extends BaseAdminController
|
||||
return $this->data($result);
|
||||
}
|
||||
|
||||
public function editContent()
|
||||
public function edit()
|
||||
{
|
||||
$params = (new CommunityPostValidate())->post()->goCheck('editContent');
|
||||
$result = CommunityPostLogic::editContent($params);
|
||||
$params = (new CommunityPostValidate())->post()->goCheck('edit');
|
||||
$result = CommunityPostLogic::edit($params);
|
||||
if (true === $result) {
|
||||
return $this->success('保存成功', [], 1, 1);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace app\adminapi\logic\community;
|
||||
use app\common\logic\BaseLogic;
|
||||
use app\common\model\community\CommunityCategory;
|
||||
use app\common\model\community\CommunityPost;
|
||||
use app\common\model\community\CommunityTag;
|
||||
use app\common\model\user\User;
|
||||
use app\common\service\ai\KbSyncService;
|
||||
use think\facade\Db;
|
||||
@@ -26,6 +27,19 @@ class CommunityPostLogic extends BaseLogic
|
||||
$post['category_name'] = (int) ($post['category_id'] ?? 0) > 0
|
||||
? (string) CommunityCategory::where('id', $post['category_id'])->value('name')
|
||||
: '';
|
||||
$post['tag_ids'] = array_map('intval', Db::name('community_post_tag')
|
||||
->where('post_id', $params['id'])
|
||||
->column('tag_id'));
|
||||
if (is_array($post['ext'] ?? null)) {
|
||||
$post['ext'] = json_encode($post['ext'], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
|
||||
} elseif (is_string($post['ext'] ?? null) && trim($post['ext']) !== '') {
|
||||
$decodedExt = json_decode($post['ext'], true);
|
||||
$post['ext'] = json_last_error() === JSON_ERROR_NONE
|
||||
? json_encode($decodedExt, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)
|
||||
: $post['ext'];
|
||||
} else {
|
||||
$post['ext'] = '';
|
||||
}
|
||||
return $post;
|
||||
}
|
||||
|
||||
@@ -50,7 +64,7 @@ class CommunityPostLogic extends BaseLogic
|
||||
}
|
||||
}
|
||||
|
||||
public static function editContent(array $params): bool
|
||||
public static function edit(array $params): bool
|
||||
{
|
||||
$post = CommunityPost::findOrEmpty($params['id']);
|
||||
if ($post->isEmpty()) {
|
||||
@@ -58,17 +72,79 @@ class CommunityPostLogic extends BaseLogic
|
||||
return false;
|
||||
}
|
||||
|
||||
$oldCategoryId = (int) $post->category_id;
|
||||
$oldTagIds = array_map('intval', Db::name('community_post_tag')
|
||||
->where('post_id', $params['id'])
|
||||
->column('tag_id'));
|
||||
$newCategoryId = (int) $params['category_id'];
|
||||
$newTagIds = array_values(array_unique(array_filter(
|
||||
array_map('intval', $params['tag_ids'] ?? []),
|
||||
static fn (int $tagId): bool => $tagId > 0
|
||||
)));
|
||||
$isPaid = (int) $params['is_paid'] === 1;
|
||||
$extValue = $params['ext'] ?? '';
|
||||
$ext = is_array($extValue)
|
||||
? json_encode($extValue, JSON_UNESCAPED_UNICODE)
|
||||
: trim((string) $extValue);
|
||||
|
||||
Db::startTrans();
|
||||
try {
|
||||
$post->content = (string) $params['content'];
|
||||
$post->save();
|
||||
if ((int) $post->status === 1) {
|
||||
KbSyncService::enqueue('post', 'post', (int) $post->id, 'upsert', 30);
|
||||
$post->save([
|
||||
'origin_id' => trim((string) ($params['origin_id'] ?? '')) ?: null,
|
||||
'user_id' => (int) $params['user_id'],
|
||||
'content' => (string) ($params['content'] ?? ''),
|
||||
'images' => array_values($params['images'] ?? []),
|
||||
'post_type' => (int) $params['post_type'],
|
||||
'category_id' => $newCategoryId,
|
||||
'match_id' => (int) $params['match_id'],
|
||||
'is_paid' => $isPaid ? 1 : 0,
|
||||
'price_points' => $isPaid ? (int) $params['price_points'] : 0,
|
||||
'free_content_len' => $isPaid ? (int) $params['free_content_len'] : 100,
|
||||
'paid_count' => (int) $params['paid_count'],
|
||||
'view_count' => (int) $params['view_count'],
|
||||
'like_count' => (int) $params['like_count'],
|
||||
'comment_count' => (int) $params['comment_count'],
|
||||
'share_count' => (int) $params['share_count'],
|
||||
'ext' => $ext === '' ? null : $ext,
|
||||
'is_top' => (int) $params['is_top'],
|
||||
'is_hot' => (int) $params['is_hot'],
|
||||
'is_recommend' => (int) $params['is_recommend'],
|
||||
'is_topic' => (int) $params['is_topic'],
|
||||
'sort' => (int) $params['sort'],
|
||||
'status' => (int) $params['status'],
|
||||
'create_time' => strtotime((string) $params['create_time']),
|
||||
'update_time' => time(),
|
||||
]);
|
||||
|
||||
Db::name('community_post_tag')->where('post_id', $post->id)->delete();
|
||||
if ($newTagIds) {
|
||||
Db::name('community_post_tag')->insertAll(array_map(
|
||||
static fn (int $tagId): array => [
|
||||
'post_id' => (int) $post->id,
|
||||
'tag_id' => $tagId,
|
||||
],
|
||||
$newTagIds
|
||||
));
|
||||
}
|
||||
return true;
|
||||
|
||||
self::refreshCategoryCount($oldCategoryId);
|
||||
self::refreshCategoryCount($newCategoryId);
|
||||
self::refreshTagCounts(array_merge($oldTagIds, $newTagIds));
|
||||
Db::commit();
|
||||
} catch (\Exception $e) {
|
||||
Db::rollback();
|
||||
self::setError($e->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
KbSyncService::enqueue(
|
||||
'post',
|
||||
'post',
|
||||
(int) $post->id,
|
||||
(int) $post->status === 1 ? 'upsert' : 'delete',
|
||||
30
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function setTop(array $params): bool
|
||||
@@ -188,4 +264,24 @@ class CommunityPostLogic extends BaseLogic
|
||||
'update_time' => time(),
|
||||
]);
|
||||
}
|
||||
|
||||
private static function refreshTagCounts(array $tagIds): void
|
||||
{
|
||||
$tagIds = array_values(array_unique(array_filter(
|
||||
array_map('intval', $tagIds),
|
||||
static fn (int $tagId): bool => $tagId > 0
|
||||
)));
|
||||
foreach ($tagIds as $tagId) {
|
||||
$postCount = Db::name('community_post_tag')
|
||||
->alias('post_tag')
|
||||
->join('community_post post', 'post.id = post_tag.post_id')
|
||||
->where('post_tag.tag_id', $tagId)
|
||||
->whereNull('post.delete_time')
|
||||
->count();
|
||||
CommunityTag::where('id', $tagId)->update([
|
||||
'post_count' => $postCount,
|
||||
'update_time' => time(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,6 @@ class CommunityTagLogic extends BaseLogic
|
||||
|
||||
public static function all(): array
|
||||
{
|
||||
return CommunityTag::where('status', 1)->order('sort', 'desc')->order('id', 'desc')->select()->toArray();
|
||||
return CommunityTag::order('sort', 'desc')->order('id', 'desc')->select()->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,30 @@ namespace app\adminapi\validate\community;
|
||||
use app\common\validate\BaseValidate;
|
||||
use app\common\model\community\CommunityCategory;
|
||||
use app\common\model\community\CommunityPost;
|
||||
use app\common\model\community\CommunityTag;
|
||||
use app\common\model\user\User;
|
||||
use think\facade\Db;
|
||||
|
||||
class CommunityPostValidate extends BaseValidate
|
||||
{
|
||||
protected $rule = [
|
||||
'id' => 'require|checkPost',
|
||||
'origin_id' => 'max:100|checkOriginId',
|
||||
'user_id' => 'require|integer|gt:0|checkUser|checkBody',
|
||||
'content' => 'max:16000',
|
||||
'images' => 'array|checkImages',
|
||||
'post_type' => 'require|in:0,1,2',
|
||||
'match_id' => 'require|integer|egt:0|checkMatch',
|
||||
'tag_ids' => 'array|checkTags',
|
||||
'is_paid' => 'require|in:0,1|checkPayment',
|
||||
'price_points' => 'require|integer|egt:0|elt:10000',
|
||||
'free_content_len' => 'require|integer|egt:0|elt:501|checkFreeContentLen',
|
||||
'paid_count' => 'require|integer|egt:0|elt:4294967296',
|
||||
'view_count' => 'require|integer|egt:0|elt:4294967296',
|
||||
'like_count' => 'require|integer|egt:0|elt:4294967296',
|
||||
'comment_count' => 'require|integer|egt:0|elt:4294967296',
|
||||
'share_count' => 'require|integer|egt:0|elt:4294967296',
|
||||
'ext' => 'checkExt',
|
||||
'status' => 'require|in:0,1,2',
|
||||
'is_top' => 'require|in:0,1',
|
||||
'is_hot' => 'require|in:0,1',
|
||||
@@ -17,14 +36,22 @@ class CommunityPostValidate extends BaseValidate
|
||||
'sort' => 'require|integer|egt:0|elt:1000000',
|
||||
'is_topic' => 'require|in:0,1',
|
||||
'category_id' => 'require|integer|egt:0|checkCategory',
|
||||
'content' => 'require|max:16000',
|
||||
'create_time' => 'require|checkDateTime',
|
||||
];
|
||||
|
||||
protected $message = [
|
||||
'id.require' => '帖子id不能为空',
|
||||
'status.require' => '状态不能为空',
|
||||
'content.require' => '帖子内容不能为空',
|
||||
'content.max' => '帖子内容不能超过16000个字符',
|
||||
'origin_id.max' => '来源标识不能超过100个字符',
|
||||
'user_id.require' => '用户ID不能为空',
|
||||
'images.array' => '帖子图片格式错误',
|
||||
'post_type.in' => '帖子类型错误',
|
||||
'match_id.egt' => '赛事ID不能小于0',
|
||||
'tag_ids.array' => '帖子标签格式错误',
|
||||
'price_points.elt' => '积分价格范围为0~9999',
|
||||
'free_content_len.elt' => '免费预览字数不能超过500',
|
||||
'create_time.require' => '发布时间不能为空',
|
||||
];
|
||||
|
||||
public function sceneDetail()
|
||||
@@ -42,9 +69,15 @@ class CommunityPostValidate extends BaseValidate
|
||||
return $this->only(['id', 'status']);
|
||||
}
|
||||
|
||||
public function sceneEditContent()
|
||||
public function sceneEdit()
|
||||
{
|
||||
return $this->only(['id', 'content']);
|
||||
return $this->only([
|
||||
'id', 'origin_id', 'user_id', 'content', 'images', 'post_type', 'category_id',
|
||||
'match_id', 'tag_ids', 'is_paid', 'price_points', 'free_content_len',
|
||||
'paid_count', 'view_count', 'like_count', 'comment_count', 'share_count',
|
||||
'ext', 'is_top', 'is_hot', 'is_recommend', 'is_topic', 'sort', 'status',
|
||||
'create_time',
|
||||
]);
|
||||
}
|
||||
|
||||
public function sceneTop()
|
||||
@@ -86,14 +119,111 @@ class CommunityPostValidate extends BaseValidate
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkCategory($value)
|
||||
public function checkOriginId($value, $rule, $data)
|
||||
{
|
||||
$originId = trim((string) $value);
|
||||
if ($originId === '') {
|
||||
return true;
|
||||
}
|
||||
$exists = Db::name('community_post')
|
||||
->where('origin_id', $originId)
|
||||
->where('id', '<>', (int) ($data['id'] ?? 0))
|
||||
->count();
|
||||
return $exists > 0 ? '来源标识已存在' : true;
|
||||
}
|
||||
|
||||
public function checkUser($value)
|
||||
{
|
||||
return User::where('id', $value)->count() > 0 ? true : '用户不存在';
|
||||
}
|
||||
|
||||
public function checkBody($value, $rule, $data)
|
||||
{
|
||||
if (trim((string) ($data['content'] ?? '')) === '' && empty($data['images'])) {
|
||||
return '帖子内容和图片不能同时为空';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkImages($value)
|
||||
{
|
||||
if (count($value) > 18) {
|
||||
return '帖子图片最多18张';
|
||||
}
|
||||
foreach ($value as $image) {
|
||||
if (!is_string($image) || trim($image) === '') {
|
||||
return '帖子图片地址格式错误';
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkMatch($value)
|
||||
{
|
||||
if ((int) $value === 0) {
|
||||
return true;
|
||||
}
|
||||
$category = CommunityCategory::where('id', $value)->where('status', 1)->findOrEmpty();
|
||||
return Db::name('match')->where('id', $value)->count() > 0 ? true : '关联赛事不存在';
|
||||
}
|
||||
|
||||
public function checkTags($value)
|
||||
{
|
||||
$tagIds = array_values(array_unique(array_map('intval', $value)));
|
||||
if (count($tagIds) > 3) {
|
||||
return '帖子标签最多选择3个';
|
||||
}
|
||||
if (!$tagIds) {
|
||||
return true;
|
||||
}
|
||||
return CommunityTag::whereIn('id', $tagIds)->count() === count($tagIds)
|
||||
? true
|
||||
: '帖子标签不存在';
|
||||
}
|
||||
|
||||
public function checkPayment($value, $rule, $data)
|
||||
{
|
||||
if ((int) $value === 1 && (int) ($data['price_points'] ?? 0) <= 0) {
|
||||
return '付费帖子必须设置积分价格';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkFreeContentLen($value, $rule, $data)
|
||||
{
|
||||
if ((int) ($data['is_paid'] ?? 0) === 1 && (int) $value < 20) {
|
||||
return '付费帖子免费预览字数不能少于20';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function checkExt($value)
|
||||
{
|
||||
if (is_array($value) || trim((string) $value) === '') {
|
||||
return true;
|
||||
}
|
||||
json_decode((string) $value, true);
|
||||
return json_last_error() === JSON_ERROR_NONE ? true : '扩展数据必须是有效的JSON';
|
||||
}
|
||||
|
||||
public function checkDateTime($value)
|
||||
{
|
||||
return strtotime((string) $value) !== false ? true : '发布时间格式错误';
|
||||
}
|
||||
|
||||
public function checkCategory($value, $rule, $data)
|
||||
{
|
||||
if ((int) $value === 0) {
|
||||
return true;
|
||||
}
|
||||
$category = CommunityCategory::where('id', $value)->findOrEmpty();
|
||||
if ($category->isEmpty()) {
|
||||
return '帖子分类不存在或已禁用';
|
||||
return '帖子分类不存在';
|
||||
}
|
||||
if ((int) $category->status !== 1) {
|
||||
$currentCategoryId = (int) CommunityPost::where('id', $data['id'] ?? 0)->value('category_id');
|
||||
if ($currentCategoryId !== (int) $value) {
|
||||
return '帖子分类已禁用';
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user