Skip to content

探字星球 项目设计文档

版本: 3.0 | 日期: 2026-07-19 基于 web/ TypeScript 项目重构,含 Mock API 层


一、项目概述

探字星球是专为 3-8 岁儿童设计的汉字学习应用,通过趣味互动和游戏化学习认识 500 个精选汉字。当前为纯前端实现 + Mock API 模拟后端。

1.1 核心设计理念

  • 游戏化驱动学习:段位升级、徽章收集、星球探索三条成长线并行
  • 数据闭环:每种学习行为都产生 record,驱动艾宾浩斯复习调度
  • 少选择、多引导:用户不面对"选哪种模式"的决策,系统直接告诉"该复习这些字"
  • 渐进式解锁:星球、关卡、徽章均按完成度逐步解锁,保持持续激励

1.2 用户画像

角色需求使用场景
3-8岁儿童识字、认读、书写每日15-30分钟学习
家长管理学习内容、控制奖励设置密码、配置奖励

二、总体架构

2.1 技术栈

类别技术版本
框架Vue 3Composition API + <script setup> + TypeScript
路由vue-router22条命名路由 + 3条重定向
状态管理Pinia5个Store(TypeScript)
UI组件库tdesign-mobile-vue移动端UI
HTTPaxiosapi-service 统一封装
Mock APImockjs39个RESTful接口
汉字书写hanzi-writer笔顺动画 + 描红练习
3D渲染three.jsWebGL + GLSL着色器
构建Vite开发服务器 + 生产构建
测试vitest140个测试用例
类型检查vue-tscTypeScript 严格模式

2.2 四层架构

Pages/Components → Stores → api-service.ts (axios) → Mock API (mockjs) → localStorage
       ↑              ↑                ↑                      ↑
   UI交互层      状态管理层       HTTP请求层            数据模拟层
  • Pages/Components:UI渲染和用户交互,引用Store和Composable
  • Stores:数据持久化入口,通过 api-service 统一访问 Mock API
  • api-service.ts:axios 封装,统一请求/响应拦截
  • Mock API:mockjs 拦截 axios 请求,模拟后端接口(39个RESTful接口)
  • Services:跨模块奖励发放(reward-service)、CDN资源管理(resource-service)
  • Composables:可复用的逻辑组合(复习调度、汉字筛选、游戏计时、拖拽交互)

2.3 模块依赖图

App.vue (TabBar: 首页/汉字星际/星球地图/我的)
  ├── 首页 (index)          → 复习计划 / 游戏中心 / 积分商店
  ├── 汉字星际 (char-select) → 汉字详情 (character) → 书写练习 (write) → 书写结果 (write-result)
  ├── 星球地图 (planet-map)  → 星球详情 (planet-detail) → 汉字分类 (planet-series) → 书写
  └── 我的 (profile)         → 成就系统 / 设置 / 复习统计 / 关于
       ├── 成就系统 (achievement-home) → 徽章墙 (badge-wall)
       └── 设置 (settings) → 家长管理 (shop-manage)

三、路由设计

3.1 完整路由表

路径名称组件Tab说明
/onboardingonboardingonboarding.vue-首次引导页
/indexindexindex.vue首页
/char-selectchar-selectchar-select.vue汉字星际
/charactercharactercharacter.vue-汉字详情
/writewritewrite.vue-书写练习
/write-resultwrite-resultwrite-result.vue-书写结果
/profileprofileprofile.vue我的
/settingssettingssettings.vue-设置
/review-todayreview-todayreview-today.vue-今日复习
/planet-mapplanet-mapplanet-map.vue星球地图
/planet-detailplanet-detailplanet-detail.vue-星球详情
/planet-seriesplanet-seriesplanet-series.vue-汉字分类
/achievement-homeachievement-homeachievement-home.vue-成就系统
/badge-wallbadge-wallbadge-wall.vue-徽章墙
/game-menugame-menugame-menu.vue-汉字游戏
/pictograph-matchpictograph-matchpictograph-match.vue-象形配对
/stroke-puzzlestroke-puzzlestroke-puzzle.vue-拼图闯关
/char-match3char-match3char-match3.vue-汉字消消乐
/review-statsreview-statsreview-stats.vue-复习统计
/shopshopshop.vue-积分商店
/shop-manageshop-manageshop-manage.vue-家长管理
/aboutaboutabout.vue-关于

重定向规则:

  • //onboarding
  • /review-mode/review-today(旧路由兼容)
  • /:pathMatch(.*)*/onboarding

3.2 路由守卫

