Skip to content

RVH "我的" 页面功能迁移参考文档

用途:供 ReadingBrowser (RB) 桌面端按需迁移 RVH 功能时参考 生成时间:2026-04-08 数据来源:RVH 代码库 (~/reading_vocab_helper) 实际代码分析


目录

  1. 概览:三大功能模块
  2. 词库管理
  3. 阅读笔记
  4. 来源图片/存储管理
  5. 共享数据结构与表关系
  6. 完整功能清单

1. 概览

Me 页面包含三个功能入口,通过卡片/链接导航:

功能模块入口样式导航路由核心价值
词库管理左列大卡片直接 push NotebookListPage管理 8614 核心词的三种状态:生词本 / 排除词 / 待收集
阅读笔记右列上卡片/reading-note-list管理阅读材料(实体书/电子书/网页),组织学习来源
来源图片右列文本链接/storage-management管理 OCR 拍照产生的图片存储,智能清理释放空间

三者的数据关系:

reading_notes (阅读笔记)
  └─ 1:N ─→ reading_sources (来源图片/文本)
               └─ N:M ─→ notebook_entries (生词本) ←─ vocabulary (核心词库)
                                                     ←─ excluded_words (排除词)

2. 词库管理

2.1 入口页:词库管理首页

页面lib/shared/presentation/pages/vocabulary_management_page.dart

布局

┌─────────────────────────────────────┐
│ 核心词库统计卡片                      │
│  总词数: 8614                        │
│  [生词本: 120] [排除词: 213] [待收集: 8281] │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ 菜单项:                              │
│  📚 生词本管理 → NotebookListPage    │
│  🚫 排除词管理 → ExcludedWordsPage   │
│  🔍 核心词浏览 → WordLookupPage      │
└─────────────────────────────────────┘

统计数据

sql
totalCount    = SELECT COUNT(*) FROM vocabulary
notebookCount = SELECT COUNT(DISTINCT vocabulary_id) FROM notebook_entries WHERE deleted_at IS NULL
excludedCount = SELECT COUNT(*) FROM excluded_words
pendingCount  = totalCount - notebookCount - excludedCount

2.2 生词本管理 (NotebookListPage)

功能点

功能说明
词汇列表分页显示所有生词本条目(每页 20 条)
搜索按 word / definition / nativeTranslation 实时搜索(300ms 防抖)
掌握状态过滤多选:学习中 / 已掌握(空选=全部)
CEFR 级别过滤多选:A1-C2(空选=全部)
阅读笔记过滤下拉选择某本笔记,只显示该笔记关联的词
左滑删除软删除条目(设置 deleted_at)
左滑标记已掌握单条标记 mastery_level → level5
撤销操作删除和标记已掌握都支持 SnackBar 撤销
批量选择模式顶栏切换,支持全选/反选
批量标记已掌握按 CEFR 级别批量标记(弹出 BottomSheet 选择级别)
批量删除确认后批量软删除
统计概览顶部显示:学习中 / 已掌握 / 总计

列表项显示

[word] [IPA] [音频播放按钮]
[释义(首个 POS 的 definition)]
[CEFR 级别标签] [掌握度标签]
← 左滑:[删除] [标记已掌握]

关键 Provider

dart
// 带参数的 Provider(支持路由传入 initialNoteId)
notebookListWithNoteProvider = StateNotifierProvider.autoDispose.family<
    NotebookListNotifier, NotebookListState, NotebookListParams>

2.3 排除词管理 (ExcludedWordsPage)

功能点

功能说明
双类型列表系统停用词(只读)+ 用户排除词(可管理)
类型过滤切换显示:全部 / 系统 / 用户
搜索按 word 搜索
添加排除词对话框输入 word + 可选 reason
左滑删除仅用户排除词可删除
批量选择支持多选 + 批量删除用户排除词
统计概览系统停用词数 / 用户排除词数 / 总计

数据结构

dart
ExcludedWordEntity {
  word: String           // 单词
  source: String         // 'system' | 'user'
  vocabularyId: String?  // 关联的 vocabulary.id
  reason: String?        // 排除原因(仅 user)
  createdAt: DateTime
}

