实现文章与分组管理
This commit is contained in:
257
web/services/article.go
Normal file
257
web/services/article.go
Normal file
@@ -0,0 +1,257 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"platform/pkg/u"
|
||||
"platform/web/core"
|
||||
m "platform/web/models"
|
||||
q "platform/web/queries"
|
||||
"time"
|
||||
|
||||
"gorm.io/gen/field"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var Article = &articleService{}
|
||||
|
||||
type articleService struct{}
|
||||
|
||||
func (s *articleService) Page(req *PageArticleReq) (result []*m.Article, count int64, err error) {
|
||||
do := q.Article.Where()
|
||||
if req.Keyword != nil && *req.Keyword != "" {
|
||||
do = do.Where(q.Article.Title.Like("%" + *req.Keyword + "%"))
|
||||
}
|
||||
if req.GroupID != nil {
|
||||
do = do.Where(q.Article.GroupID.Eq(*req.GroupID))
|
||||
}
|
||||
if req.Status != nil {
|
||||
do = do.Where(q.Article.Status.Eq(int(*req.Status)))
|
||||
}
|
||||
|
||||
return q.Article.
|
||||
Preload(q.Article.Group).
|
||||
Where(do).
|
||||
Omit(q.Article.Content).
|
||||
Order(q.Article.Sort, q.Article.CreatedAt).
|
||||
FindByPage(req.GetOffset(), req.GetLimit())
|
||||
}
|
||||
|
||||
type PageArticleReq struct {
|
||||
core.PageReq
|
||||
Keyword *string `json:"keyword,omitempty"`
|
||||
GroupID *int32 `json:"group_id,omitempty"`
|
||||
Status *m.ArticleStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
func (s *articleService) GetByAdmin(id int32) (*m.Article, error) {
|
||||
article, err := q.Article.
|
||||
Preload(q.Article.Group).
|
||||
Where(q.Article.ID.Eq(id)).
|
||||
Take()
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, core.NewBizErr("文档不存在")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return article, nil
|
||||
}
|
||||
|
||||
func (s *articleService) Create(data CreateArticleData) error {
|
||||
if err := s.ensureGroupExists(data.GroupID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return q.Article.Create(&m.Article{
|
||||
GroupID: data.GroupID,
|
||||
Title: data.Title,
|
||||
Content: data.Content,
|
||||
Sort: u.Else(data.Sort, 0),
|
||||
Status: u.Else(data.Status, m.ArticleStatusEnabled),
|
||||
})
|
||||
}
|
||||
|
||||
type CreateArticleData struct {
|
||||
GroupID int32 `json:"group_id" validate:"required"`
|
||||
Title string `json:"title" validate:"required"`
|
||||
Content *string `json:"content"`
|
||||
Sort *int32 `json:"sort"`
|
||||
Status *m.ArticleStatus `json:"status"`
|
||||
}
|
||||
|
||||
func (s *articleService) Update(data UpdateArticleData) error {
|
||||
if data.GroupID != nil {
|
||||
if err := s.ensureGroupExists(*data.GroupID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
do := make([]field.AssignExpr, 0)
|
||||
if data.GroupID != nil {
|
||||
do = append(do, q.Article.GroupID.Value(*data.GroupID))
|
||||
}
|
||||
if data.Title != nil {
|
||||
do = append(do, q.Article.Title.Value(*data.Title))
|
||||
}
|
||||
if data.Content != nil {
|
||||
do = append(do, q.Article.Content.Value(*data.Content))
|
||||
}
|
||||
if data.Sort != nil {
|
||||
do = append(do, q.Article.Sort.Value(*data.Sort))
|
||||
}
|
||||
if data.Status != nil {
|
||||
do = append(do, q.Article.Status.Value(int(*data.Status)))
|
||||
}
|
||||
if len(do) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
r, err := q.Article.Where(q.Article.ID.Eq(data.ID)).UpdateSimple(do...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if r.RowsAffected == 0 {
|
||||
return core.NewBizErr("文档状态已过期")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type UpdateArticleData struct {
|
||||
ID int32 `json:"id" validate:"required"`
|
||||
GroupID *int32 `json:"group_id"`
|
||||
Title *string `json:"title"`
|
||||
Content *string `json:"content"`
|
||||
Sort *int32 `json:"sort"`
|
||||
Status *m.ArticleStatus `json:"status"`
|
||||
}
|
||||
|
||||
func (s *articleService) Delete(id int32) error {
|
||||
r, err := q.Article.Where(q.Article.ID.Eq(id)).UpdateColumn(q.Article.DeletedAt, time.Now())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if r.RowsAffected == 0 {
|
||||
return core.NewBizErr("文档状态已过期")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *articleService) Nav() ([]*ArticleNavGroup, error) {
|
||||
groups, err := q.ArticleGroup.
|
||||
Where(q.ArticleGroup.Status.Eq(int(m.ArticleGroupStatusEnabled))).
|
||||
Order(q.ArticleGroup.Sort, q.ArticleGroup.CreatedAt).
|
||||
Find()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(groups) == 0 {
|
||||
return []*ArticleNavGroup{}, nil
|
||||
}
|
||||
|
||||
groupIDs := make([]int32, 0, len(groups))
|
||||
result := make([]*ArticleNavGroup, 0, len(groups))
|
||||
groupMap := make(map[int32]*ArticleNavGroup, len(groups))
|
||||
for _, group := range groups {
|
||||
groupIDs = append(groupIDs, group.ID)
|
||||
item := &ArticleNavGroup{
|
||||
ID: group.ID,
|
||||
Name: group.Name,
|
||||
Code: group.Code,
|
||||
Articles: []*ArticleNavArticle{},
|
||||
}
|
||||
result = append(result, item)
|
||||
groupMap[group.ID] = item
|
||||
}
|
||||
|
||||
articles, err := q.Article.
|
||||
Where(
|
||||
q.Article.GroupID.In(groupIDs...),
|
||||
q.Article.Status.Eq(int(m.ArticleStatusEnabled)),
|
||||
).
|
||||
Omit(q.Article.Content).
|
||||
Order(q.Article.Sort, q.Article.CreatedAt).
|
||||
Find()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, article := range articles {
|
||||
group := groupMap[article.GroupID]
|
||||
if group == nil {
|
||||
continue
|
||||
}
|
||||
group.Articles = append(group.Articles, &ArticleNavArticle{
|
||||
ID: article.ID,
|
||||
Title: article.Title,
|
||||
UpdatedAt: article.UpdatedAt,
|
||||
})
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type ArticleNavGroup struct {
|
||||
ID int32 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
Articles []*ArticleNavArticle `json:"articles"`
|
||||
}
|
||||
|
||||
type ArticleNavArticle struct {
|
||||
ID int32 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func (s *articleService) GetPublic(id int32) (*ArticlePublicDetail, error) {
|
||||
article, err := q.Article.
|
||||
Preload(q.Article.Group).
|
||||
Where(
|
||||
q.Article.ID.Eq(id),
|
||||
q.Article.Status.Eq(int(m.ArticleStatusEnabled)),
|
||||
).
|
||||
Take()
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, core.NewBizErr("文档不存在")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if article.Group == nil || article.Group.Status != m.ArticleGroupStatusEnabled {
|
||||
return nil, core.NewBizErr("文档不存在")
|
||||
}
|
||||
|
||||
return &ArticlePublicDetail{
|
||||
ID: article.ID,
|
||||
Title: article.Title,
|
||||
Content: article.Content,
|
||||
UpdatedAt: article.UpdatedAt,
|
||||
Group: &ArticlePublicGroup{
|
||||
ID: article.Group.ID,
|
||||
Name: article.Group.Name,
|
||||
Code: article.Group.Code,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
type ArticlePublicDetail struct {
|
||||
ID int32 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Content *string `json:"content,omitempty"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Group *ArticlePublicGroup `json:"group"`
|
||||
}
|
||||
|
||||
type ArticlePublicGroup struct {
|
||||
ID int32 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
}
|
||||
|
||||
func (s *articleService) ensureGroupExists(groupID int32) error {
|
||||
_, err := q.ArticleGroup.Where(q.ArticleGroup.ID.Eq(groupID)).Take()
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return core.NewBizErr("文档分组不存在")
|
||||
}
|
||||
return err
|
||||
}
|
||||
128
web/services/article_group.go
Normal file
128
web/services/article_group.go
Normal file
@@ -0,0 +1,128 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"platform/pkg/u"
|
||||
"platform/web/core"
|
||||
m "platform/web/models"
|
||||
q "platform/web/queries"
|
||||
"time"
|
||||
|
||||
"gorm.io/gen/field"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var ArticleGroup = &articleGroupService{}
|
||||
|
||||
type articleGroupService struct{}
|
||||
|
||||
func (s *articleGroupService) All() (result []*m.ArticleGroup, err error) {
|
||||
return q.ArticleGroup.
|
||||
Order(q.ArticleGroup.Sort, q.ArticleGroup.CreatedAt).
|
||||
Find()
|
||||
}
|
||||
|
||||
func (s *articleGroupService) Page(req *PageArticleGroupReq) (result []*m.ArticleGroup, count int64, err error) {
|
||||
do := q.ArticleGroup.Where()
|
||||
if req.Keyword != nil && *req.Keyword != "" {
|
||||
do = do.Where(
|
||||
q.ArticleGroup.Where(
|
||||
q.ArticleGroup.Name.Like("%" + *req.Keyword + "%"),
|
||||
).Or(
|
||||
q.ArticleGroup.Code.Like("%" + *req.Keyword + "%"),
|
||||
),
|
||||
)
|
||||
}
|
||||
if req.Status != nil {
|
||||
do = do.Where(q.ArticleGroup.Status.Eq(int(*req.Status)))
|
||||
}
|
||||
|
||||
return q.ArticleGroup.
|
||||
Where(do).
|
||||
Order(q.ArticleGroup.Sort, q.ArticleGroup.CreatedAt).
|
||||
FindByPage(req.GetOffset(), req.GetLimit())
|
||||
}
|
||||
|
||||
type PageArticleGroupReq struct {
|
||||
core.PageReq
|
||||
Keyword *string `json:"keyword,omitempty"`
|
||||
Status *m.ArticleGroupStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
func (s *articleGroupService) Create(data CreateArticleGroupData) error {
|
||||
err := q.ArticleGroup.Create(&m.ArticleGroup{
|
||||
Name: data.Name,
|
||||
Code: data.Code,
|
||||
Sort: u.Else(data.Sort, 0),
|
||||
Status: u.Else(data.Status, m.ArticleGroupStatusEnabled),
|
||||
})
|
||||
if errors.Is(err, gorm.ErrDuplicatedKey) {
|
||||
return core.NewBizErr("文档分组编码已存在")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type CreateArticleGroupData struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Code string `json:"code" validate:"required"`
|
||||
Sort *int32 `json:"sort"`
|
||||
Status *m.ArticleGroupStatus `json:"status"`
|
||||
}
|
||||
|
||||
func (s *articleGroupService) Update(data UpdateArticleGroupData) error {
|
||||
do := make([]field.AssignExpr, 0)
|
||||
if data.Name != nil {
|
||||
do = append(do, q.ArticleGroup.Name.Value(*data.Name))
|
||||
}
|
||||
if data.Code != nil {
|
||||
do = append(do, q.ArticleGroup.Code.Value(*data.Code))
|
||||
}
|
||||
if data.Sort != nil {
|
||||
do = append(do, q.ArticleGroup.Sort.Value(*data.Sort))
|
||||
}
|
||||
if data.Status != nil {
|
||||
do = append(do, q.ArticleGroup.Status.Value(int(*data.Status)))
|
||||
}
|
||||
if len(do) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
r, err := q.ArticleGroup.Where(q.ArticleGroup.ID.Eq(data.ID)).UpdateSimple(do...)
|
||||
if errors.Is(err, gorm.ErrDuplicatedKey) {
|
||||
return core.NewBizErr("文档分组编码已存在")
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if r.RowsAffected == 0 {
|
||||
return core.NewBizErr("文档分组状态已过期")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type UpdateArticleGroupData struct {
|
||||
ID int32 `json:"id" validate:"required"`
|
||||
Name *string `json:"name"`
|
||||
Code *string `json:"code"`
|
||||
Sort *int32 `json:"sort"`
|
||||
Status *m.ArticleGroupStatus `json:"status"`
|
||||
}
|
||||
|
||||
func (s *articleGroupService) Delete(id int32) error {
|
||||
count, err := q.Article.Where(q.Article.GroupID.Eq(id)).Count()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if count > 0 {
|
||||
return core.NewBizErr("分组下仍有关联文章,无法删除")
|
||||
}
|
||||
|
||||
r, err := q.ArticleGroup.Where(q.ArticleGroup.ID.Eq(id)).UpdateColumn(q.ArticleGroup.DeletedAt, time.Now())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if r.RowsAffected == 0 {
|
||||
return core.NewBizErr("文档分组状态已过期")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user