Files
cursor/plans/Plan-95f2e196.plan.md
ray zhou 2dd9f17da9 ok
2026-06-29 14:51:55 +08:00

5.2 KiB
Raw Permalink Blame History


todos:

  • id: "finalize-article-schema" content: "course_article 增加 content_json含 nameList/skipWords正文不再依赖 course_article_sentence" status: pending
  • id: "nce-import-command" content: "NCE_*.json → course + course_article导入时写入 skipWords/nameList人名/地名免敲)" status: pending
  • id: "article-api" content: "GET 课文 APIcontent_json 直出 TypeWords Article DTOnameList 供默写/听写跳过)" status: pending
  • id: "article-vocab-api" content: "课文生词 APIcourse_article_vocab词头+ vocab_sense + course_word_sense与正文分离" status: pending
  • id: "content-patch-admin" content: "低频勘误PATCH content_json 的 text/translate/skipWords或单课重导" status: pending isProject: false

课文内容存储方案建议(修订 v2

结论

  • 课文正文course_article.content_json(几乎不改,偶发勘误)
  • 课文生词:关系表(course_article_vocab + course_word_sense
  • 人名/地名免敲:写在 content_jsonskipWordsAPI 层映射为 TypeWords 的 nameList

人名 / 地名:练习时不用敲

需求

默写或听写课文时,人名、地名应预先标注,练习流程 自动跳过,不要求学生输入(如 SilburyPinhurstJamesScott)。

TypeWords 已有能力(可直接复用)

TypingArticle.vue 已支持 article.nameList

  • 命中 nameList 的 token 在 next()自动跳过
  • 内置跳过:Mr / Mrs / Ms / Dr / Miss
  • 多词条目 "James Scott" 会拆成 jamesscott 分别匹配

不需要在正文里加 {Silbury} 这类 inline 标记;维护一份免敲词表即可。

content_json 里怎么存

推荐 两层字段(存库清晰 + 对接 TypeWords 零改动):

{
  "title": "No wrong numbers",
  "text": "Mr.James Scott has a garage in Silbury ...",
  "textTranslate": "...",
  "audioSrc": "/sound/article/nce2-1/No wrong numbers.mp3",
  "lrcPosition": [[15.45, 24.87]],

  "skipWords": [
    { "token": "James", "type": "person" },
    { "token": "Scott", "type": "person" },
    { "token": "Silbury", "type": "place" },
    { "token": "Pinhurst", "type": "place" }
  ]
}
字段 用途
skipWords[] collin 权威存储type: person / place(可扩展 org
nameList API 输出 时由 skipWords[].token 去重生成为 TypeWords 字段(可不落库重复存)

Lesson5 示例映射:

skipWords → nameList: ["James", "Scott", "Silbury", "Pinhurst"]
Mr 已由 TypeWords 内置跳过)

练习端行为

flowchart LR
    API["GET 课文 API"]
    Map["skipWords → nameList"]
    TW["TypeWords TypingArticle"]
    Skip["isNameWord 自动 next"]

    API --> Map --> TW --> Skip
  • 默写 / 听写:同一套 nameList 逻辑
  • UI 可选增强(后续):按 skipWords.type 在课文预览里给人名/地名不同样式(不影响是否跳过)

导入时谁维护 skipWords

  1. 人工标注(推荐 MVP导入 NCE 时在源 JSON 或 Excel 补一列「免敲词」
  2. 半自动:导入脚本从 text 匹配已知的本课 course_article_vocab 之外的专名词表(准确度有限)
  3. 勘误:只改 content_json.skipWordscontent_version + 1

不要单独建 course_article_skip_token 表 — 与「几乎不改」的 JSON 方案一致,免敲词随课文打包即可。


课文正文content_json不变

层级 存储
正文 course_article.content_json
元数据 course_article 列:lesson_no, title, audio_url, status
生词 关系表(一词一行 + 义项)
词典 word / dict

content_json 不含 newWords skipWords(人名/地名)。

完整示例:

{
  "title": "A private conversation",
  "titleTranslate": "私人谈话",
  "text": "...",
  "textTranslate": "...",
  "audioSrc": "...",
  "lrcPosition": [],
  "skipWords": [
    { "token": "theatre", "type": "place" }
  ],
  "quote": null,
  "question": null
}

与 TypeWords 字段对照

TypeWords Article collin 来源
title, text, textTranslate, lrcPosition, audioSrc content_json
nameList API 由 skipWords[].token 生成
sections 前端 genArticleSectionData(text)
生词 独立 API不进 JSON

对迁移 / API 的调整

  1. course_article.content_json 文档化 skipWords 结构
  2. ArticleApiService:读 JSON → 填充 nameList → 返回 TypeWords DTO
  3. NCE 导入 Command支持从源文件 nameList 迁移,或从 sidecar 配置读 skipWords
  4. 废弃 course_article_sentence(正文不再用句子表)

实施优先级

  1. 定稿 content_json schemaskipWords
  2. NCE 导入 + 首批课文手工标注免敲词
  3. GET 课文 APIskipWordsnameList
  4. 生词 API与正文分离
  5. 勘误PATCH text / translate / skipWords