按 content-system.md 设计文档,实现帖子内容系统的最小可行 MVC。 新增: - Model: Post 模型,含 5 种状态(draft/pending/approved/rejected/locked) - Repository: post_repo.go,分页查询(前台 approved 列表 + 后台全状态筛选) - Service: post_service.go,核心业务逻辑(状态流转、Markdown 渲染 Goldmark) - Controller: post_controller + admin_post_controller,SSR 页面 6 个 + API 13 个 - Template: 列表/详情/编辑器/404 + 管理员列表,各配 CSS/JS - 路由: /posts, /posts/:id, /posts/new, /posts/:id/edit, REST API, Admin API - gomod: + github.com/yuin/goldmark v1.8.2 修改: - Main: AutoMigrate Post 表 - Router: deps 注册 PostService/Controller,路由注册 - Nav: 新增“帖子”导航链接 - Admin Sidebar: 新增“内容管理”入口 设计: - 审核开关复用 audit.enabled,开启时帖子为 draft,关闭后直接 approved - 仅 approved 公开可见,作者/admin 可预览非公开状态帖子 - 严格分层 ISP 接口: Controller → postUseCase, Service → postStore, Repo → *PostRepo - 状态保护: pending/locked 禁止编辑,rejected 编辑后自动重置为 draft
118 lines
2.9 KiB
Go
118 lines
2.9 KiB
Go
package repository
|
|
|
|
import (
|
|
"metazone.cc/metalab/internal/model"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// PostRepo 帖子数据访问
|
|
type PostRepo struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
// NewPostRepo 构造函数
|
|
func NewPostRepo(db *gorm.DB) *PostRepo {
|
|
return &PostRepo{db: db}
|
|
}
|
|
|
|
// Create 创建帖子
|
|
func (r *PostRepo) Create(post *model.Post) error {
|
|
return r.db.Create(post).Error
|
|
}
|
|
|
|
// FindByID 按 ID 查找帖子
|
|
func (r *PostRepo) FindByID(id uint) (*model.Post, error) {
|
|
var post model.Post
|
|
err := r.db.First(&post, id).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &post, nil
|
|
}
|
|
|
|
// FindByIDWithAuthor 按 ID 查找帖子(含作者用户名)
|
|
func (r *PostRepo) FindByIDWithAuthor(id uint) (*model.Post, error) {
|
|
var post model.Post
|
|
err := r.db.Table("posts").
|
|
Select("posts.*, users.username as author_name").
|
|
Joins("LEFT JOIN users ON users.uid = posts.user_id").
|
|
Where("posts.id = ?", id).
|
|
First(&post).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &post, nil
|
|
}
|
|
|
|
// FindPageable 分页查询帖子列表(仅 approved 状态,关键词模糊搜索标题)
|
|
func (r *PostRepo) FindPageable(keyword string, offset, limit int) ([]model.Post, int64, error) {
|
|
query := r.db.Table("posts").
|
|
Select("posts.*, users.username as author_name").
|
|
Joins("LEFT JOIN users ON users.uid = posts.user_id").
|
|
Where("posts.deleted_at IS NULL").
|
|
Where("posts.status = ?", model.PostStatusApproved)
|
|
|
|
if keyword != "" {
|
|
like := "%" + keyword + "%"
|
|
query = query.Where("posts.title LIKE ?", like)
|
|
}
|
|
|
|
var total int64
|
|
if err := query.Count(&total).Error; err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
var posts []model.Post
|
|
err := query.Order("posts.created_at DESC").
|
|
Offset(offset).Limit(limit).Find(&posts).Error
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
return posts, total, nil
|
|
}
|
|
|
|
// FindAdminPageable 管理后台分页查询(全状态筛选)
|
|
func (r *PostRepo) FindAdminPageable(keyword, status string, offset, limit int) ([]model.Post, int64, error) {
|
|
query := r.db.Table("posts").
|
|
Select("posts.*, users.username as author_name").
|
|
Joins("LEFT JOIN users ON users.uid = posts.user_id").
|
|
Where("posts.deleted_at IS NULL")
|
|
|
|
if keyword != "" {
|
|
like := "%" + keyword + "%"
|
|
query = query.Where("posts.title LIKE ?", like)
|
|
}
|
|
if status != "" {
|
|
query = query.Where("posts.status = ?", status)
|
|
}
|
|
|
|
var total int64
|
|
if err := query.Count(&total).Error; err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
var posts []model.Post
|
|
err := query.Order("posts.created_at DESC").
|
|
Offset(offset).Limit(limit).Find(&posts).Error
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
return posts, total, nil
|
|
}
|
|
|
|
// Update 更新帖子
|
|
func (r *PostRepo) Update(post *model.Post) error {
|
|
return r.db.Save(post).Error
|
|
}
|
|
|
|
// SoftDelete 软删除帖子
|
|
func (r *PostRepo) SoftDelete(id uint) error {
|
|
return r.db.Delete(&model.Post{}, id).Error
|
|
}
|
|
|
|
// Restore 恢复软删除
|
|
func (r *PostRepo) Restore(id uint) error {
|
|
return r.db.Unscoped().Model(&model.Post{}).Where("id = ?", id).Update("deleted_at", nil).Error
|
|
}
|