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 }