Skip to content

achievement.ts — 成就 Store

文件: web/src/stores/achievement.ts

职责

  • 段位系统计算(5 大级别 × 10 小段 = 50 段)
  • 30 枚徽章管理和自动解锁
  • 通过 watch 监听 user/game Store 数据变化自动检测徽章解锁
  • 学习记录触发 EXP/积分奖励

依赖

Store用途
useUserStore读取 EXP/积分/徽章/学习记录/连续天数/字源查看
useCharacterStore已导入(当前未直接使用)
useGameStore延迟获取(ensureGameStore),用于游戏徽章检测

数据加载

  • load(): 通过 api.get<LevelDef[]>("/achievements/levels") + api.get<BadgeDef[]>("/achievements/badges") 异步加载段位定义和徽章定义。
  • 初始化时自动调用,加载完成后立即检查所有徽章状态。

段位系统

段位定义(LEVELS)通过 GET /achievements/levels 异步加载,不再硬编码。每个 LevelDef 包含:

typescript
interface LevelDef {
  tier: string          // 级别标识(如 "bronze", "silver")
  name: string          // 显示名称(如 "青铜")
  color: string         // 颜色(如 "#cd7f32")
  min: number           // 该级别最低 EXP
  max: number           // 该级别最高 EXP
  startSegment: number  // 起始段位编号
  segmentExp: number    // 每小段所需 EXP
}

每小段 EXP = 100-300(随级别递增),共 50 段。

徽章定义

徽章定义(BADGE_DEFS)通过 GET /achievements/badges 异步加载,不再硬编码。每个 BadgeDef 包含 idnamedesccategoryicon

Reactive State

属性类型说明
totalEXPComputedRef<number>用户总经验值(来自 userStore)
shopPointsComputedRef<number>用户积分(来自 userStore)
currentLevelComputedRef<CurrentLevel>当前段位详情(含进度、下一段 EXP 等)
allBadgesComputedRef<BadgeWithStatus[]>全部徽章(含 unlocked 状态)
unlockedBadgesComputedRef<BadgeWithStatus[]>已解锁徽章列表
unlockedCountComputedRef<number>已解锁徽章数量

CurrentLevel 结构

typescript
interface CurrentLevel {
  tier: string              // 当前级别名称
  tierColor: string         // 级别颜色
  tierIcon: string          // 级别图标(tier 字段)
  tierMin: number           // 当前级别最低 EXP
  segment: number           // 当前段位编号(1-50)
  segmentInTier: number     // 当前级别内段位(1-10)
  currentEXP: number        // 当前 EXP
  nextSegmentEXP: number    // 下一段所需 EXP
  progress: number          // 当前段进度(0-1)
  tierProgress: number      // 当前级别进度(0-1)
  nextTierEXP: number       // 下一级别所需 EXP
  nextTierName: string|null // 下一级别名称
}

方法

EXP 与积分

方法签名说明
addEXP(amount: number) => void委托给 userStore.addEXP
addPoints(amount: number, source: string, sourceId: string, desc: string) => void委托给 userStore.addPoints

徽章

方法签名说明
unlockBadge(badgeId: string) => void解锁徽章(去重),额外奖励 50 EXP + 5 积分

事件处理

方法签名说明
handleNewRecord(record: RecordItem) => void处理新学习记录,根据类型/分数自动增加 EXP/积分,检查书写徽章
handleDailyReviewComplete(percent: number) => void每日复习完成奖励(≥100%: 50EXP+5分, ≥80%: 30EXP+3分)

徽章检查(watch 自动触发 + 初始化时主动调用)

方法触发条件检查徽章
checkExplorationBadgeslearned.length 变化learn_10/50/100/200/300/500
checkStreakBadgesstreak 变化streak_3/7/14/30/60/100
checkWriteBadges初始化时调用first_write, write_10/50/100, perfect_10/30
checkEtymologyBadgesetymologyViewed.length 变化etymology_10/30/50/100/200/300
checkGameBadgesgameData 变化game_1/5/10/26, game_perfect_3/10

自动监听机制

Store 初始化时注册 5 个 watch

  1. watch recordshandleNewRecord(处理新增记录,发放 EXP/积分)
  2. watch learnedcheckExplorationBadges
  3. watch streakcheckStreakBadges
  4. watch gameDatacheckGameBadges(延迟获取 gameStore 实例)
  5. watch etymologyViewedcheckEtymologyBadges

load() 完成后立即执行一轮全量徽章检查。