积分体系模块
概述
积分体系是追光AI的用户激励核心,包含20级成长系统、积分奖励引擎、积分商店、签到连击和Streak冻结保护,通过游戏化机制提升用户活跃度和留存率。
积分规则
| 行为 |
积分 |
每日上限 |
| 发表评论 |
+5 |
50 |
| 评论被点赞 |
+2 |
20 |
| 发布论坛话题 |
+10 |
无限制 |
| 论坛回复 |
+5 |
30 |
| 发表评价 |
+8 |
20 |
| 每日签到 |
+1 (递增) |
1 |
| 签到连击 bonus |
连续7天+3, 连续30天+10 |
- |
等级系统 - 20级成长体系
等级配置
- 配置文件:
src/lib/level-config.ts — 客户端安全(无Prisma依赖)
- 等级范围: LV01(0分) → LV20(50000分)
- 等级图标: ⭐(初级) → ⭐⭐⭐(中级) → 🌟(高级) → 🌟🌟(精英) → 🌟🌟🌟(大师)
等级表
| 等级 |
最低积分 |
徽章 |
每日限额 |
| LV01 |
0 |
⭐ |
50 |
| LV02 |
10 |
⭐ |
80 |
| LV03 |
30 |
⭐⭐ |
100 |
| LV04 |
60 |
⭐⭐ |
120 |
| LV05 |
100 |
⭐⭐ |
150 |
| LV06 |
200 |
⭐⭐⭐ |
180 |
| LV07 |
400 |
⭐⭐⭐ |
200 |
| LV08 |
700 |
⭐⭐⭐ |
250 |
| LV09 |
1000 |
⭐⭐⭐ |
300 |
| LV10 |
1500 |
🌟 |
400 |
| LV11 |
2000 |
🌟 |
500 |
| LV12 |
3000 |
🌟 |
600 |
| LV13 |
4500 |
🌟 |
700 |
| LV14 |
6000 |
🌟🌟 |
800 |
| LV15 |
8000 |
🌟🌟 |
1000 |
| LV16 |
11000 |
🌟🌟 |
1200 |
| LV17 |
15000 |
🌟🌟 |
1500 |
| LV18 |
20000 |
🌟🌟🌟 |
1800 |
| LV19 |
30000 |
🌟🌟🌟 |
2000 |
| LV20 |
50000 |
🌟🌟🌟 |
3000 |
旧等级迁移映射
BRONZE→LV01, SILVER→LV03, GOLD→LV06, PLATINUM→LV10
积分奖励引擎
- 文件:
src/lib/points-reward.ts
rewardPoints() — 自动发放积分 + 日限额检查 + 事务写入
getUserStats() — 获取用户综合统计(积分/评论数/话题数等)
getUserPointsHistory() — 积分历史分页查询
签到系统
每日签到
- 基础+1分,连续签到递增奖励
- 连续7天: +3 bonus
- 连续30天: +10 bonus
- 中断重置
CheckInCard 组件
- 位置: 用户中心顶部
- 功能: 签到按钮、连击天数显示、季度签到日历
Streak 冻结保护
功能说明
- 用户可通过积分商店购买 Streak Freeze 卡片
- 当用户某天未签到时,自动消耗一张 Freeze 卡保护连击不断
- 最多持有 3 张 Freeze 卡
核心库
- 文件:
src/lib/streak-freeze.ts
checkAndApplyFreeze(userId) — 检查是否需要冻结并自动应用
getFreezeCardCount(userId) — 获取当前持有数量
useFreezeCard(userId) — 消耗一张冻结卡
定时任务
- 脚本:
scripts/grant-freeze-cards.mjs
- 定期为活跃用户发放 Freeze 卡(每日01:00)
积分商店
功能概述
用户可使用积分兑换虚拟物品和社区权益。
商品定义
- 文件:
src/lib/shop-items.ts
- 商品类型: 头像框、昵称颜色、特效道具、Streak Freeze 卡
API 接口
| 路由 |
方法 |
功能 |
| /api/user/shop/items |
GET |
获取可购买商品列表 |
| /api/user/shop/purchase |
POST |
购买商品(扣积分) |
| /api/user/shop/my-items |
GET |
获取用户已购物品 |
前端组件
- 积分商店页面(用户中心入口)
- 商品卡片(名称/图标/价格/库存/购买按钮)
- 已购物品展示(个人中心装饰效果)
数据模型
PointsHistory (积分历史)
| 字段 |
类型 |
说明 |
| id |
Int @id |
主键 |
| userId |
Int |
用户ID |
| points |
Int |
积分变动(正数获得/负数消耗) |
| reason |
String |
积分原因 |
| detail |
String? |
详细信息 |
| refType |
String? |
关联类型 |
| refId |
Int? |
关联ID |
| createdAt |
DateTime |
创建时间 |
StreakFreeze (冻结卡) 🆕
| 字段 |
类型 |
说明 |
| id |
Int @id |
主键 |
| userId |
Int |
用户ID |
| cardCount |
Int |
持有数量 |
| lastUsedAt |
DateTime? |
最近使用时间 |
| createdAt |
DateTime |
创建时间 |
UserShopItem (已购物品) 🆕
| 字段 |
类型 |
说明 |
| id |
Int @id |
主键 |
| userId |
Int |
用户ID |
| itemId |
String |
商品ID |
| purchasedAt |
DateTime |
购买时间 |
| isActive |
Boolean |
是否启用/佩戴 |
前端组件
| 组件 |
文件 |
说明 |
| MemberBadge |
src/components/common/MemberBadge.tsx |
会员等级徽章(⭐🌟 + 积分显示,3种尺寸) |
| LevelProgress |
src/components/common/LevelProgress.tsx |
等级进度条(当前/下一级/进度百分比,动态变色) |
| CheckInCard |
src/components/common/CheckInCard.tsx |
签到卡片(签到按钮/连击天数/季度日历) |
技术实现要点
积分自动奖励机制
所有评论/发帖/点赞操作自动通过 rewardPoints() 发放积分:
- 每日上限检查(防刷分)
- 事务写入(积分变更 + 历史记录同时写入)
- 等级自动随积分变化更新
日志分类
积分变动通过 reason 字段区分:
comment — 评论
comment_liked — 评论被点赞
topic_create — 发帖
reply — 回复
review — 评价
check_in — 签到
shop_purchase — 商店消费(负数)