feat: 用户徽章与等级体系,积分经济管理重构
- 新增徽章系统:badge 服务与 handler、管理端配置页、BadgeChip/LevelBadge 展示组件 - 新增等级模型:model/level 及前端 levels 元数据 - 管理端经济模块拆分为 points/badges/levels 独立页面,EconomySettings 迁入设置 - 积分、签到、评论等服务适配等级与徽章逻辑
This commit is contained in:
90
backend/model/level.go
Normal file
90
backend/model/level.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// 用户等级:按「累计获得积分」(User.TotalPoints)定级,消费不减经验。
|
||||
// 等级体系(数量/阈值/颜色)由管理员在后台配置,持久化于 site_settings 的 levels_config 键;
|
||||
// 进程内持有一份原子快照供 LevelOf 纯算术计算,配置保存时刷新,无需重启。
|
||||
|
||||
// LevelDef 单级配置:Threshold 为该级累计积分下限(Lv1 恒为 0),Color 为展示色板 key
|
||||
type LevelDef struct {
|
||||
Threshold int `json:"threshold"`
|
||||
Color string `json:"color"`
|
||||
}
|
||||
|
||||
const (
|
||||
// MinLevelCount / MaxLevelCount 等级数量边界(前端 CSS 变量按 MaxLevelCount 档固定下发)
|
||||
MinLevelCount = 2
|
||||
MaxLevelCount = 12
|
||||
)
|
||||
|
||||
// DefaultLevelDefs 默认 7 级(与历史硬编码阶梯一致),缺行/配置非法时回落
|
||||
func DefaultLevelDefs() []LevelDef {
|
||||
return []LevelDef{
|
||||
{Threshold: 0, Color: "neutral"},
|
||||
{Threshold: 50, Color: "info"},
|
||||
{Threshold: 200, Color: "teal"},
|
||||
{Threshold: 500, Color: "ok"},
|
||||
{Threshold: 1200, Color: "accent"},
|
||||
{Threshold: 3000, Color: "purple"},
|
||||
{Threshold: 8000, Color: "gold"},
|
||||
}
|
||||
}
|
||||
|
||||
// levelSnapshot 当前生效的等级配置([]LevelDef)
|
||||
var levelSnapshot atomic.Value
|
||||
|
||||
func init() {
|
||||
levelSnapshot.Store(DefaultLevelDefs())
|
||||
}
|
||||
|
||||
// ValidLevelDefs 结构校验:数量 2–12、阈值非负且严格递增、首级为 0(色板合法性由 service 层校验)
|
||||
func ValidLevelDefs(defs []LevelDef) bool {
|
||||
if len(defs) < MinLevelCount || len(defs) > MaxLevelCount {
|
||||
return false
|
||||
}
|
||||
if defs[0].Threshold != 0 {
|
||||
return false
|
||||
}
|
||||
for i, d := range defs {
|
||||
if d.Threshold < 0 {
|
||||
return false
|
||||
}
|
||||
if i > 0 && d.Threshold <= defs[i-1].Threshold {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ApplyLevelDefs 刷新进程内等级快照;非法/空配置回落默认表
|
||||
func ApplyLevelDefs(defs []LevelDef) {
|
||||
if !ValidLevelDefs(defs) {
|
||||
defs = DefaultLevelDefs()
|
||||
}
|
||||
levelSnapshot.Store(append([]LevelDef(nil), defs...))
|
||||
}
|
||||
|
||||
// LevelDefs 当前生效的等级配置
|
||||
func LevelDefs() []LevelDef {
|
||||
if v, ok := levelSnapshot.Load().([]LevelDef); ok && len(v) > 0 {
|
||||
return v
|
||||
}
|
||||
return DefaultLevelDefs()
|
||||
}
|
||||
|
||||
// LevelOf 由累计获得积分计算等级,恒返回 1..len(当前配置)
|
||||
func LevelOf(totalPoints int) int {
|
||||
defs := LevelDefs()
|
||||
level := 1
|
||||
for i := 1; i < len(defs); i++ {
|
||||
if totalPoints >= defs[i].Threshold {
|
||||
level = i + 1
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return level
|
||||
}
|
||||
Reference in New Issue
Block a user