feat(posts): 类型帖截止时间、抽奖奖品表与悬赏发帖体验
统一投票/悬赏/抽奖截止与状态展示,抽奖支持多奖品行;发帖页悬赏积分对齐表格输入,并在余额不足时于底部就地提示。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -22,6 +22,7 @@ var (
|
||||
type PostService struct {
|
||||
db *gorm.DB
|
||||
setting *SettingService
|
||||
devMode bool
|
||||
}
|
||||
|
||||
func NewPostService(db *gorm.DB) *PostService {
|
||||
@@ -34,6 +35,12 @@ func (s *PostService) WithSetting(setting *SettingService) *PostService {
|
||||
return s
|
||||
}
|
||||
|
||||
// WithDevMode 开发态:抽奖同 IP 去重对回环地址放宽
|
||||
func (s *PostService) WithDevMode(dev bool) *PostService {
|
||||
s.devMode = dev
|
||||
return s
|
||||
}
|
||||
|
||||
// PostListQuery 帖子列表查询参数
|
||||
type PostListQuery struct {
|
||||
BoardID uint
|
||||
@@ -445,6 +452,7 @@ func (s *PostService) GetByIDForViewer(id, viewerID uint, loadActor func() *Acto
|
||||
// 惰性结算:悬赏过期退回 / 抽奖到期开奖
|
||||
_ = s.settleExpiredBountyIfNeeded(&post)
|
||||
_ = s.settleDueLotteryIfNeeded(&post)
|
||||
_ = s.settleDuePollIfNeeded(&post)
|
||||
if post.TypeMeta != "" {
|
||||
var fresh model.Post
|
||||
if err := s.db.Select("type_meta").First(&fresh, post.ID).Error; err == nil {
|
||||
@@ -729,9 +737,8 @@ func (s *PostService) Create(in CreatePostInput) (*PostDetail, error) {
|
||||
bm.Expired = false
|
||||
bm.AcceptedCommentID = 0
|
||||
if status == model.ContentStatusPublished {
|
||||
days := normalizeExpireDays(bm.ExpireDays, 7, []int{3, 7, 14, 30})
|
||||
bm.EndsAt = resolveEndsAtOnPublish(bm.EndsAt, bm.ExpireDays, 7, []int{3, 7, 14, 30}, now)
|
||||
bm.ExpireDays = 0
|
||||
bm.EndsAt = endsAtFromDays(days, now)
|
||||
}
|
||||
typeMeta, _ = encodeMeta(bm)
|
||||
}
|
||||
@@ -741,14 +748,26 @@ func (s *PostService) Create(in CreatePostInput) (*PostDetail, error) {
|
||||
if lm.WinnerIDs == nil {
|
||||
lm.WinnerIDs = []uint{}
|
||||
}
|
||||
if lm.Prizes == nil {
|
||||
lm.Prizes = []LotteryPrize{}
|
||||
}
|
||||
lm.Slots = lotterySlotsFromPrizes(lm.Prizes)
|
||||
if status == model.ContentStatusPublished {
|
||||
days := normalizeExpireDays(lm.ExpireDays, 7, []int{1, 3, 7, 14})
|
||||
lm.EndsAt = resolveEndsAtOnPublish(lm.EndsAt, lm.ExpireDays, 7, []int{1, 3, 7, 14}, now)
|
||||
lm.ExpireDays = 0
|
||||
lm.EndsAt = endsAtFromDays(days, now)
|
||||
}
|
||||
typeMeta, _ = encodeMeta(lm)
|
||||
}
|
||||
|
||||
if postType == model.PostTypePoll {
|
||||
pm, _ := parsePollMeta(typeMeta)
|
||||
if status == model.ContentStatusPublished {
|
||||
pm.EndsAt = resolveEndsAtOnPublish(pm.EndsAt, pm.ExpireDays, 7, []int{1, 3, 7, 14}, now)
|
||||
pm.ExpireDays = 0
|
||||
}
|
||||
typeMeta, _ = encodeMeta(pm)
|
||||
}
|
||||
|
||||
post := &model.Post{
|
||||
BoardID: in.BoardID, UserID: in.UserID,
|
||||
Title: title, Content: content, Tags: in.Tags,
|
||||
@@ -892,9 +911,15 @@ func (s *PostService) Update(actor *Actor, postID, userID uint, in UpdatePostInp
|
||||
neu.Multi = old.Multi
|
||||
neu.Anonymous = old.Anonymous
|
||||
neu.Closed = old.Closed
|
||||
neu.EndsAt = old.EndsAt
|
||||
neu.ClosedAt = old.ClosedAt
|
||||
neu.ExpireDays = 0
|
||||
meta, _ = encodeMeta(neu)
|
||||
} else {
|
||||
neu.Closed = old.Closed
|
||||
neu.EndsAt = old.EndsAt
|
||||
neu.ClosedAt = old.ClosedAt
|
||||
neu.ExpireDays = 0
|
||||
meta, _ = encodeMeta(neu)
|
||||
}
|
||||
}
|
||||
@@ -907,8 +932,16 @@ func (s *PostService) Update(actor *Actor, postID, userID uint, in UpdatePostInp
|
||||
neu.WinnerIDs = old.WinnerIDs
|
||||
neu.Closed = old.Closed
|
||||
neu.EndsAt = old.EndsAt
|
||||
if old.Drawn {
|
||||
// 已有评论或已开奖:冻结奖品(名额由奖品合计推导)
|
||||
locked := old.Drawn || post.CommentCount > 0
|
||||
if locked {
|
||||
if !lotteryPrizesEqual(neu.Prizes, old.Prizes) || neu.Slots != old.Slots {
|
||||
return nil, ErrLotteryPrizesLocked
|
||||
}
|
||||
neu.Prizes = old.Prizes
|
||||
neu.Slots = old.Slots
|
||||
} else {
|
||||
neu.Slots = lotterySlotsFromPrizes(neu.Prizes)
|
||||
}
|
||||
meta, _ = encodeMeta(neu)
|
||||
}
|
||||
@@ -920,6 +953,7 @@ func (s *PostService) Update(actor *Actor, postID, userID uint, in UpdatePostInp
|
||||
// 解题态走专用 API,编辑帖子不覆盖
|
||||
neu.Solved = old.Solved
|
||||
neu.AcceptedCommentID = old.AcceptedCommentID
|
||||
neu.SolvedAt = old.SolvedAt
|
||||
meta, _ = encodeMeta(neu)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user