2.4 核心词浏览 (WordLookupPage)

功能点

功能说明
浏览核心词库分页展示 vocabulary 表所有 8614 词
搜索按 word / definition / nativeTranslation 搜索
CEFR 过滤多选 A1-C2
点击查看详情进入 WordDetailPage(完整词汇信息)
左滑加入生词本创建 notebook_entry
左滑加入排除词创建 excluded_word
统计概览总计 / 生词本中 / 排除词中

双向操作:从核心词库可以将词汇分流到生词本或排除词库。


3. 阅读笔记

3.1 笔记列表 (NoteListPage)

页面lib/features/reading_notes/presentation/pages/reading_note_list_page.dart

功能点

功能说明
笔记列表按 updated_at 降序,显示所有阅读笔记
搜索按 title + author 搜索(case-insensitive)
新建按钮顶栏 "+New" 导航到创建页
空状态"Your library is empty" + 添加按钮
列表项封面缩略图(36×48) + 书名 + 右侧统计指标
右侧指标来源数量 / 单词数 / 掌握进度条(%)
左滑编辑进入编辑模式
左滑删除确认对话框(提示:来源不会被删除)
点击进入详情导航到 NoteDetailPage

列表项数据

dart
NoteDisplayDto {
  note: ReadingNoteEntity   // 笔记实体
  sourceCount: int          // 来源图片/文本数量
  wordCount: int            // 关联的生词数
  masteredCount: int        // 已掌握的生词数
  masteryPercent: double    // 掌握率 (0.0-1.0)
}

3.2 笔记详情 (BookDetailPage)

页面lib/features/reading_notes/presentation/pages/reading_note_detail_page.dart

布局

[AppBar: "Note Details"  [编辑] [导出PDF]]

[书籍信息卡片]
  封面(80×120) | 书名(titleLarge) + 作者(bodyMedium)

[学习统计卡片] ← 可点击,跳转到生词本(按该笔记筛选)
  Total Words: 450
  [████████░░░░] 75%
  Learning: 120  |  Mastered: 330

[CEFR 分布图] ← 条件显示(仅 totalWords > 0)
  水平堆叠柱状图:A1-C2,绿色=已掌握,灰色=未掌握

[来源统计卡片] ← 可点击,跳转到来源列表
  45 images · 12.3MB

功能点

功能说明
书籍信息展示封面 + 书名 + 作者
学习统计总词数、学习中、已掌握、进度条
CEFR 分布图按级别显示掌握/未掌握分布
来源统计图片数量 + 存储大小
导航到生词本点击 Total Words → NotebookListPage(selectedNoteId)
导航到来源列表点击来源卡片 → ReadingSourceListPage
编辑按钮进入编辑模式
PDF 导出生成包含所有单词的 PDF + SharePlus 分享

数据加载(5 个并行查询)

① getBookById(noteId)              → 笔记基本信息
② getBookWords(noteId)             → 单词列表 + 掌握统计
③ getSourceCountByBook(noteId)     → 来源图片数
④ getBookCefrDistribution(noteId)  → CEFR 级别分布
⑤ getStorageSizeByBook(noteId)     → 存储大小(bytes)

3.3 创建/编辑笔记 (CreateBookPage)

页面lib/features/reading_notes/presentation/pages/create_reading_note_page.dart

功能点