ts
router.beforeEach((to, from, next) => {
  const hasOnboarded = localStorage.getItem("tzxq_onboarded")
  if (!hasOnboarded && to.path !== "/onboarding") {
    next("/onboarding")  // 首次进入 → 引导页
  } else if (hasOnboarded && to.path === "/onboarding") {
    next("/index")       // 已引导 → 跳过引导页
  } else {
    next()
  }
})

3.3 TabBar 配置

4个底部Tab:首页(/index)、汉字星际(/char-select)、星球地图(/planet-map)、我的(/profile)


四、数据模型

4.1 核心数据结构

userStore (userData) — 用户数据

ts
interface UserData {
  userName: "汉字探索者",           // 用户名
  avatar: "",                        // 头像
  learned: [],                       // 已学会汉字列表(score≥60)
  records: [],                       // 学习记录 [{ char, type, score, date }]
  reviewStages: {},                  // 复习阶段 { [char]: { stage, nextReviewDate, history[] } }
  lastDailyReview: null,             // 上次完成每日复习日期
  settings: { dailyGoal, strokeHint, autoAudio, fontSize, darkMode, showFooterCredit },
  streak: 0,                         // 连续学习天数
  maxStreak: 0,                      // 最长连续天数
  lastStudyDate: null,               // 最后学习日期
  badges: [],                        // 已解锁徽章 [{ badgeId, unlockedAt }]
  totalEXP: 0,                       // 总经验值
  shopPoints: 0,                     // 积分余额
  pointLog: [],                      // 积分日志 [{ id, type, amount, balance, source, desc, time }]
  etymologyViewed: [],               // 已查看字源的汉字列表
  shopRewards: [],                   // 自定义奖励 [{ id, name, cost, icon, enabled, createdAt }]
  shopHistory: [],                   // 兑换历史(保留最新50条)
  shopPassword: "",                  // 密码哈希(SHA-256)
  shopLockUntil: 0,                  // 密码锁定截止时间戳
  shopAttempts: 0,                   // 密码错误尝试次数
  planetUnlocks: ["nature_planet"],  // 已解锁星球列表
}

character.json — 汉字数据

ts
interface Character {
  version: "2.3.0",
  total: 500,
  categories: { /* 6大分类 × 24子分类 */ },
  characters: {
    "一": {
      pinyin: "yī1",           // 拼音+声调(1-4声,5=轻声)
      radical: "一",            // 部首
      strokes: 1,               // 笔画数
      structure: "独体",        // 结构
      meaning: "数字一",        // 释义
      words: ["一定", "一起"],  // 词组
      sentences: ["我是一年级学生。"],
      etymology: {              // 字源
        stages: {
          oracle: { description: "..." },
          bronze: { description: "..." },
          seal: { description: "..." },
          clerical: { description: "..." },
          regular: { description: "..." }
        }
      },
      category: "number",       // 分类
      sub_category: "number_basic",
      difficulty: 1,            // 难度 1-5
      frequency: 1,             // 频率 1-5
      is_common: true,
      is_multi_pinyin: false,   // 是否多音字
      pinyins: []               // 多音字列表(含词组和造句)
    }
  }
}

categories.json — 分类体系

6大分类(自然、人物、动物、器物、植物、天文)× 24子分类,每个含 coloricondescription

planets.json — 星球配置

6颗星球,每颗含 sub_series(子系列)、rhyme(童谣)、unlock_condition。默认解锁 nature_planet。

games.json — 游戏关卡

3款游戏 × 10关 = 30关,每关含 difficulty(1-5)、rewards.exprewards.coinsstars阈值。

4.2 数据持久化

Key说明管理方式
tzxq_mock_db用户数据(Mock API 管理)Mock API 自动保存
tzxq_onboarded引导完成标记直接 localStorage
tzxq_resource_cacheLRU资源缓存resource-cache.ts

五、奖励系统

5.1 奖励常量定义

所有奖励统一由 reward-service.ts 管理,定义在 REWARD 常量对象:

常量EXP积分source触发场景
WRITE_COMPLETE+10+1write_complete每次书写完成
WRITE_PERFECT+10+1write_perfect书写满分(100分)
FIRST_LEARN+5+1first_learn首次学会(score≥60首次进入learned)
RECOGNITION_PASS+50recognition_pass认读选择题答对
RECOGNITION_FAIL+10recognition_fail认读选择题答错
REVIEW_CHAR+5+1review_char完成单字复习全流程
DAILY_REVIEW_FULL+50+5daily_review每日复习100%完成
DAILY_REVIEW_80+30+3daily_review每日复习≥80%完成
BADGE_UNLOCK+50+5badge_unlock每解锁一枚徽章

5.2 奖励发放流程

