Files
full/module/base/cms/internal/models/query.go

390 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package models 提供CMS数据模型和数据库操作
// 包含文章、分类、标签、评论等实体的数据结构和CRUD操作
package models
import (
"fmt"
"bsm/full/module/base/cms/internal/impl"
pb "bsm/full/module/base/cms/pb"
"git.apinb.com/bsm-sdk/core/errcode"
"git.apinb.com/bsm-sdk/core/types"
"git.apinb.com/bsm-sdk/core/utils"
"gorm.io/gorm"
)
// 数据库表名常量
const (
postTable = "cms_post" // 文章表
accessoryTable = "cms_accessory" // 附件表
postRelateCategoryTable = "cms_relate" // 关联表
)
// InitData 初始化基础数据
// 创建系统必需的默认数据,如根分类等
func InitData() {
var cnt int64 = 0
// 检查是否存在根分类,如果不存在则创建
err := impl.DBService.Model(&CmsCategory{}).Where("identity=?", "_RootCategory").Count(&cnt).Error
if cnt == 0 || err != nil {
data := &CmsCategory{
Title: "根目录",
ParentId: 0, // 0表示顶级分类
Std_Identity: types.Std_Identity{Identity: "_RootCategory"},
}
impl.DBService.Create(data)
}
}
// AddPost 添加文章及其关联数据
// 使用事务确保数据一致性,同时创建文章、分类关联、标签关联和附件信息
// 参数:
// - post: 文章数据模型
// - accessory: 附件数据列表
// - category: 分类标识列表
// - tags: 标签标识列表
//
// 返回:
// - error: 错误信息
func AddPost(post *CmsPost, accessory []*pb.AccessoryItem, category, tags []string) (err error) {
var (
accessoryPath = make([]CmsAccessory, 0) // 文章附件数据
categoryData = make([]CmsRelateCategory, 0) // 文章分类关联数据
TagsData = make([]CmsRelateTags, 0) // 文章标签关联数据
)
// 构建分类关联数据
for _, va := range category {
categoryData = append(categoryData, CmsRelateCategory{
Identity: utils.UUID(),
PostIdentity: post.Identity,
CategoryIdentity: va,
})
}
// 构建标签关联数据
for _, val := range tags {
TagsData = append(TagsData, CmsRelateTags{
Identity: utils.ULID(),
PostIdentity: post.Identity,
TagsIdentity: val,
})
}
// 使用事务确保数据一致性
return impl.DBService.Transaction(func(tx *gorm.DB) error {
// 创建文章记录
if err = tx.Create(post).Error; err != nil {
return err
}
// 创建附件关联记录
if len(accessory) != 0 {
for _, v := range accessory {
accessoryPath = append(accessoryPath, CmsAccessory{
Std_Identity: types.Std_Identity{Identity: utils.UUID()},
PostId: post.ID,
PostIdentity: post.Identity,
FilePath: v.FilePath,
Title: v.Title,
})
}
if err := tx.Create(&accessoryPath).Error; err != nil {
return err
}
}
// 创建分类关联记录
if len(category) != 0 {
if err := tx.Create(&categoryData).Error; err != nil {
return err
}
}
// 创建标签关联记录
if len(tags) != 0 {
if err := tx.Create(&TagsData).Error; err != nil {
return err
}
}
return nil
})
}
// PostList 文章列表
func PostList(page, size int64, categoryIdentity, keyword string, userType int64) (list []*CmsPost, cnt int64, err error) {
tx := impl.DBService.Debug().Model(&CmsPost{})
if categoryIdentity != "" {
tx = tx.Joins("left join cms_relate_category crc on crc.post_identity = cms_post.identity ")
tx = tx.Where("crc.category_identity = ?", categoryIdentity)
}
if keyword != "" {
tx = tx.Where("cms_post.title like ?", "%"+keyword+"%")
}
if userType != 0 {
tx = tx.Where("cms_post.types = ?", userType)
}
if err = tx.Count(&cnt).Order("cms_post.created_at desc").Limit(int(size)).Offset(int((page - 1) * size)).Error; err != nil {
return nil, 0, errcode.ErrDB
}
err = tx.Preload("Accessories").Preload("Categories.Category").Preload("Tags.Tags").Find(&list).Error
return
}
// ModifyPost 修改文章
func ModifyPost(identity string, post *CmsPost, accessory, category, tags []string) (err error) {
var (
accessoryPath = make([]CmsAccessory, 0)
categoryData = make([]CmsRelateCategory, 0)
tagsData = make([]CmsRelateTags, 0)
)
for _, v := range category {
categoryData = append(categoryData, CmsRelateCategory{
Identity: utils.UUID(),
PostIdentity: identity,
CategoryIdentity: v,
})
}
for _, val := range tags {
tagsData = append(tagsData, CmsRelateTags{
Identity: utils.ULID(),
PostIdentity: identity,
TagsIdentity: val,
})
}
for _, v := range accessory {
accessoryPath = append(accessoryPath, CmsAccessory{
Std_Identity: types.Std_Identity{Identity: utils.UUID()},
PostId: post.ID,
PostIdentity: identity,
FilePath: v,
})
}
return impl.DBService.Transaction(func(tx *gorm.DB) error {
if err = tx.Where("identity = ?", identity).Updates(post).Error; err != nil {
return err
}
// 删除旧的附件、分类和标签关联
if err := tx.Where("post_identity = ?", identity).Delete(&CmsAccessory{}).Error; err != nil {
return err
}
if err := tx.Where("post_identity = ?", identity).Delete(&CmsRelateCategory{}).Error; err != nil {
return err
}
if err := tx.Where("post_identity = ?", identity).Delete(&CmsRelateTags{}).Error; err != nil {
return err
}
// 创建新的分类关联
if len(category) != 0 {
if err := tx.Create(&categoryData).Error; err != nil {
return err
}
}
// 创建新的标签关联
if len(tags) != 0 {
if err := tx.Create(&tagsData).Error; err != nil {
return err
}
}
// 创建新的附件关联
if len(accessory) != 0 {
if err := tx.Create(&accessoryPath).Error; err != nil {
return err
}
}
return nil
})
}
// DeletePost 删除文章
func DeletePost(identity, authorIdentity string) (err error) {
return impl.DBService.Transaction(func(tx *gorm.DB) error {
if err = tx.Where("identity = ?", identity).Delete(&CmsPost{}).Error; err != nil {
return err
}
if err = tx.Where("post_identity = ?", identity).Delete(&CmsRelateCategory{}).Error; err != nil {
return err
}
if err = tx.Where("post_identity = ?", identity).Delete(&CmsRelateTags{}).Error; err != nil {
return err
}
if err = tx.Where("post_identity = ?", identity).Delete(&CmsAccessory{}).Error; err != nil {
return err
}
return nil
})
}
// GetPost 根据指定字段获取文章详情
// 查询成功后会更新文章的点击量
// 参数:
// - key: 查询字段名(如"identity"、"key"等)
// - val: 查询字段值
//
// 返回:
// - *CmsPost: 文章详情
// - error: 错误信息
func GetPost(key, val string) (*CmsPost, error) {
var post = &CmsPost{}
// 使用事务确保查询和更新操作的原子性
return post, impl.DBService.Transaction(func(tx *gorm.DB) error {
// 查询文章详情,预加载关联数据
if err := tx.Model(&CmsPost{}).Preload("Accessories").Preload("Categories").Preload("Tags").
Where(key+" = ?", val).First(post).Error; err != nil {
return err
}
// 更新文章点击量,只有在查询成功后才更新
if err := tx.Model(&CmsPost{}).Where(key+" = ?", val).
UpdateColumn("hits", gorm.Expr("hits + 1")).Error; err != nil {
return err
}
return nil
})
}
// IncrOrDescPostField 增加或减少文章字段值
// 用于更新文章的点赞、踩赞、评论等计数字段
// 参数:
// - identity: 文章唯一标识
// - column: 要更新的字段名
// - desc: true表示减少false表示增加
//
// 返回:
// - error: 错误信息
func IncrOrDescPostField(identity, column string, desc bool) (err error) {
expr := "%s + ?"
if desc {
expr = "%s - ?"
}
if err := impl.DBService.Model(&CmsPost{}).Where("identity = ?", identity).UpdateColumn(column, gorm.Expr(fmt.Sprintf(expr, column), 1)).Error; err != nil {
return err
}
return nil
}
func AddComment(comment *CmsComment, authorIdentity string) (err error) {
err = impl.DBService.Transaction(func(tx *gorm.DB) error {
if err := tx.Create(comment).Error; err != nil {
return err
}
// 添加评论,更新文章评论量
err := tx.Model(&CmsPost{}).Where("identity = ?", comment.PostIdentity).UpdateColumn("comment_hits", gorm.Expr("comment_hits + ?", 1)).Error
if err != nil {
return err
}
if comment.ParentId != 0 {
// 更新被评论的那条评论的计数
err = tx.Model(&CmsComment{}).Where("id = ?", comment.ParentId).UpdateColumn("comment_hits", gorm.Expr("comment_hits + ?", 1)).Error
if err != nil {
return err
}
}
return nil
})
return
}
func ModifyComment(comment *CmsComment) (err error) {
return impl.DBService.Where("identity = ?", comment.Identity).Updates(comment).Error
}
func DeleteComment(identity string) (err error) {
// get comment
comment := new(CmsComment)
err = impl.DBService.Where("identity = ?", identity).First(comment).Error
if err != nil {
return err
}
err = impl.DBService.Transaction(func(tx *gorm.DB) error {
// 删除评论,更新文章评论量
if err := tx.Where("identity = ?", identity).Delete(&CmsComment{}).Error; err != nil {
return err
}
if err := tx.Model(&CmsPost{}).Where("identity = ?", comment.PostIdentity).
UpdateColumn("comment_hits", gorm.Expr("comment_hits - ?", 1)).Error; err != nil {
return err
}
if comment.ParentId != 0 {
// 更新被评论的那条评论的计数
if err := tx.Model(&CmsComment{}).Where("id = ?", comment.ParentId).
UpdateColumn("comment_hits", gorm.Expr("comment_hits - ?", 1)).Error; err != nil {
return err
}
}
// 删除子级评论
err = tx.Where("parent_id = ?", comment.ID).Delete(&CmsComment{}).Error
if err != nil {
return err
}
return nil
})
return
}
// IncrOrDescCommentField 增加或减少评论字段值
// 用于更新评论的点赞、踩赞等计数字段
// 参数:
// - identity: 评论唯一标识
// - column: 要更新的字段名
// - desc: true表示减少false表示增加
//
// 返回:
// - error: 错误信息
//
// TODO: 记录点赞对象避免重复点赞
func IncrOrDescCommentField(identity, column string, desc bool) (err error) {
expr := "%s + ?"
if desc {
expr = "%s - ?"
}
if err = impl.DBService.Model(&CmsComment{}).Where("identity = ?", identity).UpdateColumn(column, gorm.Expr(fmt.Sprintf(expr, column), 1)).Error; err != nil {
return err
}
return nil
}
// CategoryList 文章分类列表
func CategoryList() (list []CmsCategory, cnt int64, err error) {
result := impl.DBService.Preload("Children").Find(&list)
if result.Error != nil {
err = result.Error
return
}
cnt = result.RowsAffected
return
}
// DeleteCategory 删除分类
func DeleteCategory(identity string) (err error) {
var (
cnt int64 = 0
category CmsCategory
)
err = impl.DBService.Model(&CmsCategory{}).Where("identity = ?", identity).Find(&category).Error
if err != nil {
return err
}
impl.DBService.Model(&CmsCategory{}).Where("parent_id = ?", category.ID).Count(&cnt)
if cnt != 0 {
return errcode.NewError(500, "ErrCategoryHasSubcategories")
}
err = impl.DBService.Where("identity = ?", identity).Delete(&CmsCategory{}).Error
if err != nil {
return err
}
return
}