diff --git a/admin/src/api/community.ts b/admin/src/api/community.ts
index 61995b4..6a1346f 100644
--- a/admin/src/api/community.ts
+++ b/admin/src/api/community.ts
@@ -10,9 +10,9 @@ export function communityPostDetail(params: any) {
return request.get({ url: '/community.communityPost/detail', params })
}
-// 编辑帖子内容
-export function communityPostEditContent(params: any) {
- return request.post({ url: '/community.communityPost/editContent', params })
+// 编辑帖子
+export function communityPostEdit(params: any) {
+ return request.post({ url: '/community.communityPost/edit', params })
}
// 帖子审核状态
diff --git a/admin/src/views/community/post/index.vue b/admin/src/views/community/post/index.vue
index 96cceae..015a537 100644
--- a/admin/src/views/community/post/index.vue
+++ b/admin/src/views/community/post/index.vue
@@ -68,6 +68,7 @@
赛事分析
+ 战绩分享
普通
@@ -135,8 +136,8 @@
@click="handleDetail(row.id)">
详情
-
+
编辑
关闭
-
-
-
-
-
-
+
+
+
+ 基础信息
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 正文与素材
+
+
+
+
+
+
+
+ 付费设置
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 统计数据(手动修正)
+
+
+
+
+
+
+
+
+ 展示与状态
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 置顶
+ 推荐
+ 热门
+ 话题
+
+
+
+
+
+ 扩展数据
+
+
+
+
+
取消
-
+
保存
@@ -223,7 +369,7 @@
import {
communityPostLists,
communityPostDetail,
- communityPostEditContent,
+ communityPostEdit,
communityPostStatus,
communityPostSetTop,
communityPostSetHot,
@@ -231,11 +377,13 @@ import {
communityPostSetSort,
communityPostSetTopic,
communityPostSetCategory,
+ communityTagAll,
communityCategoryAll,
communityPostDelete
} from '@/api/community'
import { usePaging } from '@/hooks/usePaging'
import feedback from '@/utils/feedback'
+import type { FormInstance, FormItemRule, FormRules } from 'element-plus'
const queryParams = reactive({
status: '',
@@ -247,6 +395,7 @@ const queryParams = reactive({
})
const categoryList = ref([])
+const tagList = ref([])
const { pager, getLists, resetPage, resetParams } = usePaging({
fetchFun: communityPostLists,
@@ -335,33 +484,167 @@ const handleDetail = async (id: number) => {
}
const showEdit = ref(false)
+const editLoading = ref(false)
const editSubmitLoading = ref(false)
-const editData = reactive({
+const createEditData = () => ({
id: 0,
- content: ''
+ origin_id: '',
+ user_id: 0,
+ content: '',
+ images: [] as string[],
+ post_type: 0,
+ category_id: 0,
+ match_id: 0,
+ tag_ids: [] as number[],
+ is_paid: 0,
+ price_points: 0,
+ free_content_len: 100,
+ paid_count: 0,
+ view_count: 0,
+ like_count: 0,
+ comment_count: 0,
+ share_count: 0,
+ ext: '',
+ is_top: 0,
+ is_hot: 0,
+ is_recommend: 0,
+ is_topic: 0,
+ sort: 0,
+ status: 1,
+ create_time: '',
+ update_time: ''
})
+type EditData = ReturnType
+type CountFieldKey = 'paid_count' | 'view_count' | 'like_count' | 'comment_count' | 'share_count'
-const handleEdit = (post: any) => {
+const editData = reactive(createEditData())
+const editFormRef = ref()
+const countFields: Array<{ key: CountFieldKey; label: string }> = [
+ { key: 'paid_count', label: '购买人数' },
+ { key: 'view_count', label: '浏览数' },
+ { key: 'like_count', label: '点赞数' },
+ { key: 'comment_count', label: '评论数' },
+ { key: 'share_count', label: '分享数' }
+]
+
+const validatePostBody = (_rule: any, _value: any, callback: (error?: Error) => void) => {
+ if (!editData.content.trim() && editData.images.length === 0) {
+ callback(new Error('帖子内容和图片不能同时为空'))
+ return
+ }
+ callback()
+}
+
+const validatePaidPrice = (_rule: any, value: number, callback: (error?: Error) => void) => {
+ if (editData.is_paid === 1 && (!value || value < 1 || value > 9999)) {
+ callback(new Error('付费帖子积分价格范围为1~9999'))
+ return
+ }
+ callback()
+}
+
+const validateExt = (_rule: any, value: string, callback: (error?: Error) => void) => {
+ if (!value.trim()) {
+ callback()
+ return
+ }
+ try {
+ JSON.parse(value)
+ callback()
+ } catch {
+ callback(new Error('请输入合法的 JSON'))
+ }
+}
+
+const nonNegativeRule: FormItemRule[] = [
+ { required: true, type: 'number', min: 0, message: '请输入不小于0的整数' }
+]
+const editRules: FormRules = {
+ user_id: [{ required: true, type: 'number', min: 1, message: '请输入有效的用户ID', trigger: 'blur' }],
+ content: [{ validator: validatePostBody, trigger: 'blur' }],
+ post_type: [{ required: true, type: 'number', message: '请选择帖子类型', trigger: 'change' }],
+ category_id: nonNegativeRule,
+ match_id: nonNegativeRule,
+ tag_ids: [{ type: 'array', max: 3, message: '帖子标签最多选择3个', trigger: 'change' }],
+ price_points: [{ validator: validatePaidPrice, trigger: 'blur' }],
+ free_content_len: [{ required: true, type: 'number', min: 20, max: 500, message: '免费预览字数为20~500' }],
+ paid_count: nonNegativeRule,
+ view_count: nonNegativeRule,
+ like_count: nonNegativeRule,
+ comment_count: nonNegativeRule,
+ share_count: nonNegativeRule,
+ sort: nonNegativeRule,
+ status: [{ required: true, type: 'number', message: '请选择审核状态', trigger: 'change' }],
+ create_time: [{ required: true, message: '请选择发布时间', trigger: 'change' }],
+ ext: [{ validator: validateExt, trigger: 'blur' }]
+}
+
+const normalizeExt = (value: any) => {
+ if (value === null || value === undefined || value === '') return ''
+ if (typeof value === 'string') return value
+ return JSON.stringify(value, null, 2)
+}
+
+const handleEdit = async (id: number) => {
showEdit.value = true
- editData.id = post.id
- editData.content = post.content || ''
+ editLoading.value = true
+ Object.assign(editData, createEditData())
+ try {
+ const res = await communityPostDetail({ id })
+ Object.assign(editData, createEditData(), res, {
+ id: Number(res.id || id),
+ origin_id: String(res.origin_id || ''),
+ user_id: Number(res.user_id || 0),
+ content: String(res.content || ''),
+ images: Array.isArray(res.images) ? res.images : [],
+ post_type: Number(res.post_type || 0),
+ category_id: Number(res.category_id || 0),
+ match_id: Number(res.match_id || 0),
+ tag_ids: Array.isArray(res.tag_ids) ? res.tag_ids.map(Number) : [],
+ is_paid: Number(res.is_paid || 0),
+ ext: normalizeExt(res.ext),
+ price_points: Number(res.is_paid) === 1 ? Number(res.price_points || 0) : 0,
+ free_content_len: Number(res.is_paid) === 1 ? Number(res.free_content_len || 100) : 100,
+ paid_count: Number(res.paid_count || 0),
+ view_count: Number(res.view_count || 0),
+ like_count: Number(res.like_count || 0),
+ comment_count: Number(res.comment_count || 0),
+ share_count: Number(res.share_count || 0),
+ is_top: Number(res.is_top || 0),
+ is_hot: Number(res.is_hot || 0),
+ is_recommend: Number(res.is_recommend || 0),
+ is_topic: Number(res.is_topic || 0),
+ sort: Number(res.sort || 0),
+ status: Number(res.status || 0),
+ create_time: String(res.create_time || ''),
+ update_time: String(res.update_time || '')
+ })
+ } finally {
+ editLoading.value = false
+ }
+}
+
+const handlePaidChange = (value: any) => {
+ if (Number(value) !== 1) {
+ editData.price_points = 0
+ editData.free_content_len = 100
+ }
}
const handleSubmitEdit = async () => {
- if (!editData.content.trim()) {
- feedback.msgError('请输入帖子内容')
- return
- }
+ const valid = await editFormRef.value?.validate().catch(() => false)
+ if (!valid) return
editSubmitLoading.value = true
try {
- await communityPostEditContent({
- id: editData.id,
- content: editData.content
+ await communityPostEdit({
+ ...editData,
+ origin_id: editData.origin_id.trim(),
+ content: editData.content,
+ images: [...editData.images],
+ tag_ids: [...editData.tag_ids],
+ ext: editData.ext.trim()
})
showEdit.value = false
- if (detailData.value.id === editData.id) {
- detailData.value.content = editData.content
- }
getLists()
} finally {
editSubmitLoading.value = false
@@ -377,6 +660,16 @@ const loadCategories = async () => {
}
}
+const loadTags = async () => {
+ try {
+ const tags = await communityTagAll()
+ tagList.value = Array.isArray(tags) ? tags : []
+ } catch {
+ tagList.value = []
+ }
+}
+
loadCategories()
+loadTags()
getLists()
diff --git a/docs/sql/create_community_post_categories.sql b/docs/sql/create_community_post_categories.sql
index eb215f1..2b5420f 100644
--- a/docs/sql/create_community_post_categories.sql
+++ b/docs/sql/create_community_post_categories.sql
@@ -204,7 +204,7 @@ FROM (
SELECT '设置推荐' AS `name`, 'community.communityPost/setRecommend' AS `perms`
UNION ALL SELECT '设置话题', 'community.communityPost/setTopic'
UNION ALL SELECT '设置分类', 'community.communityPost/setCategory'
- UNION ALL SELECT '编辑内容', 'community.communityPost/editContent'
+ UNION ALL SELECT '编辑帖子', 'community.communityPost/edit'
) permission
WHERE @post_menu_id IS NOT NULL
AND NOT EXISTS (
@@ -224,7 +224,7 @@ WHERE menu.`perms` IN (
'community.communityPost/setRecommend',
'community.communityPost/setTopic',
'community.communityPost/setCategory',
- 'community.communityPost/editContent'
+ 'community.communityPost/edit'
)
AND NOT EXISTS (
SELECT 1
diff --git a/docs/sql/insert_community_post_edit_content_permission.sql b/docs/sql/insert_community_post_edit_content_permission.sql
deleted file mode 100644
index dc0e03e..0000000
--- a/docs/sql/insert_community_post_edit_content_permission.sql
+++ /dev/null
@@ -1,24 +0,0 @@
-SET @post_menu_id = COALESCE(
- (SELECT `id` FROM `la_system_menu` WHERE `perms` = 'community.communityPost/lists' LIMIT 1),
- (SELECT `id` FROM `la_system_menu` WHERE `component` = 'community/post/index' LIMIT 1)
-);
-
-INSERT INTO `la_system_menu`
- (`pid`, `type`, `name`, `icon`, `sort`, `perms`, `paths`, `component`, `selected`, `params`, `is_cache`, `is_show`, `is_disable`, `create_time`, `update_time`)
-SELECT
- @post_menu_id, 'A', '编辑内容', '', 0, 'community.communityPost/editContent', '', '', '', '', 0, 0, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()
-WHERE @post_menu_id IS NOT NULL
- AND NOT EXISTS (
- SELECT 1 FROM `la_system_menu` WHERE `perms` = 'community.communityPost/editContent'
- );
-
-INSERT INTO `la_system_role_menu` (`role_id`, `menu_id`)
-SELECT 1, menu.`id`
-FROM `la_system_menu` menu
-WHERE menu.`perms` = 'community.communityPost/editContent'
- AND NOT EXISTS (
- SELECT 1
- FROM `la_system_role_menu` role_menu
- WHERE role_menu.`role_id` = 1
- AND role_menu.`menu_id` = menu.`id`
- );
diff --git a/docs/sql/upsert_community_post_edit_permission.sql b/docs/sql/upsert_community_post_edit_permission.sql
new file mode 100644
index 0000000..c2a449f
--- /dev/null
+++ b/docs/sql/upsert_community_post_edit_permission.sql
@@ -0,0 +1,71 @@
+SET @post_menu_id = COALESCE(
+ (SELECT `id` FROM `la_system_menu` WHERE `perms` = 'community.communityPost/lists' LIMIT 1),
+ (SELECT `id` FROM `la_system_menu` WHERE `component` = 'community/post/index' LIMIT 1)
+);
+
+SET @old_edit_menu_id = (
+ SELECT `id` FROM `la_system_menu`
+ WHERE `perms` = 'community.communityPost/editContent'
+ LIMIT 1
+);
+
+SET @edit_menu_id = (
+ SELECT `id` FROM `la_system_menu`
+ WHERE `perms` = 'community.communityPost/edit'
+ LIMIT 1
+);
+
+UPDATE `la_system_menu`
+SET `name` = '编辑帖子',
+ `perms` = 'community.communityPost/edit',
+ `update_time` = UNIX_TIMESTAMP()
+WHERE `id` = @old_edit_menu_id
+ AND @edit_menu_id IS NULL;
+
+INSERT INTO `la_system_menu`
+ (`pid`, `type`, `name`, `icon`, `sort`, `perms`, `paths`, `component`, `selected`, `params`, `is_cache`, `is_show`, `is_disable`, `create_time`, `update_time`)
+SELECT
+ @post_menu_id, 'A', '编辑帖子', '', 0, 'community.communityPost/edit', '', '', '', '', 0, 0, 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()
+WHERE @post_menu_id IS NOT NULL
+ AND NOT EXISTS (
+ SELECT 1 FROM `la_system_menu` WHERE `perms` = 'community.communityPost/edit'
+ );
+
+SET @edit_menu_id = (
+ SELECT `id` FROM `la_system_menu`
+ WHERE `perms` = 'community.communityPost/edit'
+ LIMIT 1
+);
+
+INSERT INTO `la_system_role_menu` (`role_id`, `menu_id`)
+SELECT 1, @edit_menu_id
+WHERE @edit_menu_id IS NOT NULL
+ AND NOT EXISTS (
+ SELECT 1
+ FROM `la_system_role_menu`
+ WHERE `role_id` = 1
+ AND `menu_id` = @edit_menu_id
+ );
+
+INSERT INTO `la_system_role_menu` (`role_id`, `menu_id`)
+SELECT old_role_menu.`role_id`, @edit_menu_id
+FROM `la_system_role_menu` old_role_menu
+WHERE old_role_menu.`menu_id` = @old_edit_menu_id
+ AND @old_edit_menu_id IS NOT NULL
+ AND @old_edit_menu_id <> @edit_menu_id
+ AND NOT EXISTS (
+ SELECT 1
+ FROM `la_system_role_menu` current_role_menu
+ WHERE current_role_menu.`role_id` = old_role_menu.`role_id`
+ AND current_role_menu.`menu_id` = @edit_menu_id
+ );
+
+DELETE FROM `la_system_role_menu`
+WHERE `menu_id` = @old_edit_menu_id
+ AND @old_edit_menu_id IS NOT NULL
+ AND @old_edit_menu_id <> @edit_menu_id;
+
+DELETE FROM `la_system_menu`
+WHERE `id` = @old_edit_menu_id
+ AND @old_edit_menu_id IS NOT NULL
+ AND @old_edit_menu_id <> @edit_menu_id;
diff --git a/server/app/adminapi/controller/community/CommunityPostController.php b/server/app/adminapi/controller/community/CommunityPostController.php
index c4d0ddd..6604f08 100644
--- a/server/app/adminapi/controller/community/CommunityPostController.php
+++ b/server/app/adminapi/controller/community/CommunityPostController.php
@@ -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);
}
diff --git a/server/app/adminapi/logic/community/CommunityPostLogic.php b/server/app/adminapi/logic/community/CommunityPostLogic.php
index cbb7759..eb55c00 100644
--- a/server/app/adminapi/logic/community/CommunityPostLogic.php
+++ b/server/app/adminapi/logic/community/CommunityPostLogic.php
@@ -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(),
+ ]);
+ }
+ }
}
diff --git a/server/app/adminapi/logic/community/CommunityTagLogic.php b/server/app/adminapi/logic/community/CommunityTagLogic.php
index bde744a..cfd09b3 100644
--- a/server/app/adminapi/logic/community/CommunityTagLogic.php
+++ b/server/app/adminapi/logic/community/CommunityTagLogic.php
@@ -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();
}
}
diff --git a/server/app/adminapi/validate/community/CommunityPostValidate.php b/server/app/adminapi/validate/community/CommunityPostValidate.php
index 8b5dd38..f9f7dd8 100644
--- a/server/app/adminapi/validate/community/CommunityPostValidate.php
+++ b/server/app/adminapi/validate/community/CommunityPostValidate.php
@@ -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;
}