chatontcf App v1 · 首页与单词 · 交互说明

2026-11-13(太平洋时间)。方向 D(卡片活泼)+ 冷白底 #F5F6FA,无光效(光效只留给以后的音乐页)。 这份文档给 Cursor 用:照着在 frontend-app/(Expo 58 / RN 0.88 / Reanimated 4 / Gesture Handler 3)里实现。

0. 文件和用法

路径 用途
index.html + proto/ 可点击原型。顶栏切换 iPhone / iPad 竖屏 / iPad 横屏,下拉直接跳到任意一屏。
functions/api/[[path]].js Cloudflare Pages Function,把 /api/* 转发到查词服务,key 放在 Pages 加密变量 WORD_API_KEY 里,不进前端文件。
html/tokens.css · tokens.json 设计 token(颜色、字号、间距、圆角、阴影、动效、触感)。RN 落到 lib/theme/index.ts。
html/components.css · proto/proto.css 组件样式。类名对应下面「组件表」里的 RN 组件。
html/NN-*.html 每一屏的静态 DOM 快照(脚本已去掉),给 Cursor 读结构和 class。
png/NN-*.png 每一屏 2x 截图;png/00-overview-board.png 总览板。
contrast-report.md WCAG AA 对比度检查(40 组,全部通过)。
sample-data/ 实时接口抓下来的真实响应(frapper、épanouissement、néanmoins、联想 frapp / fra / 开花、发音),已去掉 usage 字段。
src/capture.py · src/contrast.py 重新截图、重新检查对比度的脚本。

原型里实时接口的数据带绿色「实时接口」标;没有接口或要登录的数据带黄色「示意」标。原型 URL 可以带参数直达,例如 #r=word&w=frapper&device=ipad-l。

1. 关键设计决定

  1. 首页 = 任务仪表盘。 一张深色「今日计划」大卡:新词 / 待复习两个大数字、本周学习柱、今日新词进度(new_introduced_today / new_goal)、一个「开始学习 · 约 N 分钟」按钮。分钟数按 复习 12 秒/个 + 新词 30 秒/个 估算。下面是 D 风格的便当格(继续收听、课本、连续打卡)和 TCF 四项色块。全部做完后按钮变成「今天学完了 · 再来一组」。
  2. 查询 = 一个输入框做完所有事。 单词 / 句子分段切换;空闲时显示最近查询、TCF 高频词建议、查询统计;输入 220ms 防抖后出联想(前缀加粗、变形来源「来自变形 fraie」、中文反查显示中文释义);回车查第一个。麦克风只在单词模式。
  3. 单词详情 = 网页 WordResult 的全部分区,换成卡片 + 吸顶分区条。 顺序不变:单词 → 主释义 → 详细释义 → 英语桥梁 → 例句 → 变位 → 学习辅助 → 权威英语 → 我的备注(已收藏时)。分区条随滚动高亮当前分区,点击平滑滚动。详细释义默认每个词性只展开前几条,「展开全部 26 条」。变位改成「时态胶囊 + 两列表格」,不再是网页的长折叠。
  4. 法语特性做进界面。 名词阴阳性用颜色标签(阳 蓝 / 阴 玫红,文字同时写「阳性 n.m.」,不只靠颜色);查到变形词时提示「你查的 frappe 是 frapper 的变形」并可跳原形;词频 10 格条,≥7 标「TCF 高频」;IPA 用 Inter(Outfit 没有 ʁ ɑ̃ 字形)。
  5. 点任意词都能查。 例句、详细释义里的例句、复习卡背面例句、句子精讲原句,每个词都可点,弹出同一个「点词浮层」:原形、音标、词性、阴阳性、主释义三行、发音、一键加生词本、「详细释义 ›」。这是对标「每日法语听力」最该借的一点:单词模块不是孤岛。
  6. 背单词卡片跟着手指走。 点卡片翻面(3D rotateY 420ms);右滑 = 认识,左滑 = 忘记,拖动时出现「认识 / 忘记」印章;翻面后四档评分,按钮下写下次间隔(10 分钟 / 4 天 / 8 天 / 10 天),让人知道每一档的后果;右上角撤回上一张。键盘:空格翻面、1–4 评分、⌘Z 撤回(iPad 外接键盘)。
  7. 小结要能接着学。 完成率环、四档计数、「再练 N 个忘记 / 模糊的词」、本组单词和下次复习时间,点词进详情。
  8. 本子列表照网页:搜索 + 全部 / 新词 / 待复习 筛选,加上到期提示卡(「5 个今天到期 · 去复习」)、状态标签(新词 / 学习中 / 今天 / 过期 N 天 / N 天后)、左滑移除(带撤销)。
  9. iPad 不是放大的手机。 宽度 ≥ 720 换左侧导航栏(横屏 220,竖屏 84 只放图标+短字)。查询和本子是「列表 + 详情」两栏,左栏不动、右栏换内容;首页横屏两列、竖屏一列;复习和小结居中限宽 560。
  10. 所有写操作先改界面再等服务器,都带撤销:收藏、移除、评分(撤回)。失败时改回去并提示。

2. 现有交互 → 新设计(对照表)

先盘点了 tcf_canada/frontend-web(网页)、frontend-app(App 骨架)和后端 /api/app/v1/,新设计保留全部现有行为和数据,只改界面和手感。

现有(文件) 现有行为 / 数据 新设计里的样子 变化
components/words/WordSearch.tsx 输入防抖调 dict/search?q=&limit=8;↑↓ 选、回车选中或第一个、Esc 关;中文走反查(mode=zh 显示 gloss);变形词显示 via.surface 查询页联想列表(05、06、12) 保留全部键盘行为;前缀加粗;via.tags 前三个写成中文提示;英文词性 noun/verb 映射成中文;无结果时给「直接查」
components/words/WordLookup.tsx + wordSession.ts 查词结果存 sessionStorage;记录查询事件到 stats/lookups/,显示「全站 x 次 · 你 y 次」 最近查询胶囊(本地存储,可清空);详情头部的查询次数 新增「最近查询」列表(只在本机,见缺口 G3)
components/words/WordResult.tsx 分区:单词(词、音标、词形切换、summary、原形/词性/阴阳性、词频条)、主释义、详细释义、英语桥梁、例句(中/法/英)、完整变位(折叠)、学习辅助(用法、记忆、词源、搭配、近/反/派生词)、权威英语 单词详情 07–11 分区和字段一个不少;变位改时态胶囊;近义/反义/派生词可点跳转;例句的法语放第一行(网页是中文在前),每句带朗读
components/words/WordSectionStrip.tsx / WordSectionNav.tsx / useActiveWordSection.ts 分区导航,滚动高亮,hash 定位 吸顶分区条(sticky chip strip) 同一逻辑,改成横向胶囊,吸顶后出现下边线
components/words/WordLemmaSwitch.tsx lemmas[] 多个候选时切换原形(explain?lemma=) 头部候选胶囊 + 「是 xx 的变形 ›」提示条 保留
components/words/WordAudioPlayers.tsx word-audio 返回男女声各一条,按性别标签播放,同时只播一个 「音标 + 喇叭 + 女声」胶囊 + 「男声」胶囊;播放中胶囊变实心紫 合成一个胶囊(沿用 v1 规范「音标和喇叭合一」)
components/words/WordVoiceInput.tsx 浏览器语音识别查词 麦克风按钮 → 语音底部弹层(声波 + 识别中文字) App 用 expo-speech-recognition(fr-CA),不可用时不显示按钮
components/vocabulary/SaveWordControls.tsx 加入 / 移除生词本;下拉选本子,记住 last_notebook_id;add_lemma_with_inflected 时同时加原形并提示 详情底部操作栏「加入默认生词本」+ 文件夹按钮选本子;长按主按钮也能选本子;Toast「已加入默认生词本,明天开始复习 · 撤销」 增加撤销;选本子从下拉改底部弹层(iPad 居中弹窗)
components/vocabulary/StudyPageClient.tsx 取 study/summary、study/queue;正面词+音标+发音,点击翻面看释义和例句;三档 again/hard/good;完成页显示复习数 / 新词数、再来一组;空队列提示 背单词 14–18、空状态 28 加滑动、四档(「简单」需后端,见 G1)、间隔预告、撤回、分段进度、小结页再练弱项;翻面背面加记忆提示和我的备注
components/vocabulary/WordsPageClient.tsx 本子筛选、搜索、全部/新词/待复习、到期日、备注编辑、移除、更新释义、详情弹窗 本子 19–22、单词详情里的「我的备注」卡 备注失焦自动保存;移除改左滑;详情手机上是新页、iPad 是右栏
components/vocabulary/NotebooksPageClient.tsx 新建、改名、删除本子 本子页右上「+」新建;长按本子胶囊出操作菜单(改名 / 删除) 用系统弹窗和操作菜单
components/vocabulary/EntryDetailDialog.tsx 词条详情弹窗 合并进单词详情(同一组件,多一张备注卡) 不再单独做弹窗
components/sentences/SentenceLookup.tsx / SentenceResult.tsx 句子精讲:整句翻译、分块、语法点、结构、词汇、连读、总结、焦点词 句子页 23–24(原句卡 + 翻译 + 分块 + 语法点 + 连读) 原句每个词可点;结构/词汇/总结分区照网页加(原型只画了前几块)
components/sentences/SentenceTokenSelect.tsx 点选句中词作为精讲 targets,有上限(d.focusLimit) 长按任一词进入多选,底部黑色条「已选 2 个词 · 精讲」 上限保持 3
components/sentences/SentenceAudioControls.tsx text-audio 先 check_cache,没有再生成;男女声;未登录要求登录 句子卡「女声朗读 / 男声」胶囊、例句左侧喇叭 生成中按钮呼吸闪烁
components/sentences/SaveSentenceControls.tsx 收藏到句子本 句子卡「收藏到句子本」胶囊;例句长按收藏整句 新增长按
components/lookup/PracticeTextAssist.tsx 真题原文里划词 → 可拖动的小词典面板:原形、词性、阴阳性、男女声、英语桥梁、学习辅助、加入生词本、详细释义 点词浮层(23) 从「划选」改成「点一下」,手机上更顺手;浮层固定宽 300,在词的下方(上半屏)或上方(下半屏)出现
frontend-app/lib/theme/index.ts 蓝色主题 #2F7BF6、底 #F3F5F9、圆角 16 tokens.json 换成 D:紫 #5E5DD6、底 #F5F6FA、卡片圆角 20;评分色加深到 AA;结构不变(colors/spacing/radius/typography)
frontend-app/(tabs)/_layout.tsx 4 个标签 学习/查询/本子/我的 同 选中项用淡紫胶囊底;宽屏换侧栏,项目和顺序不变
frontend-app/lib/layout/ 宽度 ≥ 720 = wide 同 wide 再按方向分横/竖(侧栏宽度不同)

3. 全局规则

3.1 布局

3.2 组件表(HTML class → RN 组件)

class RN 组件 说明
.tab-bar .tab (tabs)/_layout.tsx 自定义 tabBar 选中:图标描边 2 + 淡紫胶囊 54×30
.rail .ri components/shell/SideRail 本子项带待复习红色数字徽标
.card ui/Card 白底、圆角 20、1px 描边 line,不加阴影
.card-dark.plan study/TodayPlanCard 圆角 24
.pastel.{lilac,sky,mint,pink} home/BentoCard variant 卡上一律深字
.btn-primary/-secondary/-ghost ui/Button variant 高 48(sm 36),胶囊
.chip .chip.on ui/Chip 高 32;选中为深色实心
.segmented ui/SegmentedControl 选中块用白底 + 轻阴影,滑动 200ms
.search-field ui/SearchField 聚焦 2px 紫色描边
.list .list-row ui/ListRow 行内分隔线左缩 14,不把每行做成卡片
.tag.* ui/Tag pos / m / f / exam / new / learning / review / due
.audio-pill .audio-btn audio/AudioPill、audio/AudioButton 播放中实心紫
.sec-strip words/WordSectionStrip sticky
.wd-sec words/WordSection 标题前 26×26 彩色小图标底
.tok words/TappableText 的单个词 见 4.6
.define-pop words/DefinePopover
.fc study/Flashcard
.grade.* study/GradeButton
.sheet ui/BottomSheet(宽屏为居中 Modal)
.toast ui/Toast 带可选「撤销」
.sk ui/Skeleton 1.2s 线性 shimmer
.empty ui/EmptyState 图标块 84×84 圆角 28

3.3 动效与触感(Reanimated / Haptics)

场景 参数 实现提示
按下反馈 scale 0.97,120ms,standard Pressable + useAnimatedStyle,或 Animated.View 包 withTiming
页面推入 系统原生栈动画 expo-router Stack,不自己做
分段控件 选中块平移 200ms,out withTiming(x, {duration:200, easing: Easing.bezier(.22,.9,.25,1)})
分区条滚动高亮 跟随 scrollY useAnimatedScrollHandler,分区 onLayout 记 y
点词浮层出现 透明度 0→1 + 上移 6 + scale .98→1,200ms entering={FadeInDown.duration(200)}
卡片翻面 rotateY 0→180°,420ms,out;正反面 backfaceVisibility:'hidden' 两个 Animated.View 共享 progress shared value
卡片拖动 translateX 跟手,rotate = dx/22 度;印章透明度 = dx
卡片判定 dx
评分 / 收藏 轻触感 Haptics.impactAsync(Light);「忘记」用 notificationAsync(Warning)
长按 480ms,中等触感 Gesture.LongPress().minDuration(480)
行左滑 露出 88 宽「移除」;超过 60 吸附 Swipeable(Gesture Handler)
底部弹层 spring(damping 22, stiffness 240);遮罩 200ms @gorhom/bottom-sheet 或自写
Toast 进 200ms;普通 2.6s、带撤销 4s 自动消失
骨架 1.2s 线性 shimmer withRepeat(withTiming(1,{duration:1200, easing: Easing.linear}), -1)
进度条 宽度变化 320ms,out

系统「减弱动态效果」打开时:翻面改成淡入淡出 150ms,卡片飞出改成淡出,shimmer 停止。

4. 每一屏

4.1 首页(学习 tab)· png 01–03

组件:HomeHeader(头像、问候、日期 + 今天查词次数、通知)→ TodayPlanCard → 便当格(ContinueListeningCard 跨两行、TextbookCard、StreakCard)→ TcfTile × 4。宽屏横屏两列:左「今日计划 + TCF 四项 + 我的本子」,右「便当格 + 今天要复习(前 5 个到期词)」。

元素 数据 来源
新词 / 待复习大数字 new_remaining / due_count GET vocabulary/study/summary/?notebook_id=(不带 = 全部生词本)
今日新词进度 new_introduced_today / new_goal 同上
本子选择胶囊 本子列表 GET vocabulary/notebooks/;选择存本机(v1 规范)
本周学习柱 每天学习分钟 缺口 G2
连续打卡 天数、本周 7 格 缺口 G2
今天查词 N 次 your_today GET stats/lookups/summary/
继续收听 / 课本 / TCF 四项计数 — 缺口 G5(Podcast 进度只在网页 localStorage;课本无模型;真题正确率只有网页 /api/v1/)
今天要复习(iPad) 到期词 GET vocabulary/entries/?status=due&limit=5

交互:点「开始学习」→ 复习页;点本子胶囊 → 底部弹层选本子(列出各本待复习数);点便当卡 / TCF → 对应模块(本批未设计,原型给提示)。计划全部完成:按钮文字「今天学完了 · 再来一组」,点了提前复习已学的词。

4.2 查询 tab · png 04–06、12–13

组件:大标题、SegmentedControl(单词 / 句子)、SearchField(清除、麦克风)、RecentLookups、LookupStats、SuggestionList。

状态:空闲(最近查询 + 建议 + 统计)→ 输入中(骨架 4 行)→ 有联想 → 无联想(「直接查 xx」)。句子模式:多行输入 + 「精讲这句话」+ 句子本里的句子。

元素 字段 来源
联想行 word、ipa、pos、via.surface/tags、gender;中文模式 gloss / zh.term worker 外的 api.dict.chatontcf.com/api/dict/search?q=&limit=8(网页同款)
最近查询 本机 AsyncStorage,最多 12 个,去重,最新在前 缺口 G3(后端没有查询记录列表)
统计三格 your_today、your_total、global_today GET stats/lookups/summary/

键盘:回车查当前高亮或第一个;↑↓(iPad 外接键盘)移动高亮;Esc 清空。查询成功后调 POST stats/lookups/(client_event_id 去重)记录一次。iPad:左栏保持输入框和联想不动,右栏显示结果;连续查词不用返回。

4.3 单词详情 · png 07–13

组件:NavBar(返回、数据来源标、更多)、WordHeader、WordSectionStrip、WordSection × N、WordActionBar。

元素 word-explain 字段(schema v3) 备注
词头 explanation.word >11 字母 32px,>15 字母 26px,不断词
音标胶囊 explanation.ipa(无斜杠时补 /…/) 点 = POST word-audio {text} → items[gender=f].url;男声胶囊取 gender=m
词性 / 阴阳性 display.pos / display.gender(m/f)
变形提示 display.lemma ≠ query 点原形 = 重新查
原形候选 lemmas[](label、lemma) 点 = word-explain/{word}?lemma=
概要 display.summary
词频 frequency(0–10) ≥7 加「TCF 高频」
查询次数 global_count、your_count GET stats/lookups/words/?word=
主释义 meaning.zh 19/28 Semibold
详细释义 meaning.senses[].pos、definitions[].zh/fr/example{fr,zh} 第一个词性展开 3 条、其他 1 条,「展开全部 N 条」
英语桥梁 english_bridge.thinking、english_equivalents[]
例句 examples[].fr/zh/en 默认 4 句,「再看 N 句」;喇叭 = text-audio;每个词可点(4.6);长按整句收藏到句子本
变位 conjugations.infinitif/participe_present/participe_passe/tenses[].name/forms[].p,v 时态胶囊切换,默认第一个时态
学习辅助 ai_help.usage/mnemonic/collocations[]/synonyms/antonyms/derivatives/etymology 近/反/派生词胶囊可点查词;搭配前 6 条
权威英语 authoritative_en[]
我的备注 EntryDetailOutput.note、status、due_at、notebooks[] 只在已收藏时出现;失焦 PATCH entries/<id>/ {note};「更新释义」= POST entries/<id>/refresh/
底部「加入默认生词本」 vocabulary/settings/ 的 last_notebook_id;状态 GET entries/status/?word=&notebook_id= 加入 POST notebooks/<id>/entries/(带 word, lemma, ipa, pos, meaning_zh, payload= 整个 explanation,后端存为缓存,返回 added_words);移除 DELETE notebooks/<id>/entries/?word=

状态:加载骨架(首次 AI 生成 3–8 秒,骨架下写「首次查询约需 3–8 秒」)→ 内容;出错(断网 / 超时 12 秒)→ 重试页;外部服务失败但词已收藏 → 用 payload 缓存显示并标「离线数据」。所有字段都可能为空,空就不出该分区,分区条同步隐藏。

4.4 背单词 · png 14–18、28

组件:StudyHeader(关闭、分段进度、n / N、撤回)、Flashcard(正 / 背)、GradeBar、SessionSummary、StudyEmpty。

流程:GET study/queue/?notebook_id= → 第 1 张自动读一次女声 → 点卡片或「显示答案」翻面 → 评分 → POST study/reviews/ {entry_id, rating} → 卡片飞出、下一张自动发音 → 全部完成进小结。关闭时如果已评过至少一张,先进小结。

元素 字段
正面 QueueItem.word、ipa、queue_kind(新词 / 复习标签)、阴阳性(从 payload.display.gender)
背面释义 meaning_zh;例句 payload.examples[0];记忆提示 payload.ai_help.mnemonic;我的备注 note(缺口 G4:QueueItem 没有 note)
间隔预告 客户端按 SM-2 算(需要 ease、interval_days、repetitions,缺口 G1:QueueItem 没有这三个字段)
四档 忘记 = again(10 分钟后)、模糊 = hard、认识 = good、简单 = easy(缺口 G1:后端只有三档)
小结 本地累计;连续打卡 缺口 G2

手势:右滑 = 认识(good),左滑 = 忘记(again);只在正面和背面都可滑。撤回:把上一张放回、界面恢复评分前的状态(缺口 G1:后端没有撤回接口;可先把最后一次评分延迟 4 秒提交,或加 study/reviews/<id>/undo/)。提交失败:停在当前卡片,按钮可再点,进度不丢(v1 规范)。

4.5 本子 tab · png 19–22、27

组件:大标题 + 新建、SegmentedControl(生词本 / 句子本)、NotebookChips、到期提示卡、SearchField、StatusFilter、EntryList(可左滑)。

元素 来源
本子胶囊 + 数量 GET vocabulary/notebooks/(entry_count)
列表 GET vocabulary/entries/?notebook_id=&q=&status=all|new|due&limit=50&offset= → word, ipa, pos, meaning_zh, status, due_at, notebooks
筛选计数 缺口 G6:列表接口只回当前筛选的 total,三个计数要三次请求,建议加 counts
状态标签 status + due_at 算:新词 / 学习中 / 今天 / 过期 N 天 / N 天后
到期卡「去复习」 study/summary/?notebook_id= → 复习页(只复习这个本子)
左滑移除 DELETE vocabulary/notebooks/<id>/entries/?word=;「全部生词本」视图下移除 = 从所有本子移除,要二次确认
句子本 GET sentences/notebooks/、GET sentences/entries/?notebook_id=;句子没有复习(后端无接口)

排序:按字母(后端 order_by("word"));按加入时间排序是缺口 G7。空本子、搜索无结果、待复习为 0 各有一种空状态文案。iPad:左栏列表、右栏单词详情(带备注卡),选中行淡紫高亮。

4.6 点词浮层 · 句子 · png 23–25

4.7 状态 · png 26–29

状态 画法
加载 骨架:词头块、两个胶囊、两行概要、分区条、三张卡;不整页转圈
空本子 淡紫图标块 + 「这个本子还是空的」+ 说明怎么加词 + 「去查词」
没有要复习的 薄荷绿勾 + 「今天没有要复习的词」+ 「去查词」「再来一组(提前复习)」
搜索无结果 天蓝放大镜 + 文案 + 「去查 xx」
断网 / 超时 浅红断网图标 + 原因 + 「重试」;已收藏的词仍可看缓存
写操作失败 界面改回去 + Toast「没保存上,请重试」

文案短、具体、不用感叹号和表情(v1 规范)。

5. 接口总表

用途 接口 归属 原型里
联想 GET https://api.dict.chatontcf.com/api/dict/search?q=&limit=8 外部服务(不在 tcf_worker 仓库) 实时,经 /api/dict/search 代理
单词释义 GET /api/word-explain/{word}?locale=cn[&lemma=] tcf_worker apps/word-explain(网页走 api.explain.chatontcf.com) 实时
单词发音 POST /api/word-audio {text} → items[{voice, gender, url, cached}] tcf_worker apps/word-audio 实时
例句 / 句子朗读 POST https://api.text.chatontcf.com/api/text-audio {text, lang:"fr-CA", gender, check_cache?} → items[{url, words[]}] 外部服务;tcf_worker 的 sentence-audio 只能按 id 读管理员预生成的音频,不适合任意例句 实时(先查缓存,没有再生成)
句子精讲 POST https://api.sentence-explain.chatontcf.com/api/sentence-explain 外部服务 示意(只有一句)
生词本 / 复习 / 设置 /api/app/v1/vocabulary/... Django,Bearer 示意
句子本 /api/app/v1/sentences/... Django 示意
查询统计 /api/app/v1/stats/lookups/... Django 示意
用量上报 POST /api/app/v1/usage/report/(worker 返回的 usage.data) Django 代理把 usage 去掉了,不上报

App 端仍按 v1 规范直接请求查词服务(key 在 App 配置里)。原型改用 Pages Function 代理只是为了不把 key 放进公开网页。

6. 接口缺口(需要后端补,按优先级)

# 缺口 影响 建议
G1 复习只有 again/hard/good 三档;QueueItem 没有 ease / interval_days / repetitions;没有撤回 「简单」档、按钮下的间隔预告、撤回 加 easy(ease +0.15,间隔 = good × 1.3,首次 4 天);QueueItem 加三字段或直接回 next_intervals{again,hard,good,easy};加撤回接口或客户端延迟提交
G2 没有学习记录 / 打卡 / 每日学习时长 首页本周柱、连续打卡、小结里的打卡 新增 study/history/?days=7(每天复习数、新词数、秒数)和 study/streak/
G3 没有查询记录列表 最近查询只能存本机,换设备就没了 stats/lookups/ 加 GET 列表(按时间倒序、去重)
G4 QueueItem 没有 note、gender 卡片背面的「我的备注」、正面阴阳性要额外请求 QueueItem 加 note;gender 可从 payload.display.gender 取,或单列
G5 Podcast 进度、课本、真题正确率没有 App 接口 首页继续收听、课本卡、TCF 四项计数 后续批次一起设计;先补 listening/accuracy/ 等的 app_v1 版本
G6 词条列表没有分状态计数 筛选胶囊上的数字要 3 次请求 entries/ 返回加 counts{all,new,due}
G7 词条只能按字母排序 看不到「最近加入」 entries/?ordering=-added_at
G8 考试日期没有字段 首页「距 TCF 考试 N 天」 Profile 加 exam_date
G9 例句朗读依赖外部 text-audio,tcf_worker 的 sentence-audio 是管理员按 id 生成 例句和词典例句的音频不在同一个可控服务里 把 text-audio 收进 tcf_worker,或给 examples[] 预生成音频 id
G10 首页「今天要复习」预览没有专门接口 iPad 首页右栏 复用 entries/?status=due&limit=5 即可,非阻塞

7. 对比度

见 contrast-report.md:40 组文字 / 底色组合全部 ≥ 4.5(图标 ≥ 3)。改动:分段控件未选文字从 muted 改成 ink-2;占位 / 箭头图标色从 #9A9AA6(2.8:1)压深到 #868692;评分色全部用「浅底 + 深字」,不用白字。阴阳性和状态不只靠颜色,都带文字。

8. 原型的实现说明(不进 App)