行为触发 → awardXxxReward() → achievementStore.addEXP/addPoints()

                            userStore.addEXP/addPoints()

                            api-service.ts → Mock API → localStorage 持久化

                            徽章检测 (watch → checkBadges)

5.3 去重机制

  • 复习单字去重reviewedChars Set,同一会话中同一汉字只奖励一次
  • 每日复习去重lastDailyReview 日期检查,每天只奖励一次

5.4 游戏奖励

游戏奖励通过 awardGameReward(gameType, level, stars, levelConfig) 发放,公式:

exp = baseExp × starMultiplier × difficultyMultiplier
coins = baseCoins × starMultiplier × difficultyMultiplier

starMultiplier: 1★=1.0x, 2★=1.5x, 3★=2.0x
difficultyMultiplier: [1.0, 1.0, 1.2, 1.5, 1.8, 2.0][difficulty]

失败(stars≤0)不发放奖励。


六、段位系统

6.1 段位定义

5大级别 × 10小段 = 50段,每段经验值递增:

级别名称颜色EXP区间每段EXP
青铜bronze#cd7f320-999100
白银silver#c0c0c01000-2499150
黄金gold#ffd7002500-4499200
铂金platinum#42a5f54500-6999250
王者king#ab47bc7000-9999300

段位计算:segment = startSegment + floor((totalEXP - tierMin) / segmentExp),最高50段。

6.2 升级所需总EXP

级别到达所需EXP
青铜0
白银1000
黄金2500
铂金4500
王者7000
满级10000

七、徽章系统

7.1 徽章总览(30枚)

类别数量徽章解锁条件
书写 (write)6first_write, write_10/50/100, perfect_10/30累计书写次数/满分次数
探索 (explore)6learn_10/50/100/200/300/500累计学会汉字数
恒心 (streak)6streak_3/7/14/30/60/100连续学习天数
字源 (etymology)6etymology_10/30/50/100/200/300累计查看字源字数
游戏 (game)6game_1/5/10/26, game_perfect_3/10累计完成关卡/3星通关数

7.2 徽章解锁机制

  • 书写/探索/恒心/字源:通过 watch 监听对应数据变化自动检测
  • 游戏:通过 watch 监听 gameStore.getGameProgress() 变化自动检测
  • 初始化检查achievementStore 创建时执行 checkWriteBadges() 等,确保从localStorage恢复后正确检测

7.3 徽章奖励

每解锁一枚徽章:+50 EXP, +5 积分。


八、书写系统

8.1 书写流程

汉字详情页 (character) → 书写练习页 (write) → 书写结果页 (write-result)

8.2 三种入口

入口from参数汉字列表掌握判定全部掌握后跳转
汉字星际char-select全部汉字maxScore ≥ 60/char-select
星球地图planet-series按subCategory过滤maxScore ≥ 60/planet-series
薄弱字review-statsTop 10薄弱字(动态重算)准确率 ≥ 100%/review-stats

8.3 书写评分公式

score = accuracyScore(0-70) + completionScore(0-25) + speedBonus(0-5)

accuracyScore = max(0, 1 - totalMistakes / attempted) × 70
completionScore = quizComplete ? 25 : (currentStroke / totalStrokes) × 25
speedBonus = quizComplete ? round(5 × min(1, expectedTime / totalTime)) : 0

8.4 评分等级

分数星级文案
≥955星太棒了!书写完美!
≥804星写得不错,继续加油!
≥603星还可以,多练习会更好
≥402星需要多多练习哦
<401星加油,坚持就是胜利!

8.5 HanziWriter 配置

  • 描红模式:笔画颜色 #1f2937(黑色)
  • 笔顺演示模式:笔画颜色 #3b82f6(蓝色)
  • 模式切换时保留writer实例,通过 setCharacter() 重置状态
  • 笔画数据通过 resource-service.ts 统一获取,含请求去重

九、复习系统

9.1 设计概述

基于艾宾浩斯遗忘曲线的间隔复习,已从旧版"只看首次学习日期"升级为阶段追踪制

9.2 复习间隔

REVIEW_INTERVALS = [1, 3, 7, 15, 30] 天

useReviewScheduler.ts 为唯一定义点,userStore和review-today均引用此常量。

9.3 阶段推进规则

条件行为
复习得分 ≥ 80stage + 1(不超过4),nextReviewDate按REVIEW_INTERVALS[stage]推算
复习得分 60-79stage 不变,nextReviewDate = 明天(重试)
复习得分 < 60stage 重置为 0,nextReviewDate = 明天(重新学)
错过复习日(超过nextReviewDate + 3天)标记为"过期复习"

