feat: 用户徽章与等级体系,积分经济管理重构
- 新增徽章系统:badge 服务与 handler、管理端配置页、BadgeChip/LevelBadge 展示组件 - 新增等级模型:model/level 及前端 levels 元数据 - 管理端经济模块拆分为 points/badges/levels 独立页面,EconomySettings 迁入设置 - 积分、签到、评论等服务适配等级与徽章逻辑
This commit is contained in:
@@ -61,6 +61,7 @@ func InitDB(dsn string) error {
|
||||
&Announcement{}, &SitePage{}, &SiteSetting{}, &SiteDailyStats{}, &SiteDailyVisitor{}, &VisitEvent{}, &Attachment{}, &UserBoard{}, &LoginLog{},
|
||||
&ChatRoom{}, &ChatRoomMember{}, &ChatMessage{},
|
||||
&PointLedger{}, &PostContentUnlock{}, &PostAttachment{}, &PostAttachmentUnlock{},
|
||||
&Badge{}, &UserBadge{},
|
||||
&PostPollVote{}, &PostLotteryEntry{}, &Ad{}, &SidebarWidget{},
|
||||
&ImportRecord{},
|
||||
); err != nil {
|
||||
@@ -73,6 +74,10 @@ func InitDB(dsn string) error {
|
||||
return fmt.Errorf("站长角色迁移失败: %w", err)
|
||||
}
|
||||
|
||||
// 用户等级:按积分流水回填累计获得积分(经验值,LevelOf 定级依据)。
|
||||
// 每次启动执行,幂等自愈,保证与 CreditTx 增量口径一致(均排除 bounty_refund)
|
||||
backfillUserTotalPoints(db)
|
||||
|
||||
// login_logs.success 早期 default=true 与 GORM 零值省略叠加,
|
||||
// 会把失败登录错存为成功;AutoMigrate 不会改列默认值,这里幂等修正
|
||||
if err := db.Exec(`ALTER TABLE login_logs ALTER COLUMN success SET DEFAULT false`).Error; err != nil {
|
||||
@@ -334,6 +339,35 @@ func ensureOwnerRole(db *gorm.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// backfillUserTotalPoints 按积分流水回填累计获得积分(经验值)。
|
||||
// 口径与 CreditTx 增量一致:仅计正入账,排除悬赏托管退回(bounty_refund)。
|
||||
// 每次启动执行,幂等自愈;失败仅记日志不阻断启动(等级纯展示,可下次启动修复)。
|
||||
func backfillUserTotalPoints(db *gorm.DB) {
|
||||
var tableCount int64
|
||||
if err := db.Raw(`SELECT count(1) FROM information_schema.tables WHERE table_name = 'point_ledgers'`).
|
||||
Scan(&tableCount).Error; err != nil {
|
||||
log.Printf("[model] 回填累计获得积分前置检查失败: %v", err)
|
||||
return
|
||||
}
|
||||
if tableCount == 0 {
|
||||
return
|
||||
}
|
||||
res := db.Exec(`
|
||||
UPDATE users SET total_points = COALESCE((
|
||||
SELECT SUM(delta) FROM point_ledgers
|
||||
WHERE point_ledgers.user_id = users.id AND delta > 0 AND reason <> 'bounty_refund'
|
||||
), 0)
|
||||
WHERE deleted_at IS NULL
|
||||
`)
|
||||
if res.Error != nil {
|
||||
log.Printf("[model] 回填累计获得积分失败: %v", res.Error)
|
||||
return
|
||||
}
|
||||
if res.RowsAffected > 0 {
|
||||
log.Printf("[model] 已按积分流水回填累计获得积分 %d 行", res.RowsAffected)
|
||||
}
|
||||
}
|
||||
|
||||
// backfillBoardDefaults 为升级前已存在的板块补齐新字段默认值。
|
||||
// 以 post_policy 为空作为「迁移前旧行」的判定标志:仅对这些行一次性回填
|
||||
// post_policy=all、visible=true;后续已被显式设置过的行(含站长隐藏的板块)不会被覆盖。
|
||||
|
||||
Reference in New Issue
Block a user