feat(admin): add comprehensive admin management system

- Add admin handlers and services for users, posts, comments, groups, and dashboard
- Implement role permission management with ability to view and update permissions
- Add database seeding for roles and Casbin permission policies
- Upgrade Casbin from v2 to v3 with GORM adapter for persistent policy storage
- Add admin-specific repository methods with filtering and pagination
- Register new admin API routes under /api/v1/admin/*
This commit is contained in:
2026-03-14 18:01:55 +08:00
parent ae5b997924
commit d3065b30cc
28 changed files with 4018 additions and 107 deletions

View File

@@ -529,3 +529,115 @@ func (r *PostRepository) deleteWithTx(tx *gorm.DB, id string) error {
// 最后删除帖子本身(软删除)
return tx.Delete(&model.Post{}, "id = ?", id).Error
}
// ========== Admin methods ==========
// AdminPostListQuery 管理端帖子列表查询参数
type AdminPostListQuery struct {
Page int
PageSize int
Keyword string
Status string // 为空表示所有状态
AuthorID string
StartDate string // 格式: 2006-01-02
EndDate string // 格式: 2006-01-02
}
// AdminList 管理端分页获取帖子列表(支持多条件筛选)
func (r *PostRepository) AdminList(query AdminPostListQuery) ([]*model.Post, int64, error) {
var posts []*model.Post
var total int64
db := r.db.Model(&model.Post{})
// 关键词搜索(标题或内容)
if query.Keyword != "" {
if r.db.Dialector.Name() == "postgres" {
db = db.Where(
"to_tsvector('simple', COALESCE(title, '') || ' ' || COALESCE(content, '')) @@ plainto_tsquery('simple', ?)",
query.Keyword,
)
} else {
searchPattern := "%" + query.Keyword + "%"
db = db.Where("title LIKE ? OR content LIKE ?", searchPattern, searchPattern)
}
}
// 状态筛选
if query.Status != "" {
db = db.Where("status = ?", query.Status)
}
// 作者筛选
if query.AuthorID != "" {
db = db.Where("user_id = ?", query.AuthorID)
}
// 日期范围筛选
if query.StartDate != "" {
db = db.Where("created_at >= ?", query.StartDate+" 00:00:00")
}
if query.EndDate != "" {
db = db.Where("created_at <= ?", query.EndDate+" 23:59:59")
}
// 统计总数
db.Count(&total)
// 分页查询
offset := (query.Page - 1) * query.PageSize
err := db.Preload("User").Preload("Images").
Offset(offset).Limit(query.PageSize).
Order("created_at DESC").
Find(&posts).Error
return posts, total, err
}
// GetByIDForAdmin 管理端根据ID获取帖子包含所有状态
func (r *PostRepository) GetByIDForAdmin(id string) (*model.Post, error) {
var post model.Post
err := r.db.Preload("User").Preload("Images").First(&post, "id = ?", id).Error
if err != nil {
return nil, err
}
return &post, nil
}
// BatchDelete 批量删除帖子
func (r *PostRepository) BatchDelete(ids []string) ([]string, error) {
var failedIDs []string
for _, id := range ids {
if err := r.Delete(id); err != nil {
failedIDs = append(failedIDs, id)
}
}
return failedIDs, nil
}
// BatchUpdateStatus 批量更新帖子审核状态
func (r *PostRepository) BatchUpdateStatus(ids []string, status model.PostStatus, reviewedBy string) ([]string, error) {
var failedIDs []string
for _, id := range ids {
if err := r.UpdateModerationStatus(id, status, "", reviewedBy); err != nil {
failedIDs = append(failedIDs, id)
}
}
return failedIDs, nil
}
// UpdatePinStatus 更新帖子置顶状态
func (r *PostRepository) UpdatePinStatus(postID string, isPinned bool) error {
return r.db.Model(&model.Post{}).Where("id = ?", postID).
Update("is_pinned", isPinned).Error
}
// UpdateFeatureStatus 更新帖子加精状态
func (r *PostRepository) UpdateFeatureStatus(postID string, isFeatured bool) error {
return r.db.Model(&model.Post{}).Where("id = ?", postID).
Update("is_featured", isFeatured).Error
}