9.4 复习流程(三步)

步骤1: 认读测试 — 展示汉字 → 4选1拼音选择题
  正确 → +5 EXP, record score=100
  错误 → +1 EXP, record score=0

步骤2: 书写练习 — 跳转HanziWriter描红 → 评分(0-100)

步骤3: 字源回顾 — 字源演变缩略图 + 记忆提示 → 自动进入下个字

关键设计改进:

  • 认读从主观自评改为客观选择题(4选1拼音),产生record
  • 每步都产生record,驱动艾宾浩斯调度
  • 单字完成奖励 +5 EXP, +1 积分(带去重)

9.5 每日复习奖励

条件EXP积分
完成率 = 100%+50+5
完成率 ≥ 80%+30+3
完成率 < 80%00

每天仅触发一次,通过 lastDailyReview 日期去重。

9.6 页面结构

首页 → /review-today(主入口)
  ├── 列表视图:今日复习概览 + 待复习汉字列表 + 快捷入口
  ├── 复习流程视图(ReviewFlow):三步复习流程
  └── 完成庆祝视图(ReviewComplete):奖励汇总

/review-mode 已删除,替换为重定向 /review-mode/review-today

9.7 复习统计(review-stats)

  • 显示复习阶段分布(各阶段字数、百分比、过期字数)
  • 正确率基于全部records计算
  • 阶段分布基于 reviewStages 数据实时计算

十、游戏系统

10.1 游戏总览

游戏类型核心机制道具关卡数
象形配对配对60s限时,古文字→现代汉字配对1次提示10关
拼图闯关拖放笔画拼块拖放,进度记忆提示(-5分)10关
汉字消消乐Match-37×7棋盘,步数限制锤子(3)、洗牌(2)、提示(3)10关

10.2 游戏奖励配置

象形配对 (pictograph_match)

关卡难度基础EXP基础积分1★分数2★分数3★分数
11158305070
212010305070
3225125080110
4230155080110
53401870110150
63502270110150
74602690140190
847030110170230
958035100150200
10510040130190250

拼图闯关 (stroke_puzzle)

关卡难度基础EXP基础积分
11158
212010
322512
423015
534018
635022
746026
847030
958035
10510040

汉字消消乐 (char_match3)

同上,3款游戏使用相同的奖励配置。

10.3 关卡解锁

前一关通关(目标完成)即标记 completed,与星级无关,下一关自动解锁。

10.4 失败处理

  • 象形配对:错误次数达到上限(配对数×50%)→ 弹出失败弹窗
  • 拼图闯关:错误次数达到上限(3-5次,随难度递增)→ 失败
  • 汉字消消乐:步数耗尽 → 1秒后弹出失败弹窗,endGame(false)earnedExp=0, earnedCoins=0

十一、星球系统

11.1 星球列表

星球ID主题色分类解锁条件
自然星球nature_planet#4CAF50nature默认解锁
人物星球human_planet红色系human完成自然星球
动物星球animal_planet暖色系animal完成人物星球
器物星球object_planet蓝色系object完成动物星球
植物星球plant_planet绿色系plant完成器物星球
天文星球astronomy_planet紫色系astronomy完成植物星球

11.2 解锁机制

  • 默认解锁第一颗星球(nature_planet)
  • 完成星球全部内容后自动解锁下一颗
  • 设置页面可手动解锁/锁定(第一颗不可锁定)
  • 解锁状态通过 userStore.planetUnlocks[] 管理

11.3 星球地图 3D渲染

  • 使用 Three.js + 6个GLSL着色器
  • 三态切换:orbit(轨道漫游)→ focus(聚焦单星)→ single(进入星球)
  • 光线投射检测点击
  • 相机飞行动画
  • 星空粒子背景 + 星云效果
  • 星球椭圆轨道运动

11.4 星球详情

  • 星球封面3D模型(CoverGalaxy)
  • 学习进度条:position: sticky; top: 48px,通过IntersectionObserver检测悬浮状态
  • 汉字分类展示(SeriesCharIcon使用HanziWriter绘制笔画动画)
  • 星球介绍 + 童谣

十二、积分商店

12.1 兑换流程

查找奖励 → 验证状态(enabled + 余额充足) → 扣除积分 → 生成积分日志 → 记录兑换历史

12.2 自定义奖励

数据结构:{ id, name, cost, icon, enabled, createdAt }

管理接口:addReward(), updateReward(), toggleReward(), deleteReward()

10种预设图标:tv(看电视)、toy(玩具)、park(去公园)、book(书籍)、gamepad(打游戏)、candy(零食)、bike(骑自行车)、phone(玩手机)、star(自定义)、gift(礼物)

