feat: 实现域能系统

- 新增域能完整分层:EnergyLog/PostEnergizeLog/DailyExpSummary 模型、EnergyRepo、EnergyService、EnergyController/AdminEnergyController
- 支持签到获取域能(+1)、帖子赋能(-1/-2)/被赋能(+1/+2)、改名扣能(-6)/退款(+6)、删帖扣能(-2)
- 赋能单人单帖上限20域能,每日赋能获得经验上限50
- 管理员支持批量调整域能(owner)和查询域能日志(admin)
- LV0用户(exp<1)禁止签到和发帖,余额为负可签到/被赋能/删帖但不能赋能/改名
- 首次改名免费(通过HasCompletedTask判重),改名扣能在提交审核时执行
- 移除导航栏手动签到按钮,签到融入域能系统(自动签到)
- 新增个人中心域能TAB展示余额和流水日志(近7天)
- 新增帖子详情页赋能按钮(轻赋/重赋)
- 管理后台新增域能管理和域能日志页面
This commit is contained in:
2026-06-01 03:32:50 +08:00
parent 394989b281
commit e1d7c318ab
31 changed files with 1234 additions and 88 deletions

View File

@ -44,14 +44,20 @@ type auditTaskCompleter interface {
CompleteTask(userID uint, taskType string) (newExp int, levelUp bool, err error)
}
// energyRenameRefunder 改名审核被拒时返还域能的接口ISP
type energyRenameRefunder interface {
RefundOnRenameReject(userID uint) error
}
// AuditService 审核业务逻辑
type AuditService struct {
auditRepo auditRepo
userRepo userProfileStore
settings siteSettingsChecker
defaultCfg config.AuditConfig
notifier auditNotifier
levelSvc auditTaskCompleter
auditRepo auditRepo
userRepo userProfileStore
settings siteSettingsChecker
defaultCfg config.AuditConfig
notifier auditNotifier
levelSvc auditTaskCompleter
energyRefundSvc energyRenameRefunder
}
// NewAuditService 构造函数
@ -66,6 +72,12 @@ func NewAuditService(auditRepo auditRepo, userRepo userProfileStore, settings si
}
}
// WithEnergyRefundService 链式注入域能退款服务
func (s *AuditService) WithEnergyRefundService(svc energyRenameRefunder) *AuditService {
s.energyRefundSvc = svc
return s
}
// ShouldAudit 判断指定用户是否需要走审核流程
// 规则admin 及以上角色免审
func (s *AuditService) ShouldAudit(userID uint) (bool, error) {
@ -195,11 +207,18 @@ func (s *AuditService) review(reviewerID uint, submissionID uint, approved bool,
} else {
submission.Status = model.AuditStatusRejected
submission.RejectReason = &reason
// 通知用户审核被拒
// 通知用户审核被拒(改名审核追加域能返还提示)
if s.notifier != nil {
reasonMsg := reason
if submission.AuditType == model.AuditTypeUsername {
reasonMsg += "。扣除的域能已被返还"
}
s.notifier.NotifyAuditRejected(submission.UserID, submission.AuditType, reasonMsg, submission.ID)
}
// 改名审核被拒 → 返还域能
if submission.AuditType == model.AuditTypeUsername && s.energyRefundSvc != nil {
_ = s.energyRefundSvc.RefundOnRenameReject(submission.UserID)
}
}
return s.auditRepo.Update(submission)
}