feat: 定时发布系统 — Phase 5 完成

- Post ScheduledAt 字段
- Scheduler goroutine 每分钟扫描到期文章
- Create/Update 校验最短 30min 定时
- Approve 审核晚于定时则即时发布
- public 列表+空间页过滤未到期文章
- 写文章页 datetime-local 选择器(min=now+30min)
- AutoMigrate 追加新表
This commit is contained in:
2026-06-22 00:39:04 +08:00
parent 0b8f6f890d
commit e9b7401dc9
14 changed files with 132 additions and 15 deletions

View File

@ -42,9 +42,9 @@ type postUseCase interface {
// studioUseCase StudioController 对 PostService 的最小依赖ISP9 个方法)
type studioUseCase interface {
Create(userID uint, title, body, visibility, postType, reprintSource, declaration string, reprintProhibited bool, categoryID string) (*model.Post, error)
Create(userID uint, title, body, visibility, postType, reprintSource, declaration string, reprintProhibited bool, categoryID, scheduledAt string) (*model.Post, error)
GetByID(id uint) (*model.Post, error)
Update(postID uint, title, body, visibility, postType, reprintSource, declaration string, reprintProhibited bool, categoryID string) error
Update(postID uint, title, body, visibility, postType, reprintSource, declaration string, reprintProhibited bool, categoryID, scheduledAt string) error
Delete(postID uint) error
SubmitForAudit(postID uint) error
ListByUser(userID uint, status string, page, pageSize int) ([]model.Post, int64, error)

View File

@ -30,8 +30,12 @@ func (ctrl *StudioController) Create(c *gin.Context) {
return
}
post, err := ctrl.postService.Create(uid, req.Title, req.Body, req.Visibility, req.PostType, req.ReprintSource, req.Declaration, req.ReprintProhibited, req.CategoryID)
post, err := ctrl.postService.Create(uid, req.Title, req.Body, req.Visibility, req.PostType, req.ReprintSource, req.Declaration, req.ReprintProhibited, req.CategoryID, req.ScheduledAt)
if err != nil {
if err == common.ErrScheduledTooSoon {
common.Error(c, http.StatusBadRequest, err.Error())
return
}
common.Error(c, http.StatusInternalServerError, "发布失败")
return
}
@ -74,7 +78,7 @@ func (ctrl *StudioController) Update(c *gin.Context) {
return
}
if err := ctrl.postService.Update(uint(id), req.Title, req.Body, req.Visibility, req.PostType, req.ReprintSource, req.Declaration, req.ReprintProhibited, req.CategoryID); err != nil {
if err := ctrl.postService.Update(uint(id), req.Title, req.Body, req.Visibility, req.PostType, req.ReprintSource, req.Declaration, req.ReprintProhibited, req.CategoryID, req.ScheduledAt); err != nil {
common.Error(c, http.StatusInternalServerError, "编辑失败")
return
}