12.3 密码保护

  • SHA-256哈希存储(Web Crypto API)
  • 3次错误尝试 → 锁定60秒
  • 锁定状态持久化(防刷新绕过)
  • 密码修改需输入原密码验证

12.4 积分日志

  • 每条日志包含:id、type(earn/spend)、amount、balance、source、sourceId、desc、time
  • 所有积分变动均记录
  • 兑换历史保留最新50条

十三、资源服务

13.1 资源加载策略

资源类型加载方式回退
hanziWriter笔顺本地 JSON(import.meta.glob)-
字源SVG本地 public/data/ → CNB CDNjsDelivr CDN
汉字音频本地 public/data/ → bcebos CDN → CNB CDNjsDelivr CDN → TTS

13.2 关键机制

  • 统一入口:所有CDN资源通过resource-service.ts访问,禁止裸fetch
  • 请求去重getHanziWriterData使用_hwPending Map,同汉字并发请求复用同一Promise
  • LRU缓存resource-cache.ts,最大50条,持久化到localStorage
  • 字源预检preCheckStages()先加载index.json,只对available的阶段加载SVG,缺失阶段生成fallback楷书SVG
  • 音频回退:CDN音频失败 → TTS合成,_fallbackUsed flag防止重复TTS

十四、安全设计

14.1 密码安全

  • 密码使用SHA-256哈希存储,不明文保存
  • 利用Web Crypto API实现,无需额外依赖
  • 3次错误锁定60秒,防暴力破解

14.2 数据安全

  • 所有数据存储于localStorage,无后端交互
  • 关键状态持久化(锁定时间、尝试次数)防刷新绕过
  • 积分日志完整记录每次变动,可追溯

十五、性能优化

15.1 已实施优化

优化项方案
CDN请求去重pending Promise Map,同汉字只发一次请求
字源预检先查index.json,跳过缺失阶段,减少无效请求
路由懒加载所有页面组件动态import
星球地图预加载planet-map和planet-detail使用webpackPrefetch
LRU缓存资源缓存最大50条,避免重复加载
音频回退控制_fallbackUsed flag防止重复TTS

15.2 布局约束

  • 星球地图禁止滚动:touch-action: none; overflow: hidden
  • 星球地图弹性布局:flex: 1; min-height: 0 自动填充
  • 进度条悬浮:position: sticky; top: 48px + IntersectionObserver
  • 图标横向滚动:flex-shrink: 0 保持64×64正方形
  • 图标下拉展开:3列布局,max-height: 160px 内部滚动

十六、关键设计决策

16.1 已实现的重构

维度重构前重构后
复习页面3个(review-mode + review-today + review-stats)2个(review-today + review-stats)
导航深度4跳(首页→review-mode→review-today→write)3跳(首页→review-today→write)
认读评估主观自评(无record)客观选择题(有record)
艾宾浩斯只看首次学习日期阶段追踪制(reviewStages)
复习间隔定义3处重复(user.js + review-today.vue + character.json)1处(useReviewScheduler.js)
每日复习奖励未实现已实现(80%/100%两档)
复习统计假数据混合仅真实数据

16.2 设计原则符合性

  • 一致性:所有奖励通过reward-service统一入口
  • 简洁性:复习间隔单一定义点,双源CDN统一访问
  • 可读性:useReviewScheduler纯函数可独立测试
  • 可测试性:score-calculator独立测试,覆盖正常/边界/异常
  • 可逆性:数据迁移自动执行(learned[]→reviewStages),不影响存量用户

附:文件清单

源码统计

类别数量说明
页面22个不含已删除的review-mode
Store5个user, achievement, character, game, shop(TypeScript)
Service5个api-service, reward-service, resource-service, resource-cache, storage-service
Mock API39个RESTful接口,按模块分类(auth/user/character/game/achievement/shop/planet)
Composable4个useCharFilter, useReviewScheduler, useGameTimer, useDragInteraction
全局组件5个AppNavBar, FooterCredit, EtymologyViewer, StrokeAnimationCanvas, WritingPracticeCanvas
书写模块7个文件3个页面 + 4个组件 + score-calculator
星球地图10个文件3个页面 + 4个组件 + 2个shader + 1个shader index
游戏模块9个文件3个游戏 + 1个菜单 + 5个共享组件
工具函数6个char-utils, date-utils, format-utils, array-utils, logger, index(TypeScript)
配置文件3个config.ts, constants.ts, planet-visuals.ts
数据文件4个character.json, categories.json, planets.json, games.json
测试文件140个vitest 测试用例