- 新增「简记memo」一体化小程序产品原型设计文档 - 新增简记memo完整版UI视觉设计规范和界面细节 - 添加IDEA项目配置文件.gitignore - 创建404页面HTML文件,包含响应式布局和错误提示 - 添加关于页面HTML文件,展示品牌介绍和团队信息 - 实现AES加解密工具函数,支持请求体加密 - 添加用户协议页面基础框架
20 KiB
20 KiB
成长等级系统规则文档
一、系统概述
成长等级系统是激励用户持续使用应用的核心机制,通过记录用户的日常行为(任务完成、记账、心情记录)来累计经验值,提升等级,解锁成就和特权。
二、API 接口
2.1 获取成长信息
接口路径: POST /growth/info
请求参数: 无
返回示例:
{
"code": 0,
"msg": "success",
"data": {
"id": 1,
"level": 3,
"title": "自律达人",
"titleIcon": "⭐",
"experience": 650,
"nextLevelExp": 1500,
"totalDays": 45,
"streakDays": 12,
"maxStreakDays": 20,
"avgCompletionRate": 0,
"todayProgress": {
"tasksCompleted": 3,
"taskExp": 15,
"billsRecorded": 5,
"billExp": 13,
"moodRecorded": true,
"moodExp": 5,
"streakBonus": 5,
"protectBonus": 0,
"totalExp": 38,
"maxDailyExp": 120
},
"achievements": [
{
"id": "first_record",
"name": "初次尝试",
"icon": "✨",
"unlocked": true,
"unlockDate": "2024-01-15"
}
],
"privileges": [
"解锁心情日历",
"解锁数据报表"
]
}
}
2.2 获取成就列表
接口路径: POST /growth/achievements
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| category | string | 否 | 过滤类别:streak/task/mood/bill |
返回示例:
{
"code": 0,
"msg": "success",
"data": {
"unlocked": [
{
"id": "first_record",
"name": "初次尝试",
"icon": "✨",
"category": "streak",
"description": "完成第1天记录",
"expReward": 10,
"progress": 1,
"target": 1,
"unlocked": true
}
],
"locked": [
{
"id": "streak_7",
"name": "一周打卡",
"icon": "🌟",
"category": "streak",
"description": "连续记录7天",
"expReward": 50,
"progress": 3,
"target": 7,
"unlocked": false
}
]
}
}
2.3 增加经验
接口路径: POST /growth/add
请求参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| source | string | 是 | 来源:task/bill/mood |
| source_id | string | 否 | 关联记录ID |
返回示例:
{
"code": 0,
"msg": "success",
"data": {
"expGained": 38,
"totalExp": 688,
"levelUp": false,
"currentLevel": 3,
"nextLevelExp": 1500,
"newAchievements": []
}
}
三、等级体系
3.1 等级列表
| 等级 | 头衔 | 图标 | 所需累计经验 |
|---|---|---|---|
| Lv.1 | 新手冒险家 | 🎒 | 0 |
| Lv.2 | 坚持学徒 | 📝 | 200 |
| Lv.3 | 自律达人 | ⭐ | 600 |
| Lv.4 | 习惯大师 | 💎 | 1500 |
| Lv.5 | 传奇记录者 | 👑 | 3000 |
| Lv.6 | 时光守望者 | 🏆 | 6000 |
| Lv.7 | 超级达人 | 💫 | 10000 |
| Lv.8 | 传说存在 | 🌟 | 15000 |
| Lv.9 | 永恒传奇 | ⭐ | 22000 |
| Lv.10 | 至高王者 | 👑 | 30000 |
3.2 等级经验计算逻辑
等级根据用户累计经验值自动计算:
func (h *growthHandler) getLevelByExp(exp int) int {
level := 1
for l := 10; l >= 1; l-- {
if config, ok := LevelConfigs[l]; ok && exp >= config.Exp {
level = l
break
}
}
return level
}
四、经验值获取规则
4.1 基础经验
| 来源 | 基础经验 |
|---|---|
| 完成任务 (task) | 5 EXP |
| 记账记录 (bill) | 3 EXP |
| 心情记录 (mood) | 5 EXP |
4.2 任务完成经验加成
| 今日完成任务数 | 经验计算 |
|---|---|
| 1-2个 | 5 EXP/个 |
| 3个以上 | 前2个 5 EXP/个,第3个起 10 EXP/个 |
| 5个以上 | 前2个 5 EXP/个,3-4个 10 EXP/个,第5个起 20 EXP/个 |
示例:
- 完成2个任务:2 × 5 = 10 EXP
- 完成3个任务:2 × 5 + 10 = 20 EXP
- 完成5个任务:2 × 5 + 2 × 10 + 15 = 45 EXP
4.3 记账经验加成
| 今日记账笔数 | 经验计算 |
|---|---|
| 1-2笔 | 3 EXP/笔 |
| 3笔以上 | 前2笔 3 EXP/笔,第3笔起 8 EXP/笔 |
| 5笔以上 | 前2笔 3 EXP/笔,3-4笔 8 EXP/笔,第5笔起 13 EXP/笔 |
示例:
- 记录2笔账单:2 × 3 = 6 EXP
- 记录3笔账单:2 × 3 + 8 = 14 EXP
- 记录5笔账单:2 × 3 + 2 × 8 + 13 = 33 EXP
4.4 心情记录经验
- 每次记录心情:5 EXP
- 每日仅限1次:通过 Redis 记录
mood_count:{userID}:{date},每日只能记录一次
4.5 连续打卡加成
连续打卡天数越多,加成越高:
| 连续天数范围 | 每日加成 |
|---|---|
| 1-7天 | 2 EXP/天 |
| 8-30天 | 5 EXP/天 |
| 31-90天 | 10 EXP/天 |
| 91天以上 | 15 EXP/天 |
4.6 新用户保护期
- 新用户注册后享有 7天保护期
- 保护期内享受 50%额外加成 (
protectBonus = baseExp × 0.5) - 保护期内忘记打卡不会完全重置连续天数
- 如果总记录天数 < 30天,保护期内的连续加成 翻倍
- 保护期结束后
ProtectedDays字段递减
4.7 每日经验上限
每日最高可获得 120 EXP,超过部分会被截断。
五、连续打卡机制
5.1 打卡判断逻辑
isFirstRecordToday := growth.LastRecordDate != today
if isFirstRecordToday {
yesterday := time.Now().AddDate(0, 0, -1).Format("2006-01-02")
if growth.LastRecordDate == yesterday {
// 昨天也打卡了,连续天数+1
growth.StreakDays++
} else if growth.LastRecordDate == "" || growth.LastRecordDate < yesterday {
// 昨天没打卡(断了)
if growth.StreakDays > 0 {
// 有连续记录但断了,根据之前的连续天数给予部分保留
if growth.StreakDays <= 7 {
growth.StreakDays = 0 // 7天内断了,直接清零
} else if growth.StreakDays <= 30 {
growth.StreakDays = 3 // 保留3天
} else if growth.StreakDays <= 90 {
growth.StreakDays = 7 // 保留7天
} else {
growth.StreakDays = 15 // 保留15天
}
}
growth.StreakDays++
}
growth.TotalDays++
}
5.2 断签处理规则
| 之前的连续天数 | 断签后保留天数 |
|---|---|
| ≤7天 | 0天(完全重置) |
| 8-30天 | 3天 |
| 31-90天 | 7天 |
| >90天 | 15天 |
5.3 连续天数重置规则图解
用户连续打卡25天后忘记打卡:
┌─────────────────────────────────────┐
│ 第1-7天: 连续7天 │
│ ↓ 断了 │
│ 保留3天 → 再+1天 = 当前4天连续 │
└─────────────────────────────────────┘
用户连续打卡100天后忘记打卡:
┌─────────────────────────────────────┐
│ 第1-90天: 连续90天 │
│ ↓ 断了 │
│ 保留15天 → 再+1天 = 当前16天连续 │
└─────────────────────────────────────┘
六、成就系统
6.1 成就配置总览
| 成就ID | 名称 | 类别 | 描述 | 奖励经验 | 目标类型 | 目标值 |
|---|---|---|---|---|---|---|
| first_record | 初次尝试 | streak | 完成第1天记录 | 10 | total_days | 1 |
| streak_3 | 3天坚持 | streak | 连续记录3天 | 20 | streak | 3 |
| streak_7 | 一周打卡 | streak | 连续记录7天 | 50 | streak | 7 |
| streak_30 | 月度坚持 | streak | 连续记录30天 | 200 | streak | 30 |
| streak_100 | 百日筑基 | streak | 连续记录100天 | 500 | streak | 100 |
| streak_365 | 年度传奇 | streak | 连续记录365天 | 2000 | streak | 365 |
| task_1 | 任务新手 | task | 完成第1个任务 | 10 | total_tasks | 1 |
| task_100 | 任务达人 | task | 累计完成100个任务 | 200 | total_tasks | 100 |
| task_500 | 任务大师 | task | 累计完成500个任务 | 800 | total_tasks | 500 |
| perfect_day | 完美一天 | task | 单日完成所有待办 | 30 | perfect_day | 1 |
| perfect_week | 完美一周 | task | 连续7天100%完成 | 200 | perfect_week | 7 |
| mood_first | 心情记录者 | mood | 第1次记录心情 | 10 | total_moods | 1 |
| mood_30 | 月度心情家 | mood | 累计记录30天心情 | 100 | total_moods | 30 |
| mood_100 | 心情收藏家 | mood | 累计记录100天心情 | 300 | total_moods | 100 |
| happy_streak | 阳光达人 | mood | 连续10天记录开心 | 150 | happy_streak | 10 |
| bill_1 | 记账入门 | bill | 第1次记账 | 10 | total_bills | 1 |
| bill_100 | 记账达人 | bill | 累计记账100笔 | 200 | total_bills | 100 |
| bill_500 | 记账大师 | bill | 累计记账500笔 | 500 | total_bills | 500 |
6.2 成就分类
📅 坚持类 (streak)
- first_record: 初次尝试 - 完成第1天记录
- streak_3: 3天坚持 - 连续记录3天
- streak_7: 一周打卡 - 连续记录7天
- streak_30: 月度坚持 - 连续记录30天
- streak_100: 百日筑基 - 连续记录100天
- streak_365: 年度传奇 - 连续记录365天
✅ 任务类 (task)
- task_1: 任务新手 - 完成第1个任务
- task_100: 任务达人 - 累计完成100个任务
- task_500: 任务大师 - 累计完成500个任务
- perfect_day: 完美一天 - 单日完成所有待办
- perfect_week: 完美一周 - 连续7天100%完成
😊 心情类 (mood)
- mood_first: 心情记录者 - 第1次记录心情
- mood_30: 月度心情家 - 累计记录30天心情
- mood_100: 心情收藏家 - 累计记录100天心情
- happy_streak: 阳光达人 - 连续10天记录开心
💰 记账类 (bill)
- bill_1: 记账入门 - 第1次记账
- bill_100: 记账达人 - 累计记账100笔
- bill_500: 记账大师 - 累计记账500笔
6.3 成就解锁机制
成就在以下时机检查并解锁:
- 每次增加经验时:检查相关成就是否达成
- 升级时:额外检查所有成就是否达成
解锁成就后会立即发放经验奖励,并记录到 UserAchievement 表。
七、特权系统
7.1 等级特权一览
| 等级 | 解锁特权 |
|---|---|
| Lv.1 | 基础功能 |
| Lv.2 | 解锁心情日历 |
| Lv.3 | 解锁心情日历、解锁数据报表 |
| Lv.4 | 解锁心情日历、解锁数据报表、解锁自定义主题 |
| Lv.5 | 解锁心情日历、解锁数据报表、解锁自定义主题、解锁全部功能 |
| Lv.6 | 解锁心情日历、解锁数据报表、解锁自定义主题、解锁全部功能、解锁年度回顾 |
| Lv.7+ | 解锁心情日历、解锁数据报表、解锁自定义主题、解锁全部功能、解锁年度回顾、解锁数据导出 |
7.2 特权获取逻辑
func (h *growthHandler) getLevelPrivileges(level int) []string {
privileges := []string{}
switch level {
case 1:
// Lv.1 无特权
case 2:
privileges = append(privileges, "解锁心情日历")
case 3:
privileges = append(privileges, "解锁心情日历", "解锁数据报表")
case 4:
privileges = append(privileges, "解锁心情日历", "解锁数据报表", "解锁自定义主题")
case 5:
privileges = append(privileges, "解锁心情日历", "解锁数据报表", "解锁自定义主题", "解锁全部功能")
case 6:
privileges = append(privileges, "解锁心情日历", "解锁数据报表", "解锁自定义主题", "解锁全部功能", "解锁年度回顾")
case 7:
privileges = append(privileges, "解锁心情日历", "解锁数据报表", "解锁自定义主题", "解锁全部功能", "解锁年度回顾", "解锁数据导出")
default:
privileges = append(privileges, "解锁心情日历", "解锁数据报表", "解锁自定义主题", "解锁全部功能", "解锁年度回顾", "解锁数据导出")
}
return privileges
}
八、数据统计指标
8.1 用户成长数据 (UserGrowth)
| 字段 | 类型 | 说明 |
|---|---|---|
| ID | uint | 主键 |
| UserID | uint | 用户ID |
| Level | int | 当前等级 |
| Experience | int | 当前累计经验 |
| TotalDays | int | 累计记录天数 |
| StreakDays | int | 当前连续打卡天数 |
| MaxStreakDays | int | 历史最高连续天数 |
| LastRecordDate | string | 最后记录日期 (YYYY-MM-DD) |
| ProtectedDays | int | 新用户保护期剩余天数 |
| TotalTasks | int | 累计完成任务数 |
| TotalBills | int | 累计记账笔数 |
| TotalMoods | int | 累计心情记录数 |
8.2 每日进度 (DailyProgress)
| 字段 | 类型 | 说明 |
|---|---|---|
| ID | uint | 主键 |
| UserID | uint | 用户ID |
| RecordDate | string | 记录日期 (YYYY-MM-DD) |
| TaskCount | int | 今日完成任务数 |
| BillCount | int | 今日记账笔数 |
| MoodRecorded | bool | 今日是否记录心情 |
| DailyExp | int | 今日获得总经验 |
| ExpBreakdown | string | 经验明细 (JSON格式) |
8.3 经验变化日志 (ExpChangeLog)
| 字段 | 类型 | 说明 |
|---|---|---|
| ID | uint | 主键 |
| UserID | uint | 用户ID |
| ChangeType | string | 变更类型:add/level_up |
| ExpDelta | int | 经验变化量 |
| Source | string | 来源:task/bill/mood/level |
| SourceID | string | 关联记录ID |
| BeforeExp | int | 变化前经验 |
| AfterExp | int | 变化后经验 |
| RecordDate | string | 记录日期 |
8.4 用户成就 (UserAchievement)
| 字段 | 类型 | 说明 |
|---|---|---|
| ID | uint | 主键 |
| UserID | uint | 用户ID |
| AchievementID | string | 成就ID |
| UnlockDate | string | 解锁日期 |
| ExpRewarded | int | 已奖励经验值 |
九、防刷机制
9.1 心情记录限制
if source == "mood" {
key := fmt.Sprintf("mood_count:%d:%s", userID, today)
count, _ := global.Redis.Exists(ctx, key).Result()
if count > 0 {
utils.Fail(c, "今日心情已记录")
return
}
}
- 每日只能记录一次心情
- 通过 Redis Key
mood_count:{userID}:{date}限制 - Key 过期时间:25小时
9.2 并发控制
lockKey := fmt.Sprintf("lock:growth:%d", userID)
ok, _ := global.Redis.SetNX(ctx, lockKey, "1", 2*time.Second).Result()
if !ok {
utils.Fail(c, "系统繁忙,请稍后重试")
return
}
defer global.Redis.Del(ctx, lockKey)
- 使用 Redis 分布式锁防止并发操作
- 锁过期时间:2秒
十、经验计算示例
10.1 普通用户(第1天)
基础条件:无连续、无保护期
操作:完成1个任务
经验计算:
- 任务基础经验:5 EXP
- 连续加成:0 EXP(无连续)
- 保护期加成:0 EXP(保护期需 TotalDays >= 30 才翻倍)
今日总计:5 EXP
10.2 新用户(第7天,保护期内)
基础条件:连续7天,保护期剩余0天
操作:完成3个任务,记录心情
经验计算:
- 任务基础经验:2×5 + 10 = 20 EXP
- 心情经验:5 EXP
- 连续加成(1-7天):2 EXP
- 保护期加成:5 × 50% = 2.5 EXP ≈ 2 EXP
- 保护期连续加成翻倍:2 × 2 = 4 EXP(因为 TotalDays=7 < 30)
今日总计:20 + 5 + 4 + 2 = 31 EXP
10.3 老用户(连续30天)
基础条件:连续30天,保护期已过
操作:完成5个任务,记录3笔账单,记录心情
经验计算:
- 任务经验:2×5 + 2×10 + 15 = 45 EXP
- 账单经验:2×3 + 8 = 14 EXP
- 心情经验:5 EXP
- 连续加成(8-30天):5 EXP
- 保护期加成:0 EXP(保护期已过)
今日总计:45 + 14 + 5 + 5 = 69 EXP
10.4 满级用户(连续100天)
基础条件:连续100天,保护期已过
操作:完成5个任务,记录5笔账单,记录心情
经验计算:
- 任务经验:45 EXP
- 账单经验:2×3 + 2×8 + 13 = 33 EXP
- 心情经验:5 EXP
- 连续加成(31-90天):10 EXP
今日总计:45 + 33 + 5 + 10 = 93 EXP
十一、数据库表结构
11.1 user_growths 表
CREATE TABLE `user_growths` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`created_at` datetime(3) DEFAULT NULL,
`updated_at` datetime(3) DEFAULT NULL,
`deleted_at` datetime(3) DEFAULT NULL,
`user_id` bigint unsigned NOT NULL COMMENT '用户ID',
`level` int DEFAULT '1' COMMENT '当前等级',
`experience` int DEFAULT '0' COMMENT '当前经验值',
`total_days` int DEFAULT '0' COMMENT '累计记录天数',
`streak_days` int DEFAULT '0' COMMENT '连续记录天数',
`max_streak_days` int DEFAULT '0' COMMENT '最高连续天数',
`last_record_date` varchar(10) DEFAULT '' COMMENT '最后记录日期',
`protected_days` int DEFAULT '7' COMMENT '新用户保护期剩余天数',
`total_tasks` int DEFAULT '0' COMMENT '累计完成任务数',
`total_bills` int DEFAULT '0' COMMENT '累计记账笔数',
`total_moods` int DEFAULT '0' COMMENT '累计心情记录数',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
11.2 daily_progress 表
CREATE TABLE `daily_progress` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`created_at` datetime(3) DEFAULT NULL,
`updated_at` datetime(3) DEFAULT NULL,
`deleted_at` datetime(3) DEFAULT NULL,
`user_id` bigint unsigned NOT NULL COMMENT '用户ID',
`record_date` varchar(10) NOT NULL COMMENT '记录日期',
`task_count` int DEFAULT '0' COMMENT '今日完成任务数',
`bill_count` int DEFAULT '0' COMMENT '今日记账笔数',
`mood_recorded` tinyint(1) DEFAULT '0' COMMENT '是否记录心情',
`daily_exp` int DEFAULT '0' COMMENT '今日获得经验',
`exp_breakdown` text COMMENT '经验明细JSON',
PRIMARY KEY (`id`),
KEY `idx_user_date` (`user_id`,`record_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
11.3 exp_change_logs 表
CREATE TABLE `exp_change_logs` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`created_at` datetime(3) DEFAULT NULL,
`updated_at` datetime(3) DEFAULT NULL,
`deleted_at` datetime(3) DEFAULT NULL,
`user_id` bigint unsigned NOT NULL COMMENT '用户ID',
`change_type` varchar(20) NOT NULL COMMENT '变更类型',
`exp_delta` int NOT NULL DEFAULT '0' COMMENT '经验变化量',
`source` varchar(20) DEFAULT '' COMMENT '来源',
`source_id` varchar(50) DEFAULT '' COMMENT '关联记录ID',
`before_exp` int DEFAULT '0' COMMENT '变化前经验',
`after_exp` int DEFAULT '0' COMMENT '变化后经验',
`record_date` varchar(10) NOT NULL COMMENT '记录日期',
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_record_date` (`record_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
11.4 user_achievements 表
CREATE TABLE `user_achievements` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`created_at` datetime(3) DEFAULT NULL,
`updated_at` datetime(3) DEFAULT NULL,
`deleted_at` datetime(3) DEFAULT NULL,
`user_id` bigint unsigned NOT NULL COMMENT '用户ID',
`achievement_id` varchar(50) NOT NULL COMMENT '成就ID',
`unlock_date` varchar(10) NOT NULL COMMENT '解锁日期',
`exp_rewarded` int DEFAULT '0' COMMENT '已奖励经验值',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_user_achievement` (`user_id`,`achievement_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
十二、版本历史
| 版本 | 更新日期 | 更新内容 |
|---|---|---|
| v1.0 | 2024-01-01 | 初始版本,实现基础等级系统 |
| v1.1 | 2024-02-15 | 新增成就系统,包含18个成就 |
| v1.2 | 2024-03-20 | 新增连续打卡保护机制 |
| v1.3 | 2024-04-25 | 优化经验计算规则,添加任务/账单完成加成 |
| v1.4 | 2024-06-01 | 新增心情记录功能 |
| v1.5 | 2024-08-15 | 优化防刷机制,使用Redis分布式锁 |
文档版本: v1.5
最后更新: 2024年8月15日
适用项目: simple-memo 后端成长等级系统
文档路径: /Users/sunct/WeChatProjects/simple-memo/docs/growth_rules.md