🗑️ 2026-08-02 更新:下表中 Google Books 相关的 3 项(搜索互联网书籍 / 选择搜索结果 / 后台下载封面)RVH 已删除,不要迁移。UI 入口早已拆除、管道自此不可达,RB 侧 google-books-proxy edge function 也已下线。封面现在只有「本地选图 → 压 192×192 JPEG q85 → 存 BLOB」一条路径(跨端红线 #6c)。

功能说明
书名输入TextFormField,必填验证
本地选封面ImagePicker (maxWidth:800, maxHeight:1200, quality:85)
搜索互联网书籍Google Books API → DraggableScrollableSheet 展示结果(已删除)
选择搜索结果自动回填标题 + Google Books 封面 URL(已删除)
删除/更换封面清除当前封面
后台下载封面保存后异步下载 Google Books 封面到本地(已删除)
创建模式生成 UUID → createBook() → 返回 result
编辑模式加载现有数据 → updateBook() → 返回 true

搜索结果 BottomSheet(🗑️ 2026-08-02 已随 Google Books 管道删除,仅存档):

DraggableScrollableSheet (初始 60%, 最大 85%)
  ├─ loading → CircularProgressIndicator
  ├─ loaded → ListView [小封面 + 书名 + 作者]
  └─ error → 错误提示
用户选择 → 回填标题和封面 URL → 关闭 Sheet

笔记实体

dart
ReadingNoteEntity {
  id: String              // UUID
  title: String           // 书名(必填)
  author: String?         // 作者
  coverImagePath: String? // 本地封面路径
  description: String?    // 简介
  readingProgress: double // 阅读进度 (0.0-1.0)
  bookType: NoteType      // physical / ebook / webArticle / courseMaterial
  fullTextPath: String?   // 电子书原文文件路径
  createdAt: DateTime
  updatedAt: DateTime
}

4. 来源图片/存储管理

4.1 存储管理首页 (StorageManagementPage)

页面lib/features/reading_tracking/presentation/pages/storage_management_page.dart

布局

[AppBar: "Storage"]

[存储概览卡片]
  📊 XXX images · XXX MB
  [████████░░░░] 可清理: XX MB (XX%)
  [Clean Up 按钮]

[分隔符: "By Note"]

[BookStorageCard 列表] ← 每项可点击进入详情
  [封面] 书名 · XX images · XX MB
         YY safe to clean

[分隔符: "Cache"]

[缓存管理卡片]
  临时文件: XX MB  [Clear Cache]

功能点

功能说明
全局存储统计总图片数 + 总大小 + 可清理大小 + 百分比
一键清理遍历所有笔记的可清理来源,批量删除(文件+DB)
按笔记分组每本笔记显示:图片数、大小、可清理数
进入详情页点击某本笔记 → BookStorageDetailPage
缓存清理清理 temp 目录

全局清理流程

① 计算可清理的笔记数和图片数
② 确认对话框:"Delete X images (XX MB) from Y notes.
   Word records and learning progress will be preserved."
③ 遍历每本笔记 → getCleanableSourcesByBook(noteId) → 收集 source.id
④ deleteSourcesCompletely(cleanableIds) — 删除文件 + DB 记录 (CASCADE)
⑤ SnackBar: "Cleaned up X images, freed XX MB"

存储统计实体

dart
StorageStatsEntity {
  totalSourceCount: int       // 总图片数
  totalStorageBytes: int      // 总大小
  cleanableSourceCount: int   // 可删除图片数
  cleanableBytes: int         // 可删除大小
  activeSourceCount: int      // 活跃图片数
  activeBytes: int            // 活跃大小
  bookBreakdown: List<BookStorageInfo>  // 按笔记分组
  tempCacheBytes: int         // 缓存大小
}

4.2 单本笔记存储详情 (BookStorageDetailPage)

页面lib/features/reading_tracking/presentation/pages/book_storage_detail_page.dart

功能点

功能说明
来源列表平铺显示该笔记下所有来源图片
三种排序按价值(默认) / 按大小 / 按日期
价值评分每个来源 0-100 分,圆形徽章显示
价值分类🔴 可删除 / 🟡 低价值 / 🟢 有价值
图片预览点击 → 全屏预览(InteractiveViewer 支持缩放 0.5x-4x)
长按多选长按列表项进入多选模式
快速选择"Select Deletable" 一键选中所有可删除项
全选/反选多选工具栏按钮
批量删除底部浮动栏显示 "已选择: X 项 · XX MB" + Delete 按钮

来源卡片布局

[多选☑️] [缩略图 48×48] [日期 yyyy-MM-dd]        [文件大小]
                         [词数 · 未掌握数 · 独占数]  [评分徽章]

价值评分算法

score = unmasteredRatio × 0.4
      + exclusiveScore  × 0.3
      + totalWordsScore × 0.2
      + freshnessScore  × 0.1

其中:
  unmasteredRatio = (total - mastered) / total × 100
  exclusiveScore  = min(exclusiveCount × 20, 100)
  totalWordsScore = min(totalWords × 10, 100)
  freshnessScore  = 基于创建天数(7天内=100, 14天=80, 30天=60, 90天=40, 180天=20, 更久=10)

分类规则:
  deletable (可删除) : totalWords == 0 OR score < 20
  lowValue  (低价值) : 20 ≤ score ≤ 50
  valuable  (有价值) : score > 50

安全保障

删除操作只删除:
  ✅ 图片文件(originalImagePath, coverImagePath)
  ✅ DB 中的 reading_source 记录 + 关联的 word_sources

保留不删除:
  ✅ notebook_entries(生词本条目和学习进度)
  ✅ vocabulary(核心词库数据)
  ✅ ocrText(OCR 识别的文本内容)

5. 共享数据结构与表关系

5.1 核心表结构

sql
-- 阅读笔记(原 books 表,v39 重命名)
reading_notes (
  id TEXT PRIMARY KEY,
  title TEXT NOT NULL,
  author TEXT,
  cover_image_path TEXT,
  description TEXT,
  reading_progress REAL DEFAULT 0.0,
  book_type TEXT DEFAULT 'physical',    -- physical/ebook/webArticle/courseMaterial
  full_text_path TEXT,
  created_at TEXT NOT NULL,
  updated_at TEXT NOT NULL,
  synced_at TEXT
)

-- 来源图片/文本
reading_sources (
  id TEXT PRIMARY KEY,
  note_id TEXT NOT NULL,               -- FK → reading_notes.id
  name TEXT NOT NULL,
  source_type TEXT DEFAULT 'image',    -- image/text/web
  source_ref TEXT,                     -- URL/文件路径
  image_path TEXT,
  linked_at TEXT NOT NULL,
  created_at TEXT NOT NULL,
  updated_at TEXT NOT NULL,
  synced_at TEXT
)

-- 核心词库(原 vocabulary_items,v39 重命名)
vocabulary (
  id TEXT PRIMARY KEY,
  word TEXT UNIQUE NOT NULL,
  ipa_pronunciation TEXT,
  pronunciation_url TEXT,
  primary_cefr_level TEXT,
  pos_definitions TEXT,                -- JSON: [{pos, definition, translation, examples}]
  frequency_rank INTEGER,
  source TEXT DEFAULT 'preinstalled',
  word_forms TEXT,                     -- JSON
  word_family TEXT,
  etymology TEXT,
  created_at TEXT NOT NULL,
  updated_at TEXT NOT NULL
)

-- 生词本条目
notebook_entries (
  id TEXT PRIMARY KEY,
  vocabulary_id TEXT NOT NULL,         -- FK → vocabulary.id
  user_id TEXT NOT NULL,
  mastery_level TEXT DEFAULT 'level0', -- level0-level5
  next_review_date TEXT,
  last_review_date TEXT,
  review_count INTEGER DEFAULT 0,
  correct_count INTEGER DEFAULT 0,
  easy_factor REAL DEFAULT 2.5,        -- SM-2 参数
  interval INTEGER DEFAULT 0,
  repetitions INTEGER DEFAULT 0,
  added_at TEXT NOT NULL,
  deleted_at TEXT,                      -- 软删除
  synced_at TEXT
)

-- 单词-来源关联(N:M)
word_sources (
  id TEXT PRIMARY KEY,
  notebook_entry_id TEXT NOT NULL,     -- FK → notebook_entries.id
  reading_source_id TEXT NOT NULL,     -- FK → reading_sources.id
  lemma TEXT,                          -- 词形还原后的词
  created_at TEXT NOT NULL,
  synced_at TEXT
)

-- 排除词
excluded_words (
  id TEXT PRIMARY KEY,
  word TEXT NOT NULL UNIQUE,
  source TEXT DEFAULT 'user',          -- system/user
  vocabulary_id TEXT,
  reason TEXT,
  created_at TEXT NOT NULL
)

5.2 关键关联查询

获取某笔记的所有生词

sql
SELECT DISTINCT ne.*, vi.word, vi.pos_definitions, vi.primary_cefr_level
FROM notebook_entries ne
JOIN word_sources wsr ON ne.id = wsr.notebook_entry_id
JOIN reading_sources rs ON wsr.reading_source_id = rs.id
JOIN vocabulary vi ON ne.vocabulary_id = vi.id
WHERE rs.note_id = ? AND ne.deleted_at IS NULL

获取某来源的独占词数(只在该来源出现的词):

sql
SELECT wsr.notebook_entry_id, COUNT(*) as source_count
FROM word_sources wsr
WHERE wsr.notebook_entry_id IN (
  SELECT notebook_entry_id FROM word_sources
  WHERE reading_source_id IN (
    SELECT id FROM reading_sources WHERE note_id = ?
  )
)
GROUP BY wsr.notebook_entry_id
HAVING COUNT(DISTINCT wsr.reading_source_id) = 1

获取可清理的来源

sql
-- 来源中所有关联词都已掌握(level4/level5),则该来源可清理
SELECT rs.* FROM reading_sources rs
WHERE rs.note_id = ? AND rs.image_path IS NOT NULL
AND NOT EXISTS (
  SELECT 1 FROM word_sources wsr
  INNER JOIN notebook_entries ne ON wsr.notebook_entry_id = ne.id
  WHERE wsr.reading_source_id = rs.id
    AND ne.mastery_level NOT IN ('level4', 'level5')
)

5.3 Supabase 同步表映射

本地表Supabase 表同步方向
reading_notesuser_reading_notes双向
reading_sourcesuser_reading_sources双向
notebook_entriesuser_notebook_entries双向(SM-2 merge)
word_sourcesuser_word_sources双向
vocabulary仅本地(预装词库)
excluded_words仅本地

6. 完整功能清单

词库管理

  • [ ] 词库统计首页(总数 / 生词本 / 排除词 / 待收集)
  • [ ] 生词本列表(分页、搜索、多维过滤)
  • [ ] 生词本条目左滑删除(软删除 + 撤销)
  • [ ] 生词本条目左滑标记已掌握(+ 撤销)
  • [ ] 批量选择模式(全选/反选)
  • [ ] 批量标记已掌握(按 CEFR 级别)
  • [ ] 批量删除
  • [ ] 按阅读笔记过滤生词
  • [ ] 排除词管理(系统停用词 + 用户排除词)
  • [ ] 添加/删除排除词
  • [ ] 批量删除排除词
  • [ ] 核心词浏览(vocabulary 全表)
  • [ ] 核心词搜索 + CEFR 过滤
  • [ ] 从核心词加入生词本 / 排除词

阅读笔记

  • [ ] 笔记列表(搜索、排序)
  • [ ] 创建笔记(标题必填 + 可选封面)
  • [ ] Google Books 搜索 + 自动回填标题和封面(🗑️ 2026-08-02 RVH 已删除,勿迁)
  • [ ] 本地选择封面(ImagePicker)
  • [ ] 后台下载 Google Books 封面(🗑️ 2026-08-02 RVH 已删除,勿迁)
  • [ ] 编辑笔记
  • [ ] 删除笔记(确认对话框)
  • [ ] 笔记详情页(统计 + CEFR 分布图 + 来源统计)
  • [ ] 从详情页跳转到生词本(按该笔记筛选)
  • [ ] 从详情页跳转到来源列表
  • [ ] PDF 导出(含所有单词 + SharePlus)

来源图片/存储管理

  • [ ] 全局存储统计(总量 / 可清理 / 百分比)
  • [ ] 按笔记分组统计
  • [ ] 全局一键清理
  • [ ] 缓存大小显示 + 清理
  • [ ] 单本笔记来源详情列表
  • [ ] 三种排序(价值 / 大小 / 日期)
  • [ ] 来源价值评分算法(0-100)
  • [ ] 价值分类标签(可删除 / 低价值 / 有价值)
  • [ ] 全屏图片预览(可缩放)
  • [ ] 长按进入多选模式
  • [ ] 快速选择可删除项
  • [ ] 批量删除(保留学习记录)