5.2 KiB
5.2 KiB
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 课文 API:content_json 直出 TypeWords Article DTO(nameList 供默写/听写跳过)" status: pending
- id: "article-vocab-api" content: "课文生词 API:course_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_json的skipWords(API 层映射为 TypeWords 的nameList)
人名 / 地名:练习时不用敲
需求
默写或听写课文时,人名、地名应预先标注,练习流程 自动跳过,不要求学生输入(如 Silbury、Pinhurst、James、Scott)。
TypeWords 已有能力(可直接复用)
TypingArticle.vue 已支持 article.nameList:
- 命中
nameList的 token 在next()时 自动跳过 - 内置跳过:
Mr/Mrs/Ms/Dr/Miss - 多词条目
"James Scott"会拆成james、scott分别匹配
不需要在正文里加 {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
- 人工标注(推荐 MVP):导入 NCE 时在源 JSON 或 Excel 补一列「免敲词」
- 半自动:导入脚本从
text匹配已知的本课course_article_vocab之外的专名词表(准确度有限) - 勘误:只改
content_json.skipWords,content_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 的调整
course_article.content_json文档化skipWords结构ArticleApiService:读 JSON → 填充nameList→ 返回 TypeWords DTO- NCE 导入 Command:支持从源文件
nameList迁移,或从 sidecar 配置读skipWords - 废弃
course_article_sentence(正文不再用句子表)
实施优先级
- 定稿
content_jsonschema(含skipWords) - NCE 导入 + 首批课文手工标注免敲词
- GET 课文 API(
skipWords→nameList) - 生词 API(与正文分离)
- 勘误:PATCH
text/translate/skipWords