chengjie 1 неделя назад
Родитель
Сommit
6e53de9f6d
21 измененных файлов с 16422 добавлено и 0 удалено
  1. 76 0
      .vscode/秒过知识库更新/2026年秋季更新结果.md
  2. 23 0
      .vscode/秒过知识库更新/MiaoguoLiteracy依赖检查_2026年秋季.md
  3. 44 0
      .vscode/秒过知识库更新/MiaoguoLiteracy缺失清单_2026年秋季.md
  4. 37 0
      .vscode/秒过知识库更新/MiaoguoLiteracy补录结果_2026年秋季.md
  5. 175 0
      .vscode/秒过知识库更新/README.md
  6. 2887 0
      .vscode/秒过知识库更新/apply_report_2026_fall.json
  7. 223 0
      .vscode/秒过知识库更新/audit_miaoguo_literacy_2026_fall.mjs
  8. 265 0
      .vscode/秒过知识库更新/audit_report_2026_fall.json
  9. 4289 0
      .vscode/秒过知识库更新/backups/before_2026_fall_2026-09-01T04-58-35-478Z.json
  10. 354 0
      .vscode/秒过知识库更新/backups/before_miaoguo_literacy_2026_fall_2026-09-01T05-27-10-536Z.json
  11. 2380 0
      .vscode/秒过知识库更新/dry_run_report_2026_fall.json
  12. 1528 0
      .vscode/秒过知识库更新/miaoguo_literacy_apply_report_2026_fall.json
  13. 736 0
      .vscode/秒过知识库更新/miaoguo_literacy_audit_2026_fall.json
  14. 415 0
      .vscode/秒过知识库更新/miaoguo_literacy_dependency_audit_current_2026_fall.json
  15. 1092 0
      .vscode/秒过知识库更新/miaoguo_literacy_dry_run_2026_fall.json
  16. 193 0
      .vscode/秒过知识库更新/miaoguo_literacy_post_apply_audit_2026_fall.json
  17. 262 0
      .vscode/秒过知识库更新/source_chinese_2026_fall.json
  18. 288 0
      .vscode/秒过知识库更新/source_english_2026_fall.json
  19. 202 0
      .vscode/秒过知识库更新/source_miaoguo_literacy_2026_fall.json
  20. 581 0
      .vscode/秒过知识库更新/update_knowledge_base_2026_fall.mjs
  21. 372 0
      .vscode/秒过知识库更新/update_miaoguo_literacy_2026_fall.mjs

+ 76 - 0
.vscode/秒过知识库更新/2026年秋季更新结果.md

@@ -0,0 +1,76 @@
1
+# 2026 年秋季秒过知识库更新结果
2
+
3
+执行日期:2026-09-01(Asia/Shanghai)  
4
+教材来源:`/Users/chengjie/Downloads/课本`  
5
+执行状态:已提交,事务内核验、提交后核验、独立审计均通过。
6
+
7
+## 更新清单
8
+
9
+| 学科/类别 | MiaoguoBook.ID | BookIDOld | 数据行 | UnitNum | WordNum | 写入方式 |
10
+|---|---:|---:|---:|---:|---:|---|
11
+| 语文四上识字 | 49 | 67 | 31→31 | 31→31 | 270→265 | 更新 31,新增 0,删除 0 |
12
+| 语文四上写字 | 7 | 19 | 20→25 | 20→25 | 250→250 | 更新 20,新增 5,删除 0 |
13
+| 语文四上词语 | 37 | 49 | 16→21 | 16→21 | 240→220 | 更新 16,新增 5,删除 0 |
14
+| 语文五上识字 | 51 | 69 | 26→27 | 26→27 | 217→209 | 更新 26,新增 1,删除 0 |
15
+| 语文五上写字 | 9 | 21 | 20→22 | 20→22 | 220→220 | 更新 20,新增 2,删除 0 |
16
+| 语文五上词语 | 39 | 51 | 16→18 | 16→18 | 222→213 | 更新 16,新增 2,删除 0 |
17
+| 语文六上写字 | 11 | 23 | 18→19 | 18→19 | 180→180 | 更新 18,新增 1,删除 0 |
18
+| 语文六上词语 | 41 | 53 | 14→15 | 14→15 | 224→215 | 更新 14,新增 1,删除 0 |
19
+| 英语六上单词 | 291 | 197 | 147→144 | 6→6 | 147→144 | 备份后删除旧 147,重建 144 |
20
+| 英语六上表达法 | 299 | 205 | 39→54 | 6→6 | 39→54 | 备份后删除旧 39,重建 54 |
21
+
22
+语文合计:旧行 161 行全部保留原 ID,新增 17 行,删除 0 行。
23
+
24
+## 识字表数量口径
25
+
26
+| 数据集 | 教材普通识字数 | 蓝色多音字数 | 最终 WordNum |
27
+|---|---:|---:|---:|
28
+| 四年级上识字表 | 250 | 15 | 265 |
29
+| 五年级上识字表 | 200 | 9 | 209 |
30
+
31
+蓝色多音字已写入各单元 `Example`,并计入 `MiaoguoBook.WordNum`。
32
+
33
+## 英语分单元数量
34
+
35
+| 数据集 | Unit 1 | Unit 2 | Unit 3 | Unit 4 | Unit 5 | Unit 6 | 合计 |
36
+|---|---:|---:|---:|---:|---:|---:|---:|
37
+| 六上单词表 | 26 | 25 | 20 | 17 | 29 | 27 | 144 |
38
+| 六上常用表达法 | 9 | 10 | 9 | 6 | 9 | 11 | 54 |
39
+
40
+## 审计结论
41
+
42
+- 10 个 `MiaoguoBook.ID/BookIDOld` 映射全部匹配。
43
+- 语文 8 本的实际行数、`UnitNum`、`WordNum` 全部匹配源数据。
44
+- 语文每本 `OrderID` 均从 1 连续到 N,无重复;所有名称为字面教材名称,没有“语文园地一/二”等人为编号。
45
+- 更新前的 161 个语文 `HanziUnit.ID` 更新后仍全部存在。
46
+- 识字和写字源数据包含 871 个不重复汉字,全部能在 `HanziWord` 找到。
47
+- 英语 198 行逐字段比对通过;每单元 `Sort` 从 1 连续递增。
48
+- 英语未提供的音标及扩展字段按规则保存为 `NULL`。
49
+
50
+## MiaoguoLiteracy 补录
51
+
52
+对三套新版词语表的 648 个最终词语进行了依赖检查。补录前 628 个可用,以下 20 个词完全没有记录:结账、航线、热量、星斗、兄友弟恭、湘菜、粤菜、苏绣、滇剧、民居、公事、处世、回敬、落空、表明、进一步、自制、不由得、甜丝丝、入神。
53
+
54
+现已新增 20 条 `SearchType=zici` 记录,ID 为 222100~222119。每条 `JSONString` 均包含:
55
+
56
+- `ENG` 英文释义;
57
+- `CHN.HanZi`;
58
+- `CHN.PinYin[0].pinyin/explain` 拼音和完整释义;
59
+- 与字数一致的 `KaitiArr/BiShunArr2` 楷体图和笔顺动画;
60
+- `Synonym/Antonym`;
61
+- `TianKong/PinyinTone` 拼音练习数据。
62
+
63
+事务提交后按线上 `GetMiaoguoLiteracyWords` 的过滤和排序逻辑重新检查,648/648 个词均能选到具有完整 `CHN` 的记录,问题数为 0。
64
+
65
+## 产物与校验值
66
+
67
+- 更新前备份:`backups/before_2026_fall_2026-09-01T04-58-35-478Z.json`
68
+- 语文源数据 SHA-256:`1506d0546b90a317a4f78a02103da5aa064418c377dbca32994f1a143831b0c5`
69
+- 英语源数据 SHA-256:`047b2061c17313913cca97441e7a7ca0a0b8ae17ce84f453a012b33d215e488c`
70
+- dry-run 计划:`dry_run_report_2026_fall.json`
71
+- 执行报告:`apply_report_2026_fall.json`
72
+- 独立审计:`audit_report_2026_fall.json`
73
+- MiaoguoLiteracy 补录前备份:`backups/before_miaoguo_literacy_2026_fall_2026-09-01T05-27-10-536Z.json`
74
+- MiaoguoLiteracy 补录报告:`miaoguo_literacy_apply_report_2026_fall.json`
75
+- MiaoguoLiteracy 补录后审计:`miaoguo_literacy_post_apply_audit_2026_fall.json`
76
+

+ 23 - 0
.vscode/秒过知识库更新/MiaoguoLiteracy依赖检查_2026年秋季.md

@@ -0,0 +1,23 @@
1
+# MiaoguoLiteracy 缺失清单(2026 年秋季)
2
+
3
+检查时间:2026-09-01T05:28:46.583Z
4
+
5
+检查口径:检查三套新版词语表的全部最终词语;按线上接口过滤掉 `SearchType=shici/eng`,并按 `Word,SearchType DESC` 选择每个词的首条记录。除检查 `CHN` 外,还检查了接口实际使用的 `CHN.PinYin[0].pinyin/explain`。
6
+
7
+- 新版词语总数:648
8
+- 不重复词语数:648
9
+- 相比更新前新出现的不重复词语:375
10
+- 已有可用 CHN:648
11
+- 缺少可用 CHN:0
12
+
13
+## 需要新增的词语
14
+
15
+| 词语 | 数据集 | 单元 | 状态 | 相对旧版 |
16
+|---|---|---|---|---|
17
+
18
+## 补充说明
19
+
20
+另发现 47 条低优先级 `SearchType=list` 记录自身没有 CHN;这些词同时存在排序更靠前且具有完整 CHN 的 `zici` 记录,线上接口实际会使用 `zici`,所以没有列入待新增清单。
21
+
22
+本报告只做查询和分析,没有向 `MiaoguoLiteracy` 写入任何数据。
23
+

+ 44 - 0
.vscode/秒过知识库更新/MiaoguoLiteracy缺失清单_2026年秋季.md

@@ -0,0 +1,44 @@
1
+# MiaoguoLiteracy 缺失清单(2026 年秋季)
2
+
3
+> 状态:这是补录前的缺失快照。以下 20 个词已于 2026-09-01 补录完成,新增 ID 为 222100~222119;补录后 648 个新版词语已全部通过可用性审计。
4
+
5
+检查时间:2026-09-01T05:16:32.631Z
6
+
7
+检查口径:检查三套新版词语表的全部最终词语;按线上接口过滤掉 `SearchType=shici/eng`,并按 `Word,SearchType DESC` 选择每个词的首条记录。除检查 `CHN` 外,还检查了接口实际使用的 `CHN.PinYin[0].pinyin/explain`。
8
+
9
+- 新版词语总数:648
10
+- 不重复词语数:648
11
+- 相比更新前新出现的不重复词语:375
12
+- 已有可用 CHN:628
13
+- 缺少可用 CHN:20
14
+
15
+## 需要新增的词语
16
+
17
+| 词语 | 数据集 | 单元 | 状态 | 相对旧版 |
18
+|---|---|---|---|---|
19
+| 结账 | 语文四年级上词语表 | 语文园地 | NO_ROW: MiaoguoLiteracy 中没有可用记录 | 新出现 |
20
+| 航线 | 语文五年级上词语表 | 课文7 | NO_ROW: MiaoguoLiteracy 中没有可用记录 | 新出现 |
21
+| 热量 | 语文五年级上词语表 | 课文15 | NO_ROW: MiaoguoLiteracy 中没有可用记录 | 新出现 |
22
+| 星斗 | 语文五年级上词语表 | 课文18 | NO_ROW: MiaoguoLiteracy 中没有可用记录 | 新出现 |
23
+| 兄友弟恭 | 语文五年级上词语表 | 语文园地 | NO_ROW: MiaoguoLiteracy 中没有可用记录 | 新出现 |
24
+| 湘菜 | 语文五年级上词语表 | 语文园地 | NO_ROW: MiaoguoLiteracy 中没有可用记录 | 新出现 |
25
+| 粤菜 | 语文五年级上词语表 | 语文园地 | NO_ROW: MiaoguoLiteracy 中没有可用记录 | 新出现 |
26
+| 苏绣 | 语文五年级上词语表 | 语文园地 | NO_ROW: MiaoguoLiteracy 中没有可用记录 | 新出现 |
27
+| 滇剧 | 语文五年级上词语表 | 语文园地 | NO_ROW: MiaoguoLiteracy 中没有可用记录 | 新出现 |
28
+| 民居 | 语文五年级上词语表 | 语文园地 | NO_ROW: MiaoguoLiteracy 中没有可用记录 | 新出现 |
29
+| 公事 | 语文五年级上词语表 | 课文24 | NO_ROW: MiaoguoLiteracy 中没有可用记录 | 新出现 |
30
+| 处世 | 语文五年级上词语表 | 课文24 | NO_ROW: MiaoguoLiteracy 中没有可用记录 | 新出现 |
31
+| 回敬 | 语文六年级上词语表 | 课文1 | NO_ROW: MiaoguoLiteracy 中没有可用记录 | 新出现 |
32
+| 落空 | 语文六年级上词语表 | 课文7 | NO_ROW: MiaoguoLiteracy 中没有可用记录 | 新出现 |
33
+| 表明 | 语文六年级上词语表 | 课文9 | NO_ROW: MiaoguoLiteracy 中没有可用记录 | 新出现 |
34
+| 进一步 | 语文六年级上词语表 | 课文9 | NO_ROW: MiaoguoLiteracy 中没有可用记录 | 新出现 |
35
+| 自制 | 语文六年级上词语表 | 课文14 | NO_ROW: MiaoguoLiteracy 中没有可用记录 | 新出现 |
36
+| 不由得 | 语文六年级上词语表 | 课文14 | NO_ROW: MiaoguoLiteracy 中没有可用记录 | 新出现 |
37
+| 甜丝丝 | 语文六年级上词语表 | 课文15 | NO_ROW: MiaoguoLiteracy 中没有可用记录 | 新出现 |
38
+| 入神 | 语文六年级上词语表 | 课文21 | NO_ROW: MiaoguoLiteracy 中没有可用记录 | 新出现 |
39
+
40
+## 补充说明
41
+
42
+另发现 47 条低优先级 `SearchType=list` 记录自身没有 CHN;这些词同时存在排序更靠前且具有完整 CHN 的 `zici` 记录,线上接口实际会使用 `zici`,所以没有列入待新增清单。
43
+
44
+本报告本身只记录补录前的查询结果。实际写入与补录后审计见 `miaoguo_literacy_apply_report_2026_fall.json` 和 `miaoguo_literacy_post_apply_audit_2026_fall.json`。

+ 37 - 0
.vscode/秒过知识库更新/MiaoguoLiteracy补录结果_2026年秋季.md

@@ -0,0 +1,37 @@
1
+# MiaoguoLiteracy 补录结果(2026 年秋季)
2
+
3
+执行状态:20 条记录已事务写入,提交前、提交后及独立审计均通过。
4
+
5
+| ID | 词语 | 拼音 | 释义 |
6
+|---:|---|---|---|
7
+| 222100 | 结账 | jié zhàng | 结算账目,也指结算消费的费用:饭后结账。 |
8
+| 222101 | 航线 | háng xiàn | 飞机或船舶预先规划的航行路线。 |
9
+| 222102 | 热量 | rè liàng | 由于温度差别而转移的能量;也指食物经人体消化吸收后可以提供的能量。 |
10
+| 222103 | 星斗 | xīng dǒu | 星的总称:满天星斗。 |
11
+| 222104 | 兄友弟恭 | xiōng yǒu dì gōng | 哥哥对弟弟友爱,弟弟对哥哥恭敬。形容兄弟间互爱互敬。 |
12
+| 222105 | 湘菜 | xiāng cài | 湖南风味的菜肴。 |
13
+| 222106 | 粤菜 | yuè cài | 以广东风味为代表的菜肴。 |
14
+| 222107 | 苏绣 | sū xiù | 江苏苏州出产的刺绣。 |
15
+| 222108 | 滇剧 | diān jù | 云南的主要戏曲剧种之一。唱腔以皮黄为主,流行于云南以及四川、贵州的部分地区。 |
16
+| 222109 | 民居 | mín jū | 民间房舍;百姓居住的房屋。 |
17
+| 222110 | 公事 | gōng shì | 公家的事;集体的事(区别于“私事”):公事公办。 |
18
+| 222111 | 处世 | chǔ shì | 在社会上活动,跟人交往:立身处世。 |
19
+| 222112 | 回敬 | huí jìng | 回报别人给予的敬意或馈赠;也指用同样的方式回应。 |
20
+| 222113 | 落空 | luò kōng | 没有达到目的或得到预期的结果:希望落空。 |
21
+| 222114 | 表明 | biǎo míng | 清楚地表示:表明态度。 |
22
+| 222115 | 进一步 | jìn yī bù | 表示事情在原有基础上向前发展或程度提高:进一步了解情况。 |
23
+| 222116 | 自制 | zì zhì | 自己制造;也指克制自己。 |
24
+| 222117 | 不由得 | bù yóu de | 不禁、忍不住;也表示不容许。 |
25
+| 222118 | 甜丝丝 | tián sī sī | 形容有甜味;也形容感到幸福愉快。 |
26
+| 222119 | 入神 | rù shén | 对某事物兴趣浓厚而精神高度集中;也形容技艺达到精妙的境界。 |
27
+
28
+## 完整性检查
29
+
30
+- 20 条均为 `SearchType=zici`,`Author/ShiciUrl` 沿用同类记录规则保存为空字符串。
31
+- 每条的 `CHN.PinYin[0]` 都有非空 `pinyin` 和 `explain`。
32
+- 43 个不重复汉字全部从 `HanziWord` 取得现有楷体图和笔顺动画资源。
33
+- 每条 `KaitiArr/BiShunArr2` 的数量都与词语字数一致,包括“甜丝丝”的重复字。
34
+- 三套新版词语表共 648 个词,按线上接口实际查询顺序检查,已全部可用。
35
+
36
+更新前备份:`backups/before_miaoguo_literacy_2026_fall_2026-09-01T05-27-10-536Z.json`。
37
+

+ 175 - 0
.vscode/秒过知识库更新/README.md

@@ -0,0 +1,175 @@
1
+# 秒过知识库更新维护手册
2
+
3
+本目录用于每年 2 月、9 月教材改版后的秒过知识库维护。目标是:只需放入新版教材图片、整理两份源数据、依次运行 dry-run、apply、audit,即可完成更新并留下可追溯记录。
4
+
5
+## 一、不可违反的规则
6
+
7
+1. 语文 `HanziUnit` **禁止 DELETE**,只能 `UPDATE` 旧行或 `INSERT` 新行。旧 `ID` 可能已被历史试题或用户数据引用。
8
+2. 英语 `Words` 允许按目标 `BookID` 删除后重建,但必须先备份,并且所有写入都必须在事务中完成。
9
+3. 每一本更新后,都要同步校准 `MiaoguoBook.UnitNum`、`MiaoguoBook.WordNum`。
10
+4. 识字表的蓝色多音字也要写入 `HanziUnit.Example`,并计入 `WordNum`。
11
+5. 书中重复出现的名称统一写成字面值 `语文园地`,不添加“一、二”等编号;先后次序由唯一且连续的 `OrderID` 区分。
12
+6. 数据库连接复用 `src/config/dev.js`,脚本和报告不得复制、打印或另存数据库密码。
13
+7. 未通过源数据校验、BookID 映射校验、汉字字典覆盖校验时,不得开始写库。
14
+
15
+## 二、表和书籍映射
16
+
17
+程序使用 `MiaoguoBook.BookIDOld` 查找旧系统数据表的书籍 ID。字段名是 `BookIDOld`,不是口头描述中常写的 `BookOldID`。
18
+
19
+| 类别 | MiaoguoBook.ID | 数据表 | 关联字段 | 主要字段 |
20
+|---|---:|---|---|---|
21
+| 语文写字表 | 1~12 | HanziUnit | HanziBookID=BookIDOld | UnitType、Name、Example、OrderID |
22
+| 语文词语表 | 33~42 | HanziUnit | HanziBookID=BookIDOld | UnitType、Name、Example、OrderID |
23
+| 语文识字表 | 43~52 | HanziUnit | HanziBookID=BookIDOld | UnitType、Name、Example、OrderID |
24
+| 英语单词表 | 285~292、301~305 | Words | BookID=BookIDOld | Word、LessonID、LessonName、Soundmark、Translate、Sort |
25
+| 英语常用表达法 | 293~300 | Words | BookID=BookIDOld | Word、LessonID、LessonName、Translate、Sort |
26
+
27
+本次确认的 `HanziUnit.UnitType`:识字表为 1,词语表为 2,写字表为 5。
28
+
29
+## 三、教材图片转录规则
30
+
31
+### 语文
32
+
33
+- 每个教材栏目生成一个 `units` 元素,`name` 按书中栏目名写,`example` 保存这一栏的完整数据。
34
+- 识字表、写字表的 `Example` 是连续汉字,不加逗号;使用 Unicode 字符数统计 `WordNum`。
35
+- 词语表的 `Example` 使用英文逗号分隔,按非空词条数统计 `WordNum`。
36
+- 识字表要分别记录教材标注的普通识字数、蓝色多音字数;两者之和必须等于 `wordNum`。
37
+- 多次出现的 `语文园地` 保持同名,依靠数组位置最终生成 `OrderID=1..N`。
38
+
39
+### 英语
40
+
41
+- 教材图 01~08 是单词表,09~14 是常用表达法;页码和星号不写入数据库。
42
+- `LessonID` 使用 1~N,`LessonName` 使用 `Unit 1`~`Unit N`。
43
+- 每个教材条目生成一条记录;短语、地名、拆行内容仍是一条记录。
44
+- 音标由教材的 `/.../` 统一保存为 `[...]`;教材未给音标时保存 `NULL`,不能臆造。
45
+- 过去式、`also Earth` 等教材注释保留在 `Translate`。
46
+- 英文句子中的省略符统一沿用现有库格式 `ˈ`,中文标点保留教材语义。
47
+- `Sort` 在每个单元内从 1 连续递增。接口本身按 `LessonID,Sort,ID` 排序,因此不依赖自增 ID 碰巧保持顺序。
48
+- `WordRemark`、`Level`、`EnglishExplanation`、`ExampleSentence` 没有教材来源时保存 `NULL`。
49
+
50
+## 四、标准操作流程
51
+
52
+以下命令均在仓库根目录执行:
53
+
54
+```bash
55
+cd /Users/chengjie/Documents/git/miaoguo_system_server
56
+```
57
+
58
+1. 将本批次教材图片放入统一来源目录,按学科、年级、上下册命名。
59
+2. 复制上次的 `source_chinese_*.json`、`source_english_*.json`,替换为本批次数据,同时改脚本中的文件名和目标书籍映射。
60
+3. 运行只读预检:
61
+
62
+```bash
63
+node .vscode/秒过知识库更新/update_knowledge_base_2026_fall.mjs --dry-run
64
+```
65
+
66
+4. 审查 dry-run 报告,重点确认:目标 `MiaoguoBook.ID/BookIDOld`、当前行数→目标行数、`UnitNum/WordNum`、语文新增数和 `deletes=0`、英语各单元条数。
67
+5. 执行事务更新:
68
+
69
+```bash
70
+node .vscode/秒过知识库更新/update_knowledge_base_2026_fall.mjs --apply
71
+```
72
+
73
+程序会在获取数据库行锁后、第一条写入前,把目标 `MiaoguoBook`、`HanziUnit`、`Words` 的完整旧数据写入 `backups/`。之后才执行更新;任一写入或提交前逐字段核验失败,整个事务回滚。
74
+
75
+6. 事务提交后,再独立运行一次只读审计:
76
+
77
+```bash
78
+node .vscode/秒过知识库更新/update_knowledge_base_2026_fall.mjs --audit
79
+```
80
+
81
+7. 人工复核报告,并至少抽查每套数据的首行、末行、`语文园地`、英语每单元首末词。
82
+
83
+## 五、程序的语文 ID 保留策略
84
+
85
+对于每本语文书,程序按以下优先级映射新版单元:
86
+
87
+1. 同名旧行优先复用,重复名称按原排序逐个匹配;
88
+2. 仍未匹配的新版单元,复用尚未占用的旧行并更新其内容;
89
+3. 新版行数超过旧版时,差额使用 `INSERT`;
90
+4. 如果新版行数少于旧版,程序立即报错,不写库,因为这会要求删除语文旧行。
91
+
92
+所有复用的旧行保留原 `ID` 和原 `IsLocked`。新增行默认 `IsLocked=1`。所有目标行都重新写入连续的 `OrderID=1..N`。
93
+
94
+## 六、检查项和判定标准
95
+
96
+- JSON 可以解析,且数据集、书籍 ID 没有重复。
97
+- 每套源数据由 `Example/entries` 重新计算出的数量等于声明的 `wordNum`。
98
+- 识字表满足“普通识字数 + 蓝色多音字数 = WordNum”。
99
+- 数据库目标 `MiaoguoBook.BookIDOld` 与源文件一致。
100
+- 识字、写字涉及的每个汉字都能在 `HanziWord.Name` 找到;缺字时阻止写库。
101
+- 语文更新后行数等于单元数,`OrderID` 从 1 连续到 N 且无重复,逐行 `UnitType/Name/Example` 与源文件完全一致。
102
+- 英语更新后逐行 `Word/LessonID/LessonName/Soundmark/Translate/Sort` 与源文件完全一致,未提供字段仍为 `NULL`。
103
+- 所有 `MiaoguoBook.UnitNum/WordNum` 与最终数据一致。
104
+- 备份中的所有语文旧 `HanziUnit.ID` 在更新后仍然存在。
105
+
106
+## 七、备份与异常恢复
107
+
108
+- 每次 `--apply` 都会生成唯一时间戳备份,绝不能覆盖上一次备份。
109
+- 备份是写入前的完整数据库快照,包含目标书籍元数据、语文行和英语行,可用于生成逆向 SQL。
110
+- 不要直接手工执行整文件恢复。先在事务中按主键比对当前状态和备份,再决定恢复范围。
111
+- 语文仍受“禁止 DELETE”约束:恢复旧行应按 `ID` 做 `UPDATE`;本次新增行如何处理必须根据线上引用情况单独确认,不能盲删。
112
+- 英语可在事务内按目标 `BookID` 重建为备份内容,同时恢复对应 `MiaoguoBook.UnitNum/WordNum`。
113
+- 数据库提交后若发现教材源数据本身有误,应修正源 JSON、重新 dry-run,再走一次新的备份和事务更新,不要绕开程序直接改散行。
114
+
115
+## 八、MiaoguoLiteracy 词语依赖检查
116
+
117
+词语表中的每个最终词语还依赖 `MiaoguoLiteracy`。维护时不能只更新 `HanziUnit.Example`,还必须检查线上接口实际会取到的 `JSONString` 是否具有可用的 `CHN`:
118
+
119
+```bash
120
+node .vscode/秒过知识库更新/audit_miaoguo_literacy_2026_fall.mjs
121
+```
122
+
123
+检查范围应覆盖新版词语表的全部最终词语,并标记相对旧版新出现的词语。检查逻辑与 `GetMiaoguoLiteracyWords` 保持一致:排除 `SearchType=shici/eng`,按 `Word,SearchType DESC` 选取每个词的首条记录。以下情况都视为缺失并在写入前列清单:
124
+
125
+- 完全没有符合条件的记录;
126
+- `JSONString` 为空或不是合法 JSON;
127
+- `JSONString` 中没有 `CHN`;
128
+- `CHN.PinYin[0].pinyin/explain` 不完整,现有接口无法使用。
129
+
130
+缺失词语需要在 `MiaoguoLiteracy` 新增一条 `SearchType=zici` 的记录。可以选择语义和结构相近的已有词语作为模板,但必须按新词真实内容修改 `Word`、拼音、释义、组词、近反义词等字段,不能只替换顶层 `Word`。新增前先生成清单和拟写内容供人工复核;确认后再备份、事务插入并重新运行本检查,直到缺失数为 0。
131
+
132
+本次补录程序的标准命令如下;后续批次复制脚本和源文件并修改年份:
133
+
134
+```bash
135
+# 只生成完整 JSONString 和写入计划
136
+node .vscode/秒过知识库更新/update_miaoguo_literacy_2026_fall.mjs --dry-run
137
+
138
+# 备份后事务插入,并在提交前后检查全部新版词语
139
+node .vscode/秒过知识库更新/update_miaoguo_literacy_2026_fall.mjs --apply
140
+
141
+# 独立复查新增行和全部新版词语
142
+node .vscode/秒过知识库更新/update_miaoguo_literacy_2026_fall.mjs --audit
143
+```
144
+
145
+补录程序从 `HanziWord` 复用每个汉字已有的楷体图和笔顺动画。每条新增记录至少要有 `ENG`、`CHN.HanZi`、非空的 `CHN.PinYin[0].pinyin/explain`、与字数一致的 `KaitiArr/BiShunArr2`、`Synonym/Antonym`、`TianKong/PinyinTone`。
146
+
147
+## 九、常见坑
148
+
149
+- 只看 `MiaoguoBook.WordNum` 不足以证明数据正确,必须从实际 `Example/entries` 重新计数。
150
+- 旧数据大量 `OrderID=0`,不能继续依赖自增 ID 排序;本次起统一写连续 `OrderID`。
151
+- `语文园地` 同名是正确数据,不要为“唯一”而擅自编号。
152
+- 英语复合词的音标可能只标在其中一部分,必须忠实保存教材给出的内容,不补写推测音标。
153
+- 图片 OCR 只能辅助,最终必须逐页核对专名、音标、过去式和标点。
154
+- `MiaoguoLiteracy` 同一个词可能同时有 `zici` 和 `list` 等记录;低优先级 `list` 没有 `CHN` 不一定影响词语题,必须按线上查询排序判断真正选中的记录。
155
+- 任务目录可能包含真实数据库备份,提交或外发前先确认仓库的数据安全策略。
156
+
157
+## 十、本次文件说明
158
+
159
+- `source_chinese_2026_fall.json`:2026 秋季语文 8 套结构化源数据。
160
+- `source_english_2026_fall.json`:2026 秋季英语单词表和常用表达法源数据。
161
+- `update_knowledge_base_2026_fall.mjs`:校验、计划、备份、事务更新、审计程序。
162
+- `dry_run_report_2026_fall.json`:写库前更新计划和 ID 映射。
163
+- `apply_report_2026_fall.json`:实际事务、备份位置及提交前后审计。
164
+- `audit_report_2026_fall.json`:提交后的独立审计结果。
165
+- `audit_miaoguo_literacy_2026_fall.mjs`:词语依赖的只读检查程序。
166
+- `MiaoguoLiteracy缺失清单_2026年秋季.md`、`miaoguo_literacy_audit_2026_fall.json`:本批次补录前缺少可用 CHN 的历史快照。
167
+- `MiaoguoLiteracy依赖检查_2026年秋季.md`、`miaoguo_literacy_dependency_audit_current_2026_fall.json`:运行只读检查时更新的当前状态报告。
168
+- `source_miaoguo_literacy_2026_fall.json`:缺失词语的拼音、释义、英文释义和近反义词源数据。
169
+- `update_miaoguo_literacy_2026_fall.mjs`:构建完整 CHN、备份、事务补录和全词表复查程序。
170
+- `miaoguo_literacy_dry_run_2026_fall.json`:20 条补录数据的写入前预览。
171
+- `miaoguo_literacy_apply_report_2026_fall.json`:补录 ID、完整 JSONString、事务前后审计和备份位置。
172
+- `miaoguo_literacy_post_apply_audit_2026_fall.json`:补录后的独立审计报告。
173
+- `MiaoguoLiteracy补录结果_2026年秋季.md`:20 条补录词语的人工复核表。
174
+- `2026年秋季更新结果.md`:便于人工复核的最终清单。
175
+- `backups/`:每次执行前的数据库完整备份。

Разница между файлами не показана из-за своего большого размера
+ 2887 - 0
.vscode/秒过知识库更新/apply_report_2026_fall.json


+ 223 - 0
.vscode/秒过知识库更新/audit_miaoguo_literacy_2026_fall.mjs

@@ -0,0 +1,223 @@
1
+#!/usr/bin/env node
2
+
3
+import assert from "node:assert/strict";
4
+import fs from "node:fs";
5
+import path from "node:path";
6
+import { fileURLToPath } from "node:url";
7
+import mysql from "mysql2/promise";
8
+import config from "../../src/config/dev.js";
9
+
10
+const taskDir = path.dirname(fileURLToPath(import.meta.url));
11
+const sourcePath = path.join(taskDir, "source_chinese_2026_fall.json");
12
+const applyReportPath = path.join(taskDir, "apply_report_2026_fall.json");
13
+const jsonReportPath = path.join(
14
+  taskDir,
15
+  "miaoguo_literacy_dependency_audit_current_2026_fall.json",
16
+);
17
+const markdownReportPath = path.join(taskDir, "MiaoguoLiteracy依赖检查_2026年秋季.md");
18
+
19
+const sources = JSON.parse(fs.readFileSync(sourcePath, "utf8")).filter(
20
+  (source) => source.unitType === 2,
21
+);
22
+const applyReport = JSON.parse(fs.readFileSync(applyReportPath, "utf8"));
23
+const backup = JSON.parse(fs.readFileSync(applyReport.backupPath, "utf8"));
24
+
25
+function splitWords(example) {
26
+  return example.split(",").filter(Boolean);
27
+}
28
+
29
+function inspectJson(row) {
30
+  if (!row) return { status: "NO_ROW", detail: "MiaoguoLiteracy 中没有可用记录" };
31
+  if (!row.JSONString) return { status: "EMPTY_JSON", detail: "JSONString 为空" };
32
+  try {
33
+    const json = JSON.parse(row.JSONString);
34
+    if (!json.CHN) return { status: "MISSING_CHN", detail: "JSONString 中不存在 CHN" };
35
+    if (
36
+      !Array.isArray(json.CHN.PinYin) ||
37
+      !json.CHN.PinYin[0]?.pinyin ||
38
+      !json.CHN.PinYin[0]?.explain
39
+    ) {
40
+      return {
41
+        status: "INVALID_CHN_STRUCTURE",
42
+        detail: "CHN.PinYin[0].pinyin/explain 不完整,现有接口无法使用",
43
+      };
44
+    }
45
+    return { status: "OK", detail: "存在可用 CHN" };
46
+  } catch (error) {
47
+    return { status: "INVALID_JSON", detail: error.message };
48
+  }
49
+}
50
+
51
+function writeReports(report) {
52
+  fs.writeFileSync(jsonReportPath, `${JSON.stringify(report, null, 2)}\n`, "utf8");
53
+  const lines = [
54
+    "# MiaoguoLiteracy 缺失清单(2026 年秋季)",
55
+    "",
56
+    `检查时间:${report.generatedAt}`,
57
+    "",
58
+    "检查口径:检查三套新版词语表的全部最终词语;按线上接口过滤掉 `SearchType=shici/eng`,并按 `Word,SearchType DESC` 选择每个词的首条记录。除检查 `CHN` 外,还检查了接口实际使用的 `CHN.PinYin[0].pinyin/explain`。",
59
+    "",
60
+    `- 新版词语总数:${report.summary.finalOccurrences}`,
61
+    `- 不重复词语数:${report.summary.uniqueFinalWords}`,
62
+    `- 相比更新前新出现的不重复词语:${report.summary.uniqueNewlyIntroducedWords}`,
63
+    `- 已有可用 CHN:${report.summary.usableWords}`,
64
+    `- 缺少可用 CHN:${report.summary.problemWords}`,
65
+    "",
66
+    "## 需要新增的词语",
67
+    "",
68
+    "| 词语 | 数据集 | 单元 | 状态 | 相对旧版 |",
69
+    "|---|---|---|---|---|",
70
+  ];
71
+  for (const problem of report.problems) {
72
+    lines.push(
73
+      `| ${problem.word} | ${problem.locations.map((item) => item.label).join("、")} | ${problem.locations.map((item) => item.unit).join("、")} | ${problem.status}: ${problem.detail} | ${problem.isNewlyIntroduced ? "新出现" : "旧版已有"} |`,
74
+    );
75
+  }
76
+  lines.push(
77
+    "",
78
+    "## 补充说明",
79
+    "",
80
+    `另发现 ${report.nonBlockingLowerPriorityIssues.length} 条低优先级 \`SearchType=list\` 记录自身没有 CHN;这些词同时存在排序更靠前且具有完整 CHN 的 \`zici\` 记录,线上接口实际会使用 \`zici\`,所以没有列入待新增清单。`,
81
+    "",
82
+    "本报告只做查询和分析,没有向 `MiaoguoLiteracy` 写入任何数据。",
83
+    "",
84
+  );
85
+  fs.writeFileSync(markdownReportPath, `${lines.join("\n")}\n`, "utf8");
86
+}
87
+
88
+async function main() {
89
+  assert.equal(sources.length, 3, "本批次应有三套语文词语表");
90
+  const oldWordsByBook = new Map(
91
+    sources.map((source) => [
92
+      source.bookIdOld,
93
+      new Set(
94
+        backup.hanziRows
95
+          .filter((row) => row.HanziBookID === source.bookIdOld)
96
+          .flatMap((row) => splitWords(row.Example ?? "")),
97
+      ),
98
+    ]),
99
+  );
100
+
101
+  const references = new Map();
102
+  for (const source of sources) {
103
+    const oldWords = oldWordsByBook.get(source.bookIdOld);
104
+    for (const unit of source.units) {
105
+      for (const word of splitWords(unit.example)) {
106
+        const items = references.get(word) ?? [];
107
+        items.push({
108
+          label: source.label,
109
+          bookIdOld: source.bookIdOld,
110
+          unit: unit.name,
111
+          isNewlyIntroduced: !oldWords.has(word),
112
+        });
113
+        references.set(word, items);
114
+      }
115
+    }
116
+  }
117
+
118
+  const words = [...references.keys()];
119
+  const connection = await mysql.createConnection(config.database);
120
+  try {
121
+    const [rows] = await connection.query(
122
+      `SELECT ID,Word,SearchType,JSONString
123
+         FROM MiaoguoLiteracy
124
+        WHERE Word IN (?)
125
+          AND SearchType<>?
126
+          AND SearchType<>?
127
+        ORDER BY Word,SearchType DESC,ID`,
128
+      [words, "shici", "eng"],
129
+    );
130
+
131
+    const rowsByWord = new Map();
132
+    for (const row of rows) {
133
+      const items = rowsByWord.get(row.Word) ?? [];
134
+      items.push(row);
135
+      rowsByWord.set(row.Word, items);
136
+    }
137
+
138
+    const problems = [];
139
+    const nonBlockingLowerPriorityIssues = [];
140
+    for (const word of words) {
141
+      const wordRows = rowsByWord.get(word) ?? [];
142
+      const selectedRow = wordRows[0];
143
+      const selectedCheck = inspectJson(selectedRow);
144
+      const locations = references.get(word);
145
+      if (selectedCheck.status !== "OK") {
146
+        problems.push({
147
+          word,
148
+          status: selectedCheck.status,
149
+          detail: selectedCheck.detail,
150
+          selectedRow: selectedRow
151
+            ? { id: selectedRow.ID, searchType: selectedRow.SearchType }
152
+            : null,
153
+          rowCount: wordRows.length,
154
+          isNewlyIntroduced: locations.some((item) => item.isNewlyIntroduced),
155
+          locations,
156
+        });
157
+      }
158
+      for (const row of wordRows.slice(1)) {
159
+        const check = inspectJson(row);
160
+        if (check.status !== "OK") {
161
+          nonBlockingLowerPriorityIssues.push({
162
+            word,
163
+            id: row.ID,
164
+            searchType: row.SearchType,
165
+            status: check.status,
166
+            detail: check.detail,
167
+            selectedRowId: selectedRow?.ID ?? null,
168
+          });
169
+        }
170
+      }
171
+    }
172
+
173
+    const uniqueNewlyIntroducedWords = words.filter((word) =>
174
+      references.get(word).some((item) => item.isNewlyIntroduced),
175
+    ).length;
176
+    const report = {
177
+      generatedAt: new Date().toISOString(),
178
+      readOnly: true,
179
+      querySemantics:
180
+        "与 GetMiaoguoLiteracyWords 一致:排除 SearchType=shici/eng,按 Word,SearchType DESC 取词语首条记录",
181
+      summary: {
182
+        finalOccurrences: sources.reduce((total, source) => total + source.wordNum, 0),
183
+        uniqueFinalWords: words.length,
184
+        uniqueNewlyIntroducedWords,
185
+        eligibleDatabaseRows: rows.length,
186
+        usableWords: words.length - problems.length,
187
+        problemWords: problems.length,
188
+      },
189
+      datasets: sources.map((source) => ({
190
+        label: source.label,
191
+        bookIdOld: source.bookIdOld,
192
+        finalWords: source.wordNum,
193
+        oldUniqueWords: oldWordsByBook.get(source.bookIdOld).size,
194
+        newlyIntroducedOccurrences: source.units
195
+          .flatMap((unit) => splitWords(unit.example))
196
+          .filter((word) => !oldWordsByBook.get(source.bookIdOld).has(word)).length,
197
+      })),
198
+      problems,
199
+      nonBlockingLowerPriorityIssues,
200
+    };
201
+    writeReports(report);
202
+    console.log(
203
+      JSON.stringify(
204
+        {
205
+          summary: report.summary,
206
+          missingWords: problems.map((problem) => problem.word),
207
+          jsonReportPath,
208
+          markdownReportPath,
209
+        },
210
+        null,
211
+        2,
212
+      ),
213
+    );
214
+    if (problems.length > 0) process.exitCode = 2;
215
+  } finally {
216
+    await connection.end();
217
+  }
218
+}
219
+
220
+main().catch((error) => {
221
+  console.error(error);
222
+  process.exitCode = 1;
223
+});

+ 265 - 0
.vscode/秒过知识库更新/audit_report_2026_fall.json

@@ -0,0 +1,265 @@
1
+{
2
+  "generatedAt": "2026-09-01T05:01:43.519Z",
3
+  "mode": "audit",
4
+  "dictionaryCheck": {
5
+    "checkedDistinctCharacters": 871,
6
+    "missing": []
7
+  },
8
+  "chineseIdPreservation": {
9
+    "oldRows": 161,
10
+    "oldIdsStillPresent": 161,
11
+    "missingIds": [],
12
+    "newRows": 17
13
+  },
14
+  "audit": {
15
+    "passed": true,
16
+    "books": [
17
+      {
18
+        "id": 49,
19
+        "bookName": "识字",
20
+        "bookIdOld": 67,
21
+        "unitNum": 31,
22
+        "wordNum": 265
23
+      },
24
+      {
25
+        "id": 7,
26
+        "bookName": "写字",
27
+        "bookIdOld": 19,
28
+        "unitNum": 25,
29
+        "wordNum": 250
30
+      },
31
+      {
32
+        "id": 37,
33
+        "bookName": "词语",
34
+        "bookIdOld": 49,
35
+        "unitNum": 21,
36
+        "wordNum": 220
37
+      },
38
+      {
39
+        "id": 51,
40
+        "bookName": "识字",
41
+        "bookIdOld": 69,
42
+        "unitNum": 27,
43
+        "wordNum": 209
44
+      },
45
+      {
46
+        "id": 9,
47
+        "bookName": "写字",
48
+        "bookIdOld": 21,
49
+        "unitNum": 22,
50
+        "wordNum": 220
51
+      },
52
+      {
53
+        "id": 39,
54
+        "bookName": "词语",
55
+        "bookIdOld": 51,
56
+        "unitNum": 18,
57
+        "wordNum": 213
58
+      },
59
+      {
60
+        "id": 11,
61
+        "bookName": "写字",
62
+        "bookIdOld": 23,
63
+        "unitNum": 19,
64
+        "wordNum": 180
65
+      },
66
+      {
67
+        "id": 41,
68
+        "bookName": "词语",
69
+        "bookIdOld": 53,
70
+        "unitNum": 15,
71
+        "wordNum": 215
72
+      },
73
+      {
74
+        "id": 291,
75
+        "bookName": "单元词汇",
76
+        "bookIdOld": 197,
77
+        "unitNum": 6,
78
+        "wordNum": 144
79
+      },
80
+      {
81
+        "id": 299,
82
+        "bookName": "常用表达法",
83
+        "bookIdOld": 205,
84
+        "unitNum": 6,
85
+        "wordNum": 54
86
+      }
87
+    ],
88
+    "chinese": [
89
+      {
90
+        "label": "语文四年级上识字表",
91
+        "miaoguoBookId": 49,
92
+        "bookIdOld": 67,
93
+        "rows": 31,
94
+        "unitNum": 31,
95
+        "wordNum": 265,
96
+        "orderIdRange": [
97
+          1,
98
+          31
99
+        ],
100
+        "duplicateOrderIds": 0
101
+      },
102
+      {
103
+        "label": "语文四年级上写字表",
104
+        "miaoguoBookId": 7,
105
+        "bookIdOld": 19,
106
+        "rows": 25,
107
+        "unitNum": 25,
108
+        "wordNum": 250,
109
+        "orderIdRange": [
110
+          1,
111
+          25
112
+        ],
113
+        "duplicateOrderIds": 0
114
+      },
115
+      {
116
+        "label": "语文四年级上词语表",
117
+        "miaoguoBookId": 37,
118
+        "bookIdOld": 49,
119
+        "rows": 21,
120
+        "unitNum": 21,
121
+        "wordNum": 220,
122
+        "orderIdRange": [
123
+          1,
124
+          21
125
+        ],
126
+        "duplicateOrderIds": 0
127
+      },
128
+      {
129
+        "label": "语文五年级上识字表",
130
+        "miaoguoBookId": 51,
131
+        "bookIdOld": 69,
132
+        "rows": 27,
133
+        "unitNum": 27,
134
+        "wordNum": 209,
135
+        "orderIdRange": [
136
+          1,
137
+          27
138
+        ],
139
+        "duplicateOrderIds": 0
140
+      },
141
+      {
142
+        "label": "语文五年级上写字表",
143
+        "miaoguoBookId": 9,
144
+        "bookIdOld": 21,
145
+        "rows": 22,
146
+        "unitNum": 22,
147
+        "wordNum": 220,
148
+        "orderIdRange": [
149
+          1,
150
+          22
151
+        ],
152
+        "duplicateOrderIds": 0
153
+      },
154
+      {
155
+        "label": "语文五年级上词语表",
156
+        "miaoguoBookId": 39,
157
+        "bookIdOld": 51,
158
+        "rows": 18,
159
+        "unitNum": 18,
160
+        "wordNum": 213,
161
+        "orderIdRange": [
162
+          1,
163
+          18
164
+        ],
165
+        "duplicateOrderIds": 0
166
+      },
167
+      {
168
+        "label": "语文六年级上写字表",
169
+        "miaoguoBookId": 11,
170
+        "bookIdOld": 23,
171
+        "rows": 19,
172
+        "unitNum": 19,
173
+        "wordNum": 180,
174
+        "orderIdRange": [
175
+          1,
176
+          19
177
+        ],
178
+        "duplicateOrderIds": 0
179
+      },
180
+      {
181
+        "label": "语文六年级上词语表",
182
+        "miaoguoBookId": 41,
183
+        "bookIdOld": 53,
184
+        "rows": 15,
185
+        "unitNum": 15,
186
+        "wordNum": 215,
187
+        "orderIdRange": [
188
+          1,
189
+          15
190
+        ],
191
+        "duplicateOrderIds": 0
192
+      }
193
+    ],
194
+    "english": [
195
+      {
196
+        "label": "英语六年级上单词表",
197
+        "miaoguoBookId": 291,
198
+        "bookIdOld": 197,
199
+        "rows": 144,
200
+        "unitNum": 6,
201
+        "wordNum": 144,
202
+        "perUnit": [
203
+          {
204
+            "lessonId": 1,
205
+            "rows": 26
206
+          },
207
+          {
208
+            "lessonId": 2,
209
+            "rows": 25
210
+          },
211
+          {
212
+            "lessonId": 3,
213
+            "rows": 20
214
+          },
215
+          {
216
+            "lessonId": 4,
217
+            "rows": 17
218
+          },
219
+          {
220
+            "lessonId": 5,
221
+            "rows": 29
222
+          },
223
+          {
224
+            "lessonId": 6,
225
+            "rows": 27
226
+          }
227
+        ]
228
+      },
229
+      {
230
+        "label": "英语六年级上常用表达法",
231
+        "miaoguoBookId": 299,
232
+        "bookIdOld": 205,
233
+        "rows": 54,
234
+        "unitNum": 6,
235
+        "wordNum": 54,
236
+        "perUnit": [
237
+          {
238
+            "lessonId": 1,
239
+            "rows": 9
240
+          },
241
+          {
242
+            "lessonId": 2,
243
+            "rows": 10
244
+          },
245
+          {
246
+            "lessonId": 3,
247
+            "rows": 9
248
+          },
249
+          {
250
+            "lessonId": 4,
251
+            "rows": 6
252
+          },
253
+          {
254
+            "lessonId": 5,
255
+            "rows": 9
256
+          },
257
+          {
258
+            "lessonId": 6,
259
+            "rows": 11
260
+          }
261
+        ]
262
+      }
263
+    ]
264
+  }
265
+}

Разница между файлами не показана из-за своего большого размера
+ 4289 - 0
.vscode/秒过知识库更新/backups/before_2026_fall_2026-09-01T04-58-35-478Z.json


Разница между файлами не показана из-за своего большого размера
+ 354 - 0
.vscode/秒过知识库更新/backups/before_miaoguo_literacy_2026_fall_2026-09-01T05-27-10-536Z.json


Разница между файлами не показана из-за своего большого размера
+ 2380 - 0
.vscode/秒过知识库更新/dry_run_report_2026_fall.json


Разница между файлами не показана из-за своего большого размера
+ 1528 - 0
.vscode/秒过知识库更新/miaoguo_literacy_apply_report_2026_fall.json


+ 736 - 0
.vscode/秒过知识库更新/miaoguo_literacy_audit_2026_fall.json

@@ -0,0 +1,736 @@
1
+{
2
+  "generatedAt": "2026-09-01T05:16:32.631Z",
3
+  "readOnly": true,
4
+  "querySemantics": "与 GetMiaoguoLiteracyWords 一致:排除 SearchType=shici/eng,按 Word,SearchType DESC 取词语首条记录",
5
+  "summary": {
6
+    "finalOccurrences": 648,
7
+    "uniqueFinalWords": 648,
8
+    "uniqueNewlyIntroducedWords": 375,
9
+    "eligibleDatabaseRows": 675,
10
+    "usableWords": 628,
11
+    "problemWords": 20
12
+  },
13
+  "datasets": [
14
+    {
15
+      "label": "语文四年级上词语表",
16
+      "bookIdOld": 49,
17
+      "finalWords": 220,
18
+      "oldUniqueWords": 241,
19
+      "newlyIntroducedOccurrences": 135
20
+    },
21
+    {
22
+      "label": "语文五年级上词语表",
23
+      "bookIdOld": 51,
24
+      "finalWords": 213,
25
+      "oldUniqueWords": 222,
26
+      "newlyIntroducedOccurrences": 120
27
+    },
28
+    {
29
+      "label": "语文六年级上词语表",
30
+      "bookIdOld": 53,
31
+      "finalWords": 215,
32
+      "oldUniqueWords": 224,
33
+      "newlyIntroducedOccurrences": 120
34
+    }
35
+  ],
36
+  "problems": [
37
+    {
38
+      "word": "结账",
39
+      "status": "NO_ROW",
40
+      "detail": "MiaoguoLiteracy 中没有可用记录",
41
+      "selectedRow": null,
42
+      "rowCount": 0,
43
+      "isNewlyIntroduced": true,
44
+      "locations": [
45
+        {
46
+          "label": "语文四年级上词语表",
47
+          "bookIdOld": 49,
48
+          "unit": "语文园地",
49
+          "isNewlyIntroduced": true
50
+        }
51
+      ]
52
+    },
53
+    {
54
+      "word": "航线",
55
+      "status": "NO_ROW",
56
+      "detail": "MiaoguoLiteracy 中没有可用记录",
57
+      "selectedRow": null,
58
+      "rowCount": 0,
59
+      "isNewlyIntroduced": true,
60
+      "locations": [
61
+        {
62
+          "label": "语文五年级上词语表",
63
+          "bookIdOld": 51,
64
+          "unit": "课文7",
65
+          "isNewlyIntroduced": true
66
+        }
67
+      ]
68
+    },
69
+    {
70
+      "word": "热量",
71
+      "status": "NO_ROW",
72
+      "detail": "MiaoguoLiteracy 中没有可用记录",
73
+      "selectedRow": null,
74
+      "rowCount": 0,
75
+      "isNewlyIntroduced": true,
76
+      "locations": [
77
+        {
78
+          "label": "语文五年级上词语表",
79
+          "bookIdOld": 51,
80
+          "unit": "课文15",
81
+          "isNewlyIntroduced": true
82
+        }
83
+      ]
84
+    },
85
+    {
86
+      "word": "星斗",
87
+      "status": "NO_ROW",
88
+      "detail": "MiaoguoLiteracy 中没有可用记录",
89
+      "selectedRow": null,
90
+      "rowCount": 0,
91
+      "isNewlyIntroduced": true,
92
+      "locations": [
93
+        {
94
+          "label": "语文五年级上词语表",
95
+          "bookIdOld": 51,
96
+          "unit": "课文18",
97
+          "isNewlyIntroduced": true
98
+        }
99
+      ]
100
+    },
101
+    {
102
+      "word": "兄友弟恭",
103
+      "status": "NO_ROW",
104
+      "detail": "MiaoguoLiteracy 中没有可用记录",
105
+      "selectedRow": null,
106
+      "rowCount": 0,
107
+      "isNewlyIntroduced": true,
108
+      "locations": [
109
+        {
110
+          "label": "语文五年级上词语表",
111
+          "bookIdOld": 51,
112
+          "unit": "语文园地",
113
+          "isNewlyIntroduced": true
114
+        }
115
+      ]
116
+    },
117
+    {
118
+      "word": "湘菜",
119
+      "status": "NO_ROW",
120
+      "detail": "MiaoguoLiteracy 中没有可用记录",
121
+      "selectedRow": null,
122
+      "rowCount": 0,
123
+      "isNewlyIntroduced": true,
124
+      "locations": [
125
+        {
126
+          "label": "语文五年级上词语表",
127
+          "bookIdOld": 51,
128
+          "unit": "语文园地",
129
+          "isNewlyIntroduced": true
130
+        }
131
+      ]
132
+    },
133
+    {
134
+      "word": "粤菜",
135
+      "status": "NO_ROW",
136
+      "detail": "MiaoguoLiteracy 中没有可用记录",
137
+      "selectedRow": null,
138
+      "rowCount": 0,
139
+      "isNewlyIntroduced": true,
140
+      "locations": [
141
+        {
142
+          "label": "语文五年级上词语表",
143
+          "bookIdOld": 51,
144
+          "unit": "语文园地",
145
+          "isNewlyIntroduced": true
146
+        }
147
+      ]
148
+    },
149
+    {
150
+      "word": "苏绣",
151
+      "status": "NO_ROW",
152
+      "detail": "MiaoguoLiteracy 中没有可用记录",
153
+      "selectedRow": null,
154
+      "rowCount": 0,
155
+      "isNewlyIntroduced": true,
156
+      "locations": [
157
+        {
158
+          "label": "语文五年级上词语表",
159
+          "bookIdOld": 51,
160
+          "unit": "语文园地",
161
+          "isNewlyIntroduced": true
162
+        }
163
+      ]
164
+    },
165
+    {
166
+      "word": "滇剧",
167
+      "status": "NO_ROW",
168
+      "detail": "MiaoguoLiteracy 中没有可用记录",
169
+      "selectedRow": null,
170
+      "rowCount": 0,
171
+      "isNewlyIntroduced": true,
172
+      "locations": [
173
+        {
174
+          "label": "语文五年级上词语表",
175
+          "bookIdOld": 51,
176
+          "unit": "语文园地",
177
+          "isNewlyIntroduced": true
178
+        }
179
+      ]
180
+    },
181
+    {
182
+      "word": "民居",
183
+      "status": "NO_ROW",
184
+      "detail": "MiaoguoLiteracy 中没有可用记录",
185
+      "selectedRow": null,
186
+      "rowCount": 0,
187
+      "isNewlyIntroduced": true,
188
+      "locations": [
189
+        {
190
+          "label": "语文五年级上词语表",
191
+          "bookIdOld": 51,
192
+          "unit": "语文园地",
193
+          "isNewlyIntroduced": true
194
+        }
195
+      ]
196
+    },
197
+    {
198
+      "word": "公事",
199
+      "status": "NO_ROW",
200
+      "detail": "MiaoguoLiteracy 中没有可用记录",
201
+      "selectedRow": null,
202
+      "rowCount": 0,
203
+      "isNewlyIntroduced": true,
204
+      "locations": [
205
+        {
206
+          "label": "语文五年级上词语表",
207
+          "bookIdOld": 51,
208
+          "unit": "课文24",
209
+          "isNewlyIntroduced": true
210
+        }
211
+      ]
212
+    },
213
+    {
214
+      "word": "处世",
215
+      "status": "NO_ROW",
216
+      "detail": "MiaoguoLiteracy 中没有可用记录",
217
+      "selectedRow": null,
218
+      "rowCount": 0,
219
+      "isNewlyIntroduced": true,
220
+      "locations": [
221
+        {
222
+          "label": "语文五年级上词语表",
223
+          "bookIdOld": 51,
224
+          "unit": "课文24",
225
+          "isNewlyIntroduced": true
226
+        }
227
+      ]
228
+    },
229
+    {
230
+      "word": "回敬",
231
+      "status": "NO_ROW",
232
+      "detail": "MiaoguoLiteracy 中没有可用记录",
233
+      "selectedRow": null,
234
+      "rowCount": 0,
235
+      "isNewlyIntroduced": true,
236
+      "locations": [
237
+        {
238
+          "label": "语文六年级上词语表",
239
+          "bookIdOld": 53,
240
+          "unit": "课文1",
241
+          "isNewlyIntroduced": true
242
+        }
243
+      ]
244
+    },
245
+    {
246
+      "word": "落空",
247
+      "status": "NO_ROW",
248
+      "detail": "MiaoguoLiteracy 中没有可用记录",
249
+      "selectedRow": null,
250
+      "rowCount": 0,
251
+      "isNewlyIntroduced": true,
252
+      "locations": [
253
+        {
254
+          "label": "语文六年级上词语表",
255
+          "bookIdOld": 53,
256
+          "unit": "课文7",
257
+          "isNewlyIntroduced": true
258
+        }
259
+      ]
260
+    },
261
+    {
262
+      "word": "表明",
263
+      "status": "NO_ROW",
264
+      "detail": "MiaoguoLiteracy 中没有可用记录",
265
+      "selectedRow": null,
266
+      "rowCount": 0,
267
+      "isNewlyIntroduced": true,
268
+      "locations": [
269
+        {
270
+          "label": "语文六年级上词语表",
271
+          "bookIdOld": 53,
272
+          "unit": "课文9",
273
+          "isNewlyIntroduced": true
274
+        }
275
+      ]
276
+    },
277
+    {
278
+      "word": "进一步",
279
+      "status": "NO_ROW",
280
+      "detail": "MiaoguoLiteracy 中没有可用记录",
281
+      "selectedRow": null,
282
+      "rowCount": 0,
283
+      "isNewlyIntroduced": true,
284
+      "locations": [
285
+        {
286
+          "label": "语文六年级上词语表",
287
+          "bookIdOld": 53,
288
+          "unit": "课文9",
289
+          "isNewlyIntroduced": true
290
+        }
291
+      ]
292
+    },
293
+    {
294
+      "word": "自制",
295
+      "status": "NO_ROW",
296
+      "detail": "MiaoguoLiteracy 中没有可用记录",
297
+      "selectedRow": null,
298
+      "rowCount": 0,
299
+      "isNewlyIntroduced": true,
300
+      "locations": [
301
+        {
302
+          "label": "语文六年级上词语表",
303
+          "bookIdOld": 53,
304
+          "unit": "课文14",
305
+          "isNewlyIntroduced": true
306
+        }
307
+      ]
308
+    },
309
+    {
310
+      "word": "不由得",
311
+      "status": "NO_ROW",
312
+      "detail": "MiaoguoLiteracy 中没有可用记录",
313
+      "selectedRow": null,
314
+      "rowCount": 0,
315
+      "isNewlyIntroduced": true,
316
+      "locations": [
317
+        {
318
+          "label": "语文六年级上词语表",
319
+          "bookIdOld": 53,
320
+          "unit": "课文14",
321
+          "isNewlyIntroduced": true
322
+        }
323
+      ]
324
+    },
325
+    {
326
+      "word": "甜丝丝",
327
+      "status": "NO_ROW",
328
+      "detail": "MiaoguoLiteracy 中没有可用记录",
329
+      "selectedRow": null,
330
+      "rowCount": 0,
331
+      "isNewlyIntroduced": true,
332
+      "locations": [
333
+        {
334
+          "label": "语文六年级上词语表",
335
+          "bookIdOld": 53,
336
+          "unit": "课文15",
337
+          "isNewlyIntroduced": true
338
+        }
339
+      ]
340
+    },
341
+    {
342
+      "word": "入神",
343
+      "status": "NO_ROW",
344
+      "detail": "MiaoguoLiteracy 中没有可用记录",
345
+      "selectedRow": null,
346
+      "rowCount": 0,
347
+      "isNewlyIntroduced": true,
348
+      "locations": [
349
+        {
350
+          "label": "语文六年级上词语表",
351
+          "bookIdOld": 53,
352
+          "unit": "课文21",
353
+          "isNewlyIntroduced": true
354
+        }
355
+      ]
356
+    }
357
+  ],
358
+  "nonBlockingLowerPriorityIssues": [
359
+    {
360
+      "word": "蚊子",
361
+      "id": 1214,
362
+      "searchType": "list",
363
+      "status": "MISSING_CHN",
364
+      "detail": "JSONString 中不存在 CHN",
365
+      "selectedRowId": 1215
366
+    },
367
+    {
368
+      "word": "苍蝇",
369
+      "id": 947,
370
+      "searchType": "list",
371
+      "status": "MISSING_CHN",
372
+      "detail": "JSONString 中不存在 CHN",
373
+      "selectedRowId": 948
374
+    },
375
+    {
376
+      "word": "配合",
377
+      "id": 60074,
378
+      "searchType": "list",
379
+      "status": "MISSING_CHN",
380
+      "detail": "JSONString 中不存在 CHN",
381
+      "selectedRowId": 60075
382
+    },
383
+    {
384
+      "word": "能够",
385
+      "id": 486,
386
+      "searchType": "list",
387
+      "status": "MISSING_CHN",
388
+      "detail": "JSONString 中不存在 CHN",
389
+      "selectedRowId": 487
390
+    },
391
+    {
392
+      "word": "玻璃",
393
+      "id": 60269,
394
+      "searchType": "list",
395
+      "status": "MISSING_CHN",
396
+      "detail": "JSONString 中不存在 CHN",
397
+      "selectedRowId": 60270
398
+    },
399
+    {
400
+      "word": "玫瑰",
401
+      "id": 5799,
402
+      "searchType": "list",
403
+      "status": "MISSING_CHN",
404
+      "detail": "JSONString 中不存在 CHN",
405
+      "selectedRowId": 5800
406
+    },
407
+    {
408
+      "word": "牡丹",
409
+      "id": 5815,
410
+      "searchType": "list",
411
+      "status": "MISSING_CHN",
412
+      "detail": "JSONString 中不存在 CHN",
413
+      "selectedRowId": 5816
414
+    },
415
+    {
416
+      "word": "茉莉",
417
+      "id": 4714,
418
+      "searchType": "list",
419
+      "status": "MISSING_CHN",
420
+      "detail": "JSONString 中不存在 CHN",
421
+      "selectedRowId": 4715
422
+    },
423
+    {
424
+      "word": "海棠",
425
+      "id": 61389,
426
+      "searchType": "list",
427
+      "status": "MISSING_CHN",
428
+      "detail": "JSONString 中不存在 CHN",
429
+      "selectedRowId": 61390
430
+    },
431
+    {
432
+      "word": "无可奈何",
433
+      "id": 2501,
434
+      "searchType": "list",
435
+      "status": "MISSING_CHN",
436
+      "detail": "JSONString 中不存在 CHN",
437
+      "selectedRowId": 2502
438
+    },
439
+    {
440
+      "word": "笑呵呵",
441
+      "id": 91955,
442
+      "searchType": "list",
443
+      "status": "MISSING_CHN",
444
+      "detail": "JSONString 中不存在 CHN",
445
+      "selectedRowId": 91956
446
+    },
447
+    {
448
+      "word": "崇山峻岭",
449
+      "id": 59773,
450
+      "searchType": "list",
451
+      "status": "MISSING_CHN",
452
+      "detail": "JSONString 中不存在 CHN",
453
+      "selectedRowId": 59774
454
+    },
455
+    {
456
+      "word": "自然",
457
+      "id": 86300,
458
+      "searchType": "list",
459
+      "status": "MISSING_CHN",
460
+      "detail": "JSONString 中不存在 CHN",
461
+      "selectedRowId": 86301
462
+    },
463
+    {
464
+      "word": "镜子",
465
+      "id": 885,
466
+      "searchType": "list",
467
+      "status": "MISSING_CHN",
468
+      "detail": "JSONString 中不存在 CHN",
469
+      "selectedRowId": 886
470
+    },
471
+    {
472
+      "word": "狮子",
473
+      "id": 59463,
474
+      "searchType": "list",
475
+      "status": "MISSING_CHN",
476
+      "detail": "JSONString 中不存在 CHN",
477
+      "selectedRowId": 59464
478
+    },
479
+    {
480
+      "word": "默默",
481
+      "id": 90597,
482
+      "searchType": "list",
483
+      "status": "MISSING_CHN",
484
+      "detail": "JSONString 中不存在 CHN",
485
+      "selectedRowId": 156357
486
+    },
487
+    {
488
+      "word": "桂花",
489
+      "id": 4143,
490
+      "searchType": "list",
491
+      "status": "MISSING_CHN",
492
+      "detail": "JSONString 中不存在 CHN",
493
+      "selectedRowId": 4144
494
+    },
495
+    {
496
+      "word": "故乡",
497
+      "id": 81493,
498
+      "searchType": "list",
499
+      "status": "MISSING_CHN",
500
+      "detail": "JSONString 中不存在 CHN",
501
+      "selectedRowId": 81494
502
+    },
503
+    {
504
+      "word": "成熟",
505
+      "id": 111,
506
+      "searchType": "list",
507
+      "status": "MISSING_CHN",
508
+      "detail": "JSONString 中不存在 CHN",
509
+      "selectedRowId": 112
510
+    },
511
+    {
512
+      "word": "果实",
513
+      "id": 823,
514
+      "searchType": "list",
515
+      "status": "MISSING_CHN",
516
+      "detail": "JSONString 中不存在 CHN",
517
+      "selectedRowId": 825
518
+    },
519
+    {
520
+      "word": "距离",
521
+      "id": 59849,
522
+      "searchType": "list",
523
+      "status": "MISSING_CHN",
524
+      "detail": "JSONString 中不存在 CHN",
525
+      "selectedRowId": 59850
526
+    },
527
+    {
528
+      "word": "拒绝",
529
+      "id": 74078,
530
+      "searchType": "list",
531
+      "status": "MISSING_CHN",
532
+      "detail": "JSONString 中不存在 CHN",
533
+      "selectedRowId": 74079
534
+    },
535
+    {
536
+      "word": "小心翼翼",
537
+      "id": 74851,
538
+      "searchType": "list",
539
+      "status": "MISSING_CHN",
540
+      "detail": "JSONString 中不存在 CHN",
541
+      "selectedRowId": 1462
542
+    },
543
+    {
544
+      "word": "凌晨",
545
+      "id": 61747,
546
+      "searchType": "list",
547
+      "status": "MISSING_CHN",
548
+      "detail": "JSONString 中不存在 CHN",
549
+      "selectedRowId": 61748
550
+    },
551
+    {
552
+      "word": "岗位",
553
+      "id": 83719,
554
+      "searchType": "list",
555
+      "status": "MISSING_CHN",
556
+      "detail": "JSONString 中不存在 CHN",
557
+      "selectedRowId": 83720
558
+    },
559
+    {
560
+      "word": "忠于职守",
561
+      "id": 158695,
562
+      "searchType": "list",
563
+      "status": "MISSING_CHN",
564
+      "detail": "JSONString 中不存在 CHN",
565
+      "selectedRowId": 158696
566
+    },
567
+    {
568
+      "word": "相依为命",
569
+      "id": 87860,
570
+      "searchType": "list",
571
+      "status": "MISSING_CHN",
572
+      "detail": "JSONString 中不存在 CHN",
573
+      "selectedRowId": 87861
574
+    },
575
+    {
576
+      "word": "诗情画意",
577
+      "id": 79602,
578
+      "searchType": "list",
579
+      "status": "MISSING_CHN",
580
+      "detail": "JSONString 中不存在 CHN",
581
+      "selectedRowId": 79603
582
+    },
583
+    {
584
+      "word": "漫游",
585
+      "id": 94524,
586
+      "searchType": "list",
587
+      "status": "MISSING_CHN",
588
+      "detail": "JSONString 中不存在 CHN",
589
+      "selectedRowId": 94525
590
+    },
591
+    {
592
+      "word": "寸草不生",
593
+      "id": 60333,
594
+      "searchType": "list",
595
+      "status": "MISSING_CHN",
596
+      "detail": "JSONString 中不存在 CHN",
597
+      "selectedRowId": 60334
598
+    },
599
+    {
600
+      "word": "酷暑",
601
+      "id": 82791,
602
+      "searchType": "list",
603
+      "status": "MISSING_CHN",
604
+      "detail": "JSONString 中不存在 CHN",
605
+      "selectedRowId": 82792
606
+    },
607
+    {
608
+      "word": "机械",
609
+      "id": 75650,
610
+      "searchType": "list",
611
+      "status": "MISSING_CHN",
612
+      "detail": "JSONString 中不存在 CHN",
613
+      "selectedRowId": 75651
614
+    },
615
+    {
616
+      "word": "旅店",
617
+      "id": 97622,
618
+      "searchType": "list",
619
+      "status": "MISSING_CHN",
620
+      "detail": "JSONString 中不存在 CHN",
621
+      "selectedRowId": 97623
622
+    },
623
+    {
624
+      "word": "父慈子孝",
625
+      "id": 186990,
626
+      "searchType": "list",
627
+      "status": "MISSING_CHN",
628
+      "detail": "JSONString 中不存在 CHN",
629
+      "selectedRowId": 182489
630
+    },
631
+    {
632
+      "word": "如泣如诉",
633
+      "id": 159492,
634
+      "searchType": "list",
635
+      "status": "MISSING_CHN",
636
+      "detail": "JSONString 中不存在 CHN",
637
+      "selectedRowId": 159493
638
+    },
639
+    {
640
+      "word": "一张一弛",
641
+      "id": 170074,
642
+      "searchType": "list",
643
+      "status": "MISSING_CHN",
644
+      "detail": "JSONString 中不存在 CHN",
645
+      "selectedRowId": 170075
646
+    },
647
+    {
648
+      "word": "忘却",
649
+      "id": 5089,
650
+      "searchType": "list",
651
+      "status": "MISSING_CHN",
652
+      "detail": "JSONString 中不存在 CHN",
653
+      "selectedRowId": 5090
654
+    },
655
+    {
656
+      "word": "悠然",
657
+      "id": 1748,
658
+      "searchType": "list",
659
+      "status": "MISSING_CHN",
660
+      "detail": "JSONString 中不存在 CHN",
661
+      "selectedRowId": 1749
662
+    },
663
+    {
664
+      "word": "潇洒",
665
+      "id": 60623,
666
+      "searchType": "list",
667
+      "status": "MISSING_CHN",
668
+      "detail": "JSONString 中不存在 CHN",
669
+      "selectedRowId": 60624
670
+    },
671
+    {
672
+      "word": "悬崖",
673
+      "id": 1931,
674
+      "searchType": "list",
675
+      "status": "MISSING_CHN",
676
+      "detail": "JSONString 中不存在 CHN",
677
+      "selectedRowId": 1932
678
+    },
679
+    {
680
+      "word": "斩钉截铁",
681
+      "id": 62295,
682
+      "searchType": "list",
683
+      "status": "MISSING_CHN",
684
+      "detail": "JSONString 中不存在 CHN",
685
+      "selectedRowId": 62296
686
+    },
687
+    {
688
+      "word": "眺望",
689
+      "id": 692,
690
+      "searchType": "list",
691
+      "status": "MISSING_CHN",
692
+      "detail": "JSONString 中不存在 CHN",
693
+      "selectedRowId": 693
694
+    },
695
+    {
696
+      "word": "幸而",
697
+      "id": 116735,
698
+      "searchType": "list",
699
+      "status": "MISSING_CHN",
700
+      "detail": "JSONString 中不存在 CHN",
701
+      "selectedRowId": 168292
702
+    },
703
+    {
704
+      "word": "弄巧成拙",
705
+      "id": 5561,
706
+      "searchType": "list",
707
+      "status": "MISSING_CHN",
708
+      "detail": "JSONString 中不存在 CHN",
709
+      "selectedRowId": 5562
710
+    },
711
+    {
712
+      "word": "暴露",
713
+      "id": 62046,
714
+      "searchType": "list",
715
+      "status": "MISSING_CHN",
716
+      "detail": "JSONString 中不存在 CHN",
717
+      "selectedRowId": 62047
718
+    },
719
+    {
720
+      "word": "移居",
721
+      "id": 3844,
722
+      "searchType": "list",
723
+      "status": "MISSING_CHN",
724
+      "detail": "JSONString 中不存在 CHN",
725
+      "selectedRowId": 3845
726
+    },
727
+    {
728
+      "word": "蟋蟀",
729
+      "id": 60593,
730
+      "searchType": "list",
731
+      "status": "MISSING_CHN",
732
+      "detail": "JSONString 中不存在 CHN",
733
+      "selectedRowId": 60594
734
+    }
735
+  ]
736
+}

+ 415 - 0
.vscode/秒过知识库更新/miaoguo_literacy_dependency_audit_current_2026_fall.json

@@ -0,0 +1,415 @@
1
+{
2
+  "generatedAt": "2026-09-01T05:28:46.583Z",
3
+  "readOnly": true,
4
+  "querySemantics": "与 GetMiaoguoLiteracyWords 一致:排除 SearchType=shici/eng,按 Word,SearchType DESC 取词语首条记录",
5
+  "summary": {
6
+    "finalOccurrences": 648,
7
+    "uniqueFinalWords": 648,
8
+    "uniqueNewlyIntroducedWords": 375,
9
+    "eligibleDatabaseRows": 695,
10
+    "usableWords": 648,
11
+    "problemWords": 0
12
+  },
13
+  "datasets": [
14
+    {
15
+      "label": "语文四年级上词语表",
16
+      "bookIdOld": 49,
17
+      "finalWords": 220,
18
+      "oldUniqueWords": 241,
19
+      "newlyIntroducedOccurrences": 135
20
+    },
21
+    {
22
+      "label": "语文五年级上词语表",
23
+      "bookIdOld": 51,
24
+      "finalWords": 213,
25
+      "oldUniqueWords": 222,
26
+      "newlyIntroducedOccurrences": 120
27
+    },
28
+    {
29
+      "label": "语文六年级上词语表",
30
+      "bookIdOld": 53,
31
+      "finalWords": 215,
32
+      "oldUniqueWords": 224,
33
+      "newlyIntroducedOccurrences": 120
34
+    }
35
+  ],
36
+  "problems": [],
37
+  "nonBlockingLowerPriorityIssues": [
38
+    {
39
+      "word": "蚊子",
40
+      "id": 1214,
41
+      "searchType": "list",
42
+      "status": "MISSING_CHN",
43
+      "detail": "JSONString 中不存在 CHN",
44
+      "selectedRowId": 1215
45
+    },
46
+    {
47
+      "word": "苍蝇",
48
+      "id": 947,
49
+      "searchType": "list",
50
+      "status": "MISSING_CHN",
51
+      "detail": "JSONString 中不存在 CHN",
52
+      "selectedRowId": 948
53
+    },
54
+    {
55
+      "word": "配合",
56
+      "id": 60074,
57
+      "searchType": "list",
58
+      "status": "MISSING_CHN",
59
+      "detail": "JSONString 中不存在 CHN",
60
+      "selectedRowId": 60075
61
+    },
62
+    {
63
+      "word": "能够",
64
+      "id": 486,
65
+      "searchType": "list",
66
+      "status": "MISSING_CHN",
67
+      "detail": "JSONString 中不存在 CHN",
68
+      "selectedRowId": 487
69
+    },
70
+    {
71
+      "word": "玻璃",
72
+      "id": 60269,
73
+      "searchType": "list",
74
+      "status": "MISSING_CHN",
75
+      "detail": "JSONString 中不存在 CHN",
76
+      "selectedRowId": 60270
77
+    },
78
+    {
79
+      "word": "玫瑰",
80
+      "id": 5799,
81
+      "searchType": "list",
82
+      "status": "MISSING_CHN",
83
+      "detail": "JSONString 中不存在 CHN",
84
+      "selectedRowId": 5800
85
+    },
86
+    {
87
+      "word": "牡丹",
88
+      "id": 5815,
89
+      "searchType": "list",
90
+      "status": "MISSING_CHN",
91
+      "detail": "JSONString 中不存在 CHN",
92
+      "selectedRowId": 5816
93
+    },
94
+    {
95
+      "word": "茉莉",
96
+      "id": 4714,
97
+      "searchType": "list",
98
+      "status": "MISSING_CHN",
99
+      "detail": "JSONString 中不存在 CHN",
100
+      "selectedRowId": 4715
101
+    },
102
+    {
103
+      "word": "海棠",
104
+      "id": 61389,
105
+      "searchType": "list",
106
+      "status": "MISSING_CHN",
107
+      "detail": "JSONString 中不存在 CHN",
108
+      "selectedRowId": 61390
109
+    },
110
+    {
111
+      "word": "无可奈何",
112
+      "id": 2501,
113
+      "searchType": "list",
114
+      "status": "MISSING_CHN",
115
+      "detail": "JSONString 中不存在 CHN",
116
+      "selectedRowId": 2502
117
+    },
118
+    {
119
+      "word": "笑呵呵",
120
+      "id": 91955,
121
+      "searchType": "list",
122
+      "status": "MISSING_CHN",
123
+      "detail": "JSONString 中不存在 CHN",
124
+      "selectedRowId": 91956
125
+    },
126
+    {
127
+      "word": "崇山峻岭",
128
+      "id": 59773,
129
+      "searchType": "list",
130
+      "status": "MISSING_CHN",
131
+      "detail": "JSONString 中不存在 CHN",
132
+      "selectedRowId": 59774
133
+    },
134
+    {
135
+      "word": "自然",
136
+      "id": 86300,
137
+      "searchType": "list",
138
+      "status": "MISSING_CHN",
139
+      "detail": "JSONString 中不存在 CHN",
140
+      "selectedRowId": 86301
141
+    },
142
+    {
143
+      "word": "镜子",
144
+      "id": 885,
145
+      "searchType": "list",
146
+      "status": "MISSING_CHN",
147
+      "detail": "JSONString 中不存在 CHN",
148
+      "selectedRowId": 886
149
+    },
150
+    {
151
+      "word": "狮子",
152
+      "id": 59463,
153
+      "searchType": "list",
154
+      "status": "MISSING_CHN",
155
+      "detail": "JSONString 中不存在 CHN",
156
+      "selectedRowId": 59464
157
+    },
158
+    {
159
+      "word": "默默",
160
+      "id": 90597,
161
+      "searchType": "list",
162
+      "status": "MISSING_CHN",
163
+      "detail": "JSONString 中不存在 CHN",
164
+      "selectedRowId": 156357
165
+    },
166
+    {
167
+      "word": "桂花",
168
+      "id": 4143,
169
+      "searchType": "list",
170
+      "status": "MISSING_CHN",
171
+      "detail": "JSONString 中不存在 CHN",
172
+      "selectedRowId": 4144
173
+    },
174
+    {
175
+      "word": "故乡",
176
+      "id": 81493,
177
+      "searchType": "list",
178
+      "status": "MISSING_CHN",
179
+      "detail": "JSONString 中不存在 CHN",
180
+      "selectedRowId": 81494
181
+    },
182
+    {
183
+      "word": "成熟",
184
+      "id": 111,
185
+      "searchType": "list",
186
+      "status": "MISSING_CHN",
187
+      "detail": "JSONString 中不存在 CHN",
188
+      "selectedRowId": 112
189
+    },
190
+    {
191
+      "word": "果实",
192
+      "id": 823,
193
+      "searchType": "list",
194
+      "status": "MISSING_CHN",
195
+      "detail": "JSONString 中不存在 CHN",
196
+      "selectedRowId": 825
197
+    },
198
+    {
199
+      "word": "距离",
200
+      "id": 59849,
201
+      "searchType": "list",
202
+      "status": "MISSING_CHN",
203
+      "detail": "JSONString 中不存在 CHN",
204
+      "selectedRowId": 59850
205
+    },
206
+    {
207
+      "word": "拒绝",
208
+      "id": 74078,
209
+      "searchType": "list",
210
+      "status": "MISSING_CHN",
211
+      "detail": "JSONString 中不存在 CHN",
212
+      "selectedRowId": 74079
213
+    },
214
+    {
215
+      "word": "小心翼翼",
216
+      "id": 74851,
217
+      "searchType": "list",
218
+      "status": "MISSING_CHN",
219
+      "detail": "JSONString 中不存在 CHN",
220
+      "selectedRowId": 1462
221
+    },
222
+    {
223
+      "word": "凌晨",
224
+      "id": 61747,
225
+      "searchType": "list",
226
+      "status": "MISSING_CHN",
227
+      "detail": "JSONString 中不存在 CHN",
228
+      "selectedRowId": 61748
229
+    },
230
+    {
231
+      "word": "岗位",
232
+      "id": 83719,
233
+      "searchType": "list",
234
+      "status": "MISSING_CHN",
235
+      "detail": "JSONString 中不存在 CHN",
236
+      "selectedRowId": 83720
237
+    },
238
+    {
239
+      "word": "忠于职守",
240
+      "id": 158695,
241
+      "searchType": "list",
242
+      "status": "MISSING_CHN",
243
+      "detail": "JSONString 中不存在 CHN",
244
+      "selectedRowId": 158696
245
+    },
246
+    {
247
+      "word": "相依为命",
248
+      "id": 87860,
249
+      "searchType": "list",
250
+      "status": "MISSING_CHN",
251
+      "detail": "JSONString 中不存在 CHN",
252
+      "selectedRowId": 87861
253
+    },
254
+    {
255
+      "word": "诗情画意",
256
+      "id": 79602,
257
+      "searchType": "list",
258
+      "status": "MISSING_CHN",
259
+      "detail": "JSONString 中不存在 CHN",
260
+      "selectedRowId": 79603
261
+    },
262
+    {
263
+      "word": "漫游",
264
+      "id": 94524,
265
+      "searchType": "list",
266
+      "status": "MISSING_CHN",
267
+      "detail": "JSONString 中不存在 CHN",
268
+      "selectedRowId": 94525
269
+    },
270
+    {
271
+      "word": "寸草不生",
272
+      "id": 60333,
273
+      "searchType": "list",
274
+      "status": "MISSING_CHN",
275
+      "detail": "JSONString 中不存在 CHN",
276
+      "selectedRowId": 60334
277
+    },
278
+    {
279
+      "word": "酷暑",
280
+      "id": 82791,
281
+      "searchType": "list",
282
+      "status": "MISSING_CHN",
283
+      "detail": "JSONString 中不存在 CHN",
284
+      "selectedRowId": 82792
285
+    },
286
+    {
287
+      "word": "机械",
288
+      "id": 75650,
289
+      "searchType": "list",
290
+      "status": "MISSING_CHN",
291
+      "detail": "JSONString 中不存在 CHN",
292
+      "selectedRowId": 75651
293
+    },
294
+    {
295
+      "word": "旅店",
296
+      "id": 97622,
297
+      "searchType": "list",
298
+      "status": "MISSING_CHN",
299
+      "detail": "JSONString 中不存在 CHN",
300
+      "selectedRowId": 97623
301
+    },
302
+    {
303
+      "word": "父慈子孝",
304
+      "id": 186990,
305
+      "searchType": "list",
306
+      "status": "MISSING_CHN",
307
+      "detail": "JSONString 中不存在 CHN",
308
+      "selectedRowId": 182489
309
+    },
310
+    {
311
+      "word": "如泣如诉",
312
+      "id": 159492,
313
+      "searchType": "list",
314
+      "status": "MISSING_CHN",
315
+      "detail": "JSONString 中不存在 CHN",
316
+      "selectedRowId": 159493
317
+    },
318
+    {
319
+      "word": "一张一弛",
320
+      "id": 170074,
321
+      "searchType": "list",
322
+      "status": "MISSING_CHN",
323
+      "detail": "JSONString 中不存在 CHN",
324
+      "selectedRowId": 170075
325
+    },
326
+    {
327
+      "word": "忘却",
328
+      "id": 5089,
329
+      "searchType": "list",
330
+      "status": "MISSING_CHN",
331
+      "detail": "JSONString 中不存在 CHN",
332
+      "selectedRowId": 5090
333
+    },
334
+    {
335
+      "word": "悠然",
336
+      "id": 1748,
337
+      "searchType": "list",
338
+      "status": "MISSING_CHN",
339
+      "detail": "JSONString 中不存在 CHN",
340
+      "selectedRowId": 1749
341
+    },
342
+    {
343
+      "word": "潇洒",
344
+      "id": 60623,
345
+      "searchType": "list",
346
+      "status": "MISSING_CHN",
347
+      "detail": "JSONString 中不存在 CHN",
348
+      "selectedRowId": 60624
349
+    },
350
+    {
351
+      "word": "悬崖",
352
+      "id": 1931,
353
+      "searchType": "list",
354
+      "status": "MISSING_CHN",
355
+      "detail": "JSONString 中不存在 CHN",
356
+      "selectedRowId": 1932
357
+    },
358
+    {
359
+      "word": "斩钉截铁",
360
+      "id": 62295,
361
+      "searchType": "list",
362
+      "status": "MISSING_CHN",
363
+      "detail": "JSONString 中不存在 CHN",
364
+      "selectedRowId": 62296
365
+    },
366
+    {
367
+      "word": "眺望",
368
+      "id": 692,
369
+      "searchType": "list",
370
+      "status": "MISSING_CHN",
371
+      "detail": "JSONString 中不存在 CHN",
372
+      "selectedRowId": 693
373
+    },
374
+    {
375
+      "word": "幸而",
376
+      "id": 116735,
377
+      "searchType": "list",
378
+      "status": "MISSING_CHN",
379
+      "detail": "JSONString 中不存在 CHN",
380
+      "selectedRowId": 168292
381
+    },
382
+    {
383
+      "word": "弄巧成拙",
384
+      "id": 5561,
385
+      "searchType": "list",
386
+      "status": "MISSING_CHN",
387
+      "detail": "JSONString 中不存在 CHN",
388
+      "selectedRowId": 5562
389
+    },
390
+    {
391
+      "word": "暴露",
392
+      "id": 62046,
393
+      "searchType": "list",
394
+      "status": "MISSING_CHN",
395
+      "detail": "JSONString 中不存在 CHN",
396
+      "selectedRowId": 62047
397
+    },
398
+    {
399
+      "word": "移居",
400
+      "id": 3844,
401
+      "searchType": "list",
402
+      "status": "MISSING_CHN",
403
+      "detail": "JSONString 中不存在 CHN",
404
+      "selectedRowId": 3845
405
+    },
406
+    {
407
+      "word": "蟋蟀",
408
+      "id": 60593,
409
+      "searchType": "list",
410
+      "status": "MISSING_CHN",
411
+      "detail": "JSONString 中不存在 CHN",
412
+      "selectedRowId": 60594
413
+    }
414
+  ]
415
+}

Разница между файлами не показана из-за своего большого размера
+ 1092 - 0
.vscode/秒过知识库更新/miaoguo_literacy_dry_run_2026_fall.json


+ 193 - 0
.vscode/秒过知识库更新/miaoguo_literacy_post_apply_audit_2026_fall.json

@@ -0,0 +1,193 @@
1
+{
2
+  "generatedAt": "2026-09-01T05:28:46.300Z",
3
+  "mode": "audit",
4
+  "passed": true,
5
+  "insertedRows": [
6
+    {
7
+      "id": 222100,
8
+      "word": "结账",
9
+      "searchType": "zici",
10
+      "pinyin": "jié zhàng",
11
+      "explain": "结算账目,也指结算消费的费用:饭后结账。",
12
+      "kaitiImages": 2,
13
+      "strokeAnimations": 2
14
+    },
15
+    {
16
+      "id": 222101,
17
+      "word": "航线",
18
+      "searchType": "zici",
19
+      "pinyin": "háng xiàn",
20
+      "explain": "飞机或船舶预先规划的航行路线。",
21
+      "kaitiImages": 2,
22
+      "strokeAnimations": 2
23
+    },
24
+    {
25
+      "id": 222102,
26
+      "word": "热量",
27
+      "searchType": "zici",
28
+      "pinyin": "rè liàng",
29
+      "explain": "1.由于温度差别而转移的能量。\n2.食物经人体消化吸收后可以提供的能量。",
30
+      "kaitiImages": 2,
31
+      "strokeAnimations": 2
32
+    },
33
+    {
34
+      "id": 222103,
35
+      "word": "星斗",
36
+      "searchType": "zici",
37
+      "pinyin": "xīng dǒu",
38
+      "explain": "星的总称:满天星斗。",
39
+      "kaitiImages": 2,
40
+      "strokeAnimations": 2
41
+    },
42
+    {
43
+      "id": 222104,
44
+      "word": "兄友弟恭",
45
+      "searchType": "zici",
46
+      "pinyin": "xiōng yǒu dì gōng",
47
+      "explain": "哥哥对弟弟友爱,弟弟对哥哥恭敬。形容兄弟间互爱互敬。",
48
+      "kaitiImages": 4,
49
+      "strokeAnimations": 4
50
+    },
51
+    {
52
+      "id": 222105,
53
+      "word": "湘菜",
54
+      "searchType": "zici",
55
+      "pinyin": "xiāng cài",
56
+      "explain": "湖南风味的菜肴。",
57
+      "kaitiImages": 2,
58
+      "strokeAnimations": 2
59
+    },
60
+    {
61
+      "id": 222106,
62
+      "word": "粤菜",
63
+      "searchType": "zici",
64
+      "pinyin": "yuè cài",
65
+      "explain": "以广东风味为代表的菜肴。",
66
+      "kaitiImages": 2,
67
+      "strokeAnimations": 2
68
+    },
69
+    {
70
+      "id": 222107,
71
+      "word": "苏绣",
72
+      "searchType": "zici",
73
+      "pinyin": "sū xiù",
74
+      "explain": "江苏苏州出产的刺绣。",
75
+      "kaitiImages": 2,
76
+      "strokeAnimations": 2
77
+    },
78
+    {
79
+      "id": 222108,
80
+      "word": "滇剧",
81
+      "searchType": "zici",
82
+      "pinyin": "diān jù",
83
+      "explain": "云南的主要戏曲剧种之一。唱腔以皮黄为主,流行于云南以及四川、贵州的部分地区。",
84
+      "kaitiImages": 2,
85
+      "strokeAnimations": 2
86
+    },
87
+    {
88
+      "id": 222109,
89
+      "word": "民居",
90
+      "searchType": "zici",
91
+      "pinyin": "mín jū",
92
+      "explain": "民间房舍;百姓居住的房屋。",
93
+      "kaitiImages": 2,
94
+      "strokeAnimations": 2
95
+    },
96
+    {
97
+      "id": 222110,
98
+      "word": "公事",
99
+      "searchType": "zici",
100
+      "pinyin": "gōng shì",
101
+      "explain": "公家的事;集体的事(区别于“私事”):公事公办。",
102
+      "kaitiImages": 2,
103
+      "strokeAnimations": 2
104
+    },
105
+    {
106
+      "id": 222111,
107
+      "word": "处世",
108
+      "searchType": "zici",
109
+      "pinyin": "chǔ shì",
110
+      "explain": "在社会上活动,跟人交往:立身处世。",
111
+      "kaitiImages": 2,
112
+      "strokeAnimations": 2
113
+    },
114
+    {
115
+      "id": 222112,
116
+      "word": "回敬",
117
+      "searchType": "zici",
118
+      "pinyin": "huí jìng",
119
+      "explain": "回报别人给予的敬意或馈赠;也指用同样的方式回应。",
120
+      "kaitiImages": 2,
121
+      "strokeAnimations": 2
122
+    },
123
+    {
124
+      "id": 222113,
125
+      "word": "落空",
126
+      "searchType": "zici",
127
+      "pinyin": "luò kōng",
128
+      "explain": "没有达到目的或得到预期的结果:希望落空。",
129
+      "kaitiImages": 2,
130
+      "strokeAnimations": 2
131
+    },
132
+    {
133
+      "id": 222114,
134
+      "word": "表明",
135
+      "searchType": "zici",
136
+      "pinyin": "biǎo míng",
137
+      "explain": "清楚地表示:表明态度。",
138
+      "kaitiImages": 2,
139
+      "strokeAnimations": 2
140
+    },
141
+    {
142
+      "id": 222115,
143
+      "word": "进一步",
144
+      "searchType": "zici",
145
+      "pinyin": "jìn yī bù",
146
+      "explain": "表示事情在原有基础上向前发展或程度提高:进一步了解情况。",
147
+      "kaitiImages": 3,
148
+      "strokeAnimations": 3
149
+    },
150
+    {
151
+      "id": 222116,
152
+      "word": "自制",
153
+      "searchType": "zici",
154
+      "pinyin": "zì zhì",
155
+      "explain": "1.自己制造:自制教具。\n2.克制自己:难以自制。",
156
+      "kaitiImages": 2,
157
+      "strokeAnimations": 2
158
+    },
159
+    {
160
+      "id": 222117,
161
+      "word": "不由得",
162
+      "searchType": "zici",
163
+      "pinyin": "bù yóu de",
164
+      "explain": "1.不禁,忍不住:不由得笑了起来。\n2.不容许:不由得你不信。",
165
+      "kaitiImages": 3,
166
+      "strokeAnimations": 3
167
+    },
168
+    {
169
+      "id": 222118,
170
+      "word": "甜丝丝",
171
+      "searchType": "zici",
172
+      "pinyin": "tián sī sī",
173
+      "explain": "状态词。形容有甜味;也形容感到幸福愉快:心里甜丝丝的。",
174
+      "kaitiImages": 3,
175
+      "strokeAnimations": 3
176
+    },
177
+    {
178
+      "id": 222119,
179
+      "word": "入神",
180
+      "searchType": "zici",
181
+      "pinyin": "rù shén",
182
+      "explain": "1.对某事物兴趣浓厚而精神高度集中:听得入神。\n2.形容技艺达到精妙的境界。",
183
+      "kaitiImages": 2,
184
+      "strokeAnimations": 2
185
+    }
186
+  ],
187
+  "vocabularyAudit": {
188
+    "passed": true,
189
+    "finalVocabularyWords": 648,
190
+    "selectedUsableRows": 648,
191
+    "problems": []
192
+  }
193
+}

+ 262 - 0
.vscode/秒过知识库更新/source_chinese_2026_fall.json

@@ -0,0 +1,262 @@
1
+[
2
+  {
3
+    "label": "语文四年级上识字表",
4
+    "miaoguoBookId": 49,
5
+    "bookIdOld": 67,
6
+    "unitType": 1,
7
+    "officialWordNum": 250,
8
+    "blueCharacterCount": 15,
9
+    "wordNum": 265,
10
+    "units": [
11
+      {"name": "课文1", "example": "盐薄隆鼎沸浩崩霎余漫吼"},
12
+      {"name": "课文2", "example": "昧坠莹"},
13
+      {"name": "课文3", "example": "巢苇瞬穗罗霸"},
14
+      {"name": "课文4", "example": "豌僵预揭囚劈框吻脏溢健康"},
15
+      {"name": "课文5", "example": "蝙蝠蛾避锐蝇障碍荧屏驾"},
16
+      {"name": "课文6", "example": "橱焦扣嚷溜筒懂"},
17
+      {"name": "课文7", "example": "忌将获赢拳跃测输谋划策荐"},
18
+      {"name": "语文园地", "example": "纲揍锈沫综氧账矿俱"},
19
+      {"name": "课文8", "example": "暮残瑟缘降骚评逊"},
20
+      {"name": "课文9", "example": "茎柄蜗曲萎"},
21
+      {"name": "课文10", "example": "蟋蟀宅慎址畅倾骤置糙朴燥"},
22
+      {"name": "课文11", "example": "斧缓浊丈肢躯液"},
23
+      {"name": "课文12", "example": "曰溺"},
24
+      {"name": "课文13", "example": "斯悲惨盗驰佩违锁遭肝脏愤砸"},
25
+      {"name": "课文14", "example": "兽措陷混捺燃炼熄浆杀颂"},
26
+      {"name": "语文园地", "example": "卉玫瑰牡丹蕾茉莉棠"},
27
+      {"name": "课文15", "example": "嗅奈拯嘶哑牺牲庞"},
28
+      {"name": "课文16", "example": "链颤攀辫呵"},
29
+      {"name": "课文17", "example": "峻基砧扩砖屯兵堡垒仗畜耗"},
30
+      {"name": "课文18", "example": "殿漆琉佛煌"},
31
+      {"name": "课文19", "example": "享誉宏皇率着靴誓塑惟肖拟逼"},
32
+      {"name": "语文园地", "example": "萨昭陵寝堰尼绸廊"},
33
+      {"name": "课文20", "example": "鹅屁股谓捶顽吁膊瓶怖欺掐"},
34
+      {"name": "课文21", "example": "露羡殷逗撇啊霉亏撤哄拙唉"},
35
+      {"name": "课文22", "example": "钉质岳削废骂帅衅扭彻溃豪"},
36
+      {"name": "课文23", "example": "戎诸竞唯"},
37
+      {"name": "语文园地", "example": "韭芹椒蒜薯藕芋姜"},
38
+      {"name": "课文24", "example": "菲抛奉亿邀"},
39
+      {"name": "课文25", "example": "崛范魏默晰惑轧惩肇斥辱"},
40
+      {"name": "课文26", "example": "昔茅炕索媚"},
41
+      {"name": "课文27", "example": "催君征塞秦杰鬼"}
42
+    ]
43
+  },
44
+  {
45
+    "label": "语文四年级上写字表",
46
+    "miaoguoBookId": 7,
47
+    "bookIdOld": 19,
48
+    "unitType": 5,
49
+    "officialWordNum": 250,
50
+    "wordNum": 250,
51
+    "units": [
52
+      {"name": "课文1", "example": "据随堤顿逐渐堵墙浩崩霎余"},
53
+      {"name": "课文2", "example": "繁怀寂谈熟躺模糊围舞"},
54
+      {"name": "课文4", "example": "舒适揭晓滚滑擦探曾沟涨"},
55
+      {"name": "课文5", "example": "蚊即题绳嘴蝇研究驾驶"},
56
+      {"name": "课文6", "example": "帽脑袋假扣懂溜筒摆玻璃"},
57
+      {"name": "语文园地", "example": "纲揍锈沫综氧账矿俱"},
58
+      {"name": "课文8", "example": "残铺壁横侧峰庐缘降评章输"},
59
+      {"name": "课文9", "example": "虎脚操嫩隙柄触痕迹瞧"},
60
+      {"name": "课文10", "example": "宅毫重选择址厅专修较腿增"},
61
+      {"name": "课文11", "example": "醒翻缓踏丈撑疲竭耀肢整"},
62
+      {"name": "课文12", "example": "填帝曰娃衔"},
63
+      {"name": "课文13", "example": "喷颗败敬佩忍既遭屈肝脏获"},
64
+      {"name": "语文园地", "example": "卉玫瑰牡丹蕾茉莉棠"},
65
+      {"name": "课文15", "example": "嗅猛烈奈躯掩浑牺牲庞强量"},
66
+      {"name": "课文16", "example": "哩陡级链颤纪攀猴呵啦鼓"},
67
+      {"name": "课文17", "example": "峻旋扩砖筑隔仗扶耗智慧"},
68
+      {"name": "课文18", "example": "绕幅栽笋腰煌镜隐狮"},
69
+      {"name": "语文园地", "example": "萨昭陵寝堰尼绸廊"},
70
+      {"name": "课文20", "example": "鹅骑拳坚竟胸鞋拖胳膊握摔"},
71
+      {"name": "课文21", "example": "表演俩练捧示技撤推哄堂摘"},
72
+      {"name": "课文23", "example": "戎诸竞唯"},
73
+      {"name": "语文园地", "example": "韭芹椒蒜薯藕芋姜"},
74
+      {"name": "课文24", "example": "席抛激奉训亿勤邀"},
75
+      {"name": "课文25", "example": "崛肃脆默晰离凡惩斥燃"},
76
+      {"name": "课文27", "example": "词葡萄杯塞秦将杰鬼雄项"}
77
+    ]
78
+  },
79
+  {
80
+    "label": "语文四年级上词语表",
81
+    "miaoguoBookId": 37,
82
+    "bookIdOld": 49,
83
+    "unitType": 2,
84
+    "officialWordNum": 220,
85
+    "wordNum": 220,
86
+    "units": [
87
+      {"name": "课文1", "example": "奇观,据说,人山人海,顿时,风平浪静,逐渐,齐头并进,浩浩荡荡,山崩地裂,霎时,余波"},
88
+      {"name": "课文2", "example": "繁星,密密麻麻,忘记,谈话,渐渐,模糊,周围,飞舞,柔和,梦幻,怀抱,沉睡"},
89
+      {"name": "课文4", "example": "暖洋洋,舒适,揭晓,身份,暖和,的确,曾经,打滚,水沟,注视"},
90
+      {"name": "课文5", "example": "蚊子,即使,问题,绳子,苍蝇,证明,相互,配合,研究,类似,能够"},
91
+      {"name": "课文6", "example": "帽子,脑袋,舒服,假如,设法,懂事,一溜烟,各式各样,摆放,玻璃"},
92
+      {"name": "语文园地", "example": "提纲,生锈,泡沫,综合,氧气,结账,矿物,俱乐部"},
93
+      {"name": "课文9", "example": "爬山虎,操场,嫩绿,新鲜,均匀,空隙,叶柄,触角,弯曲,痕迹,瞧不起,牢固"},
94
+      {"name": "课文10", "example": "住宅,选择,住址,大厅,柔弱,平坦,光滑,修理,重要,增长"},
95
+      {"name": "课文11", "example": "宇宙,黑乎乎,翻身,下降,精疲力竭,飘动,照耀,四肢,奔流不息,茂盛,整个"},
96
+      {"name": "课文13", "example": "喷射,气急败坏,严厉,立即,执行,敬佩,坚定,忍受,遭受,尽管,屈服,肝脏,获得"},
97
+      {"name": "语文园地", "example": "花卉,玫瑰,牡丹,花蕾,茉莉,海棠"},
98
+      {"name": "课文15", "example": "麻雀,悄悄,猛烈,无可奈何,身躯,掩护,紧张,浑身,牺牲,庞大,强大,力量,勇气"},
99
+      {"name": "课文16", "example": "石级,发颤,年纪,奋力,猴子,纪念,笑呵呵,鼓舞"},
100
+      {"name": "课文17", "example": "崇山峻岭,盘旋,扩建,修筑,平整,打仗,自然,当地,耗费,大量,智慧,工程,奇迹"},
101
+      {"name": "课文18", "example": "柱子,栏杆,人物,神清气爽,建筑,耸立,半山腰,金碧辉煌,镜子,隐隐约约,游人,狮子,姿态"},
102
+      {"name": "语文园地", "example": "陵寝,景观,丝绸"},
103
+      {"name": "课文20", "example": "虽然,拳头,故意,神气,忙乱,鞋子,助威,胳膊,纷纷,可笑,无缘无故"},
104
+      {"name": "课文21", "example": "文艺,表演,角色,排练,主意,通情达理,充分,提示,演技,撤换,等候,哄堂大笑,垂头丧气"},
105
+      {"name": "语文园地", "example": "韭菜,芹菜,辣椒,红薯,莲藕,芋头"},
106
+      {"name": "课文24", "example": "主席,举行,心情,补充,激动,状态,奉献,运动员,训练,建设,勤劳,邀请"},
107
+      {"name": "课文25", "example": "崛起,严肃,干脆,默默,若有所思,清晰,离开,随便,忘怀,非凡,惩处,训斥,燃烧,响亮"}
108
+    ]
109
+  },
110
+  {
111
+    "label": "语文五年级上识字表",
112
+    "miaoguoBookId": 51,
113
+    "bookIdOld": 69,
114
+    "unitType": 1,
115
+    "officialWordNum": 200,
116
+    "blueCharacterCount": 9,
117
+    "wordNum": 209,
118
+    "units": [
119
+      {"name": "课文1", "example": "篓杭"},
120
+      {"name": "课文2", "example": "亩吩榨榴"},
121
+      {"name": "课文3", "example": "悉雏哟啄嗒抚陪睑泻"},
122
+      {"name": "课文4", "example": "侵碉任丘搁拐岔"},
123
+      {"name": "课文5", "example": "壁臣冠强允罪廉御辞擅岳拒卿削"},
124
+      {"name": "课文6", "example": "鸵冠隼瀚啸"},
125
+      {"name": "课文7", "example": "曼敦弥玛剖裸呛艇秩嘈祸殴岗宰遣"},
126
+      {"name": "课文8", "example": "酬禽塌"},
127
+      {"name": "课文9", "example": "嫂恳筛咧歹罕惯纱梭监狱酿瞌落"},
128
+      {"name": "课文10", "example": "俭偎珊瑚礁筐扭"},
129
+      {"name": "课文11", "example": "乃邱熏亥龚恃"},
130
+      {"name": "课文12", "example": "潜渊惶胎履疆"},
131
+      {"name": "课文13", "example": "估玲珑剔澜瑶烬"},
132
+      {"name": "课文14", "example": "蓄剃租纠要斩烫妄"},
133
+      {"name": "课文15", "example": "殖炭疗"},
134
+      {"name": "课文16", "example": "埃狭甬黏"},
135
+      {"name": "课文17", "example": "篇魄怂恿抑颓纫噪惫兜械权"},
136
+      {"name": "课文18", "example": "茧栈冤枉跷僻迪撩嫁缴锡嘲鲁篷"},
137
+      {"name": "课文19", "example": "涟漪凉铠肋赴辰凯姥淳尚憾"},
138
+      {"name": "语文园地", "example": "孝喻躁泣弛卑亢赋"},
139
+      {"name": "课文20", "example": "瞑浣愈酥"},
140
+      {"name": "课文21", "example": "凛冽咯吱屑瑞谚馒"},
141
+      {"name": "课文22", "example": "鹭蓑嵌匣嗜澄"},
142
+      {"name": "语文园地", "example": "湘粤蜀沪滇赣闽陕窑皖"},
143
+      {"name": "课文23", "example": "耻识吾论矣"},
144
+      {"name": "课文24", "example": "宴述传煞勉寇贾刊琐榜栩呻某"},
145
+      {"name": "课文25", "example": "侣娱趟"}
146
+    ]
147
+  },
148
+  {
149
+    "label": "语文五年级上写字表",
150
+    "miaoguoBookId": 9,
151
+    "bookIdOld": 21,
152
+    "unitType": 5,
153
+    "officialWordNum": 220,
154
+    "wordNum": 220,
155
+    "units": [
156
+      {"name": "课文1", "example": "欣兰篓靠婆糕饼浸茶"},
157
+      {"name": "课文2", "example": "亩荒播浇吩咐茅亭矮"},
158
+      {"name": "课文4", "example": "锁简阔丘妨碍距厕陷坑兵拐铜铃杭"},
159
+      {"name": "课文5", "example": "臣议罢亏允诺典君托杀辞录拒敲"},
160
+      {"name": "课文6", "example": "赛冠俯超箭赤"},
161
+      {"name": "课文7", "example": "例弥峡晨剖混哔喘违悲岗宰措犹"},
162
+      {"name": "课文8", "example": "酬叮嘱禽焦催延灾避悔倾涌"},
163
+      {"name": "课文9", "example": "郎嫂棚挺罕幸柴惯纱哎姑娘婚辈"},
164
+      {"name": "课文11", "example": "祭乃翁杭珍衰"},
165
+      {"name": "课文12", "example": "欧洲泻潜腾兽胎皇途"},
166
+      {"name": "课文13", "example": "估损组殿征览境宏唐侵销罪略"},
167
+      {"name": "课文15", "example": "际抵摄氏殖粮棉煤炭蒸滴菌疗"},
168
+      {"name": "课文16", "example": "塔埃墓堆基砌狭"},
169
+      {"name": "课文17", "example": "慈篇怂恿抑碌酷暑噪掏缴哇械权"},
170
+      {"name": "课文18", "example": "蚕省挣糖委迪缺扎嫁陪毕猪鲁"},
171
+      {"name": "语文园地", "example": "孝喻躁泣弛卑亢赋"},
172
+      {"name": "课文20", "example": "维孙眠寺愈"},
173
+      {"name": "课文21", "example": "茫屑虹俗瑞枕"},
174
+      {"name": "课文22", "example": "素朱哨恩韵"},
175
+      {"name": "语文园地", "example": "湘粤蜀沪滇赣闽陕窑皖"},
176
+      {"name": "课文23", "example": "耻吾谓矣岂"},
177
+      {"name": "课文24", "example": "舅津宴凯趣述勉贾衰遣刊朴某"}
178
+    ]
179
+  },
180
+  {
181
+    "label": "语文五年级上词语表",
182
+    "miaoguoBookId": 39,
183
+    "bookIdOld": 51,
184
+    "unitType": 2,
185
+    "officialWordNum": 213,
186
+    "wordNum": 213,
187
+    "units": [
188
+      {"name": "课文1", "example": "桂花,故乡,时节,欣赏,糕饼,成熟,完整,茶叶"},
189
+      {"name": "课文2", "example": "播种,收获,食品,吩咐,价钱,可贵,果实,体面"},
190
+      {"name": "课文4", "example": "地道,平原,扫荡,封锁,武装,粉碎,简直,广阔,不计其数,游击,战争,妨碍,距离,武器,拐弯,想方设法,转移,无穷无尽"},
191
+      {"name": "课文5", "example": "无价之宝,召集,大臣,商议,理亏,交付,允诺,隆重,典礼,约定,思量,承诺,国君,推辞,记录,拒绝,同心协力"},
192
+      {"name": "课文6", "example": "速度,赛跑,冠军,陆地,俯冲,超过,高度,火箭,摆脱,赤道"},
193
+      {"name": "课文7", "example": "照例,航线,弥漫,小心翼翼,海峡,容量,凌晨,隐约,震荡,惊恐万状,混乱,势不可当,威严,违抗,悲壮,岗位,惊慌失措,犹如,纹丝不动,相提并论,忠于职守,壮举"},
194
+      {"name": "课文8", "example": "流传,呼救,酬谢,叮嘱,议论,焦急,催促,千真万确,迟延,灾难,镇定,避难,后悔,密布,怒号,倾盆大雨,震天动地,世世代代"},
195
+      {"name": "课文9", "example": "眉开眼笑,美中不足,成家立业,稀罕,幸亏,相依为命"},
196
+      {"name": "课文13", "example": "毁灭,不可估量,举世闻名,众星拱月,环绕,殿堂,亭台楼阁,象征,仿照,诗情画意,漫步,漫游,天南海北,饱览,奇珍异宝,销毁,罪证,侵略,奉命,瑰宝,精华"},
197
+      {"name": "课文15", "example": "寸草不生,摄氏度,繁殖,粮食,煤炭,水蒸气,地区,热量,杀菌,治疗"},
198
+      {"name": "课文16", "example": "陵墓,堆砌,狭长,叹为观止"},
199
+      {"name": "课文17", "example": "慈母,长篇,怂恿,压抑,潮湿,忙碌,酷暑,扫视,噪声,忍心,机械,权利"},
200
+      {"name": "课文18", "example": "节省,旅店,教训,糖果,委屈,抽象,启迪,毕业,品尝,意识,领略,星斗,精致"},
201
+      {"name": "语文园地", "example": "兄友弟恭,父慈子孝,家喻户晓,心浮气躁,如泣如诉,一张一弛,不卑不亢,诗词歌赋"},
202
+      {"name": "课文21", "example": "侵入,飘落,粉妆玉砌,彩虹,俗话,瑞雪,供应"},
203
+      {"name": "课文22", "example": "精巧,身段,适宜,寻常,忘却,安稳,悠然,恩惠"},
204
+      {"name": "语文园地", "example": "湘菜,粤菜,蜀绣,苏绣,沪剧,滇剧,窑洞,民居"},
205
+      {"name": "课文24", "example": "津津有味,公事,一知半解,兴趣,述说,厌烦,朝代,兴亡盛衰,处世,书刊,精彩,质朴,浅显,国际,刊物"}
206
+    ]
207
+  },
208
+  {
209
+    "label": "语文六年级上写字表",
210
+    "miaoguoBookId": 11,
211
+    "bookIdOld": 23,
212
+    "unitType": 5,
213
+    "officialWordNum": 180,
214
+    "wordNum": 180,
215
+    "units": [
216
+      {"name": "课文1", "example": "勒吟骏鞭裳蹄腐貌拘稍"},
217
+      {"name": "课文2", "example": "缀窥紫潇雅檐浊拙簇遮恍"},
218
+      {"name": "课文3", "example": "德暮旷鹊蝉稻"},
219
+      {"name": "课文4", "example": "律蒙丸崖渡索"},
220
+      {"name": "课文5", "example": "贯棋悬斩截沸砸雹昂豪迈"},
221
+      {"name": "课文6", "example": "政府宾宣拂阅率榴辆嗓哑"},
222
+      {"name": "课文7", "example": "藏趴伪摧幕搜蔓液缩熄"},
223
+      {"name": "课文8", "example": "凛搏俊棍裁筹橡雕泰屏禁蹲"},
224
+      {"name": "课文9", "example": "谜猜尚析效轨谓斑萎燥漠"},
225
+      {"name": "课文11", "example": "黎疯淌盯肆伍揪呻膛废揭"},
226
+      {"name": "课文12", "example": "妻娜唉僵淋嘿糟霉嘛惨熬"},
227
+      {"name": "课文14", "example": "盏豫副倚制插聚愣漆堡枪编"},
228
+      {"name": "课文15", "example": "篷嫌瓦柜嘻嚷锅酱唇蹦"},
229
+      {"name": "课文16", "example": "帘裹薄篮渺资滥胁祸"},
230
+      {"name": "课文19", "example": "涯牵莺苔"},
231
+      {"name": "课文20", "example": "仓聪置悦施"},
232
+      {"name": "课文21", "example": "谐拦添怖愉蟋蟀"},
233
+      {"name": "课文23", "example": "郑拜偷租厨毡羞爹猬伶俐"},
234
+      {"name": "课文24", "example": "搁萍藻漾焰削缕晕骤撕坠剩"}
235
+    ]
236
+  },
237
+  {
238
+    "label": "语文六年级上词语表",
239
+    "miaoguoBookId": 41,
240
+    "bookIdOld": 53,
241
+    "unitType": 2,
242
+    "officialWordNum": 215,
243
+    "wordNum": 215,
244
+    "units": [
245
+      {"name": "课文1", "example": "柔美,勾勒,境界,惊叹,低吟,奇丽,骏马,回味,洒脱,衣裳,疾驰,静寂,礼貌,拘束,回敬"},
246
+      {"name": "课文2", "example": "宅院,潇洒,幽雅,伏案,轻灵,浑浊,笨拙,参差,遮掩,文思,如同,何以,恰如,恍然,顺心"},
247
+      {"name": "课文5", "example": "奋战,险要,沉着,全神贯注,崎岖,横七竖八,悬崖,斩钉截铁,热血沸腾,居高临下,粉身碎骨,眺望,昂首,豪迈,气壮山河"},
248
+      {"name": "课文6", "example": "政府,汇集,爆发,排山倒海,庄严,宣告,欢跃,雄壮,肃立,飘拂,完毕,检阅,率领"},
249
+      {"name": "课文7", "example": "隐蔽,潜伏,前沿,伪装,枯黄,作为,摧毁,突击,搜索,蔓延,幸而,浓重,落空,忍耐,熄灭"},
250
+      {"name": "课文8", "example": "前功尽弃,威风凛凛,搏斗,疲倦,别出心裁,技高一筹,得意扬扬,观摩,弄巧成拙,知趣,大步流星,不禁,一无所获,念念有词,忘乎所以,心满意足"},
251
+      {"name": "课文9", "example": "盛会,系统,猜测,尚未,分析,效应,轨道,表明,所谓,斑点,枯萎,干燥,沙漠,进一步,一系列,探索"},
252
+      {"name": "课文11", "example": "黎明,狂奔,惊慌,跌跌撞撞,拥戴,清瘦,乱哄哄,沙哑,依次,放肆,队伍,呻吟,胸膛,吞没,猛然"},
253
+      {"name": "课文12", "example": "风暴,心惊肉跳,勉强,抱怨,倾听,探望,照顾,张罗,仍旧,僵硬,自作自受,湿淋淋,糟糕,倒霉,忧虑"},
254
+      {"name": "课文14", "example": "宏伟,赞叹,自制,微弱,聚精会神,不由得,点燃,漆黑,后续,阻击,突破,暴露,不惜"},
255
+      {"name": "课文15", "example": "斗篷,瓦蓝,衣柜,遮盖,闷雷,央求,心思,不声不响,逗引,张望,果真,甜丝丝,理直气壮,起劲"},
256
+      {"name": "课文16", "example": "眼帘,摇篮,渺小,资源,无私,节制,枯竭,毁坏,滥用,威胁,移居,指望,设想,目睹,造福"},
257
+      {"name": "课文21", "example": "街心,走动,和谐,清脆,单调,增加,神秘,轻易,入神,唯恐,恐怖,愉快,证实,蟋蟀"},
258
+      {"name": "课文23", "example": "一望无际,其间,尽力,郑重,讲究,以及,允许,明晃晃,可见,无端,伶俐,潮汛,往常"},
259
+      {"name": "课文24", "example": "昏沉,茅屋,荡漾,解散,退缩,边缘,瘦削,浮动,骤然,陡然,何尝"}
260
+    ]
261
+  }
262
+]

+ 288 - 0
.vscode/秒过知识库更新/source_english_2026_fall.json

@@ -0,0 +1,288 @@
1
+[
2
+  {
3
+    "label": "英语六年级上单词表",
4
+    "miaoguoBookId": 291,
5
+    "bookIdOld": 197,
6
+    "wordNum": 144,
7
+    "units": [
8
+      {
9
+        "lessonId": 1,
10
+        "lessonName": "Unit 1",
11
+        "entries": [
12
+          {"word": "was", "soundmark": "[wəz]", "translate": "(be 的第一和第三人称单数过去式)"},
13
+          {"word": "climb", "soundmark": "[klaɪm]", "translate": "攀登;爬"},
14
+          {"word": "kilometre", "soundmark": "[kɪˈlɒmɪtə(r)]", "translate": "(=km)千米;公里"},
15
+          {"word": "gingerbread house", "soundmark": "[ˈdʒɪndʒəbred]", "translate": "姜饼屋"},
16
+          {"word": "send", "soundmark": "[send]", "translate": "邮寄;发送"},
17
+          {"word": "go", "soundmark": "[ɡəʊ]", "translate": "(过去式 went /went/)去;走"},
18
+          {"word": "thousand", "soundmark": "[ˈθaʊznd]", "translate": "一千"},
19
+          {"word": "clay", "soundmark": "[kleɪ]", "translate": "黏土;陶土"},
20
+          {"word": "see", "soundmark": "[siː]", "translate": "(过去式 saw /sɔː/)看见"},
21
+          {"word": "village", "soundmark": "[ˈvɪlɪdʒ]", "translate": "村庄;村镇"},
22
+          {"word": "eat", "soundmark": "[iːt]", "translate": "(过去式 ate /eɪt/)吃"},
23
+          {"word": "dry", "soundmark": "[draɪ]", "translate": "干的"},
24
+          {"word": "take", "soundmark": "[teɪk]", "translate": "(过去式 took /tʊk/)做(某个动作;和名词连用代替某个动词)"},
25
+          {"word": "view", "soundmark": "[vjuː]", "translate": "景色"},
26
+          {"word": "inspiring", "soundmark": "[ɪnˈspaɪərɪŋ]", "translate": "鼓舞人心的"},
27
+          {"word": "bamboo", "soundmark": "[ˌbæmˈbuː]", "translate": "竹;竹子"},
28
+          {"word": "pumpkin", "soundmark": "[ˈpʌmpkɪn]", "translate": "南瓜"},
29
+          {"word": "restaurant", "soundmark": "[ˈrestrɒnt]", "translate": "餐馆;餐厅"},
30
+          {"word": "airport", "soundmark": "[ˈeəpɔːt]", "translate": "机场"},
31
+          {"word": "New Zealand", "soundmark": "[ˌnjuː ˈziːlənd]", "translate": "新西兰"},
32
+          {"word": "Hong Kong-Zhuhai-Macao Bridge", "soundmark": "[ˌhɒŋˈkɒŋ məˈkaʊ brɪdʒ]", "translate": "港珠澳大桥"},
33
+          {"word": "Paris", "soundmark": "[ˈpærɪs]", "translate": "巴黎"},
34
+          {"word": "Eiffel Tower", "soundmark": "[ˈaɪfl]", "translate": "埃菲尔铁塔"},
35
+          {"word": "Terracotta Warriors", "soundmark": "[ˌterəˈkɒtə ˈwɒriəz]", "translate": "兵马俑"},
36
+          {"word": "Jinggangshan Revolution Museum", "soundmark": "[ˌrevəˈluːʃn]", "translate": "井冈山革命博物馆"},
37
+          {"word": "the Red Army", "soundmark": null, "translate": "红军"}
38
+        ]
39
+      },
40
+      {
41
+        "lessonId": 2,
42
+        "lessonName": "Unit 2",
43
+        "entries": [
44
+          {"word": "paste", "soundmark": "[peɪst]", "translate": "粘贴"},
45
+          {"word": "dress", "soundmark": "[dres]", "translate": "穿衣服"},
46
+          {"word": "gala", "soundmark": "[ˈɡɑːlə]", "translate": "演出;庆典"},
47
+          {"word": "count down", "soundmark": "[kaʊnt daʊn]", "translate": "倒计时"},
48
+          {"word": "marathon", "soundmark": "[ˈmærəθən]", "translate": "马拉松赛跑"},
49
+          {"word": "as", "soundmark": "[əz]", "translate": "作为"},
50
+          {"word": "race", "soundmark": "[reɪs]", "translate": "赛跑;速度竞赛"},
51
+          {"word": "run", "soundmark": "[rʌn]", "translate": "(过去式 ran /ræn/)跑;奔跑"},
52
+          {"word": "cheer", "soundmark": "[tʃɪə(r)]", "translate": "欢呼;加油"},
53
+          {"word": "book fair", "soundmark": "[feə(r)]", "translate": "书市"},
54
+          {"word": "writer", "soundmark": "[ˈraɪtə(r)]", "translate": "作家;作者"},
55
+          {"word": "read", "soundmark": "[riːd]", "translate": "(过去式 read /red/)阅读"},
56
+          {"word": "make", "soundmark": "[meɪk]", "translate": "(过去式 made /meɪd/)做;使出现"},
57
+          {"word": "sing", "soundmark": "[sɪŋ]", "translate": "(过去式 sang /sæŋ/)唱(歌);演唱"},
58
+          {"word": "wear", "soundmark": "[weə(r)]", "translate": "(过去式 wore /wɔː(r)/)穿;戴"},
59
+          {"word": "yesterday", "soundmark": "[ˈjestədeɪ]", "translate": "昨天"},
60
+          {"word": "notice", "soundmark": "[ˈnəʊtɪs]", "translate": "通知"},
61
+          {"word": "wake", "soundmark": "[weɪk]", "translate": "(过去式 woke /wəʊk/)醒;醒来"},
62
+          {"word": "later", "soundmark": "[ˈleɪtə(r)]", "translate": "随后;后来"},
63
+          {"word": "judge", "soundmark": "[dʒʌdʒ]", "translate": "裁判"},
64
+          {"word": "begin", "soundmark": "[bɪˈɡɪn]", "translate": "(过去式 began /bɪˈɡæn/)开始"},
65
+          {"word": "win", "soundmark": "[wɪn]", "translate": "(过去式 won /wʌn/)获胜"},
66
+          {"word": "winner", "soundmark": "[ˈwɪnə(r)]", "translate": "获胜的人(或队);成功者"},
67
+          {"word": "ever", "soundmark": "[ˈevə(r)]", "translate": "(进行比较时用于加强语气)以往任何时候"},
68
+          {"word": "exciting", "soundmark": "[ɪkˈsaɪtɪŋ]", "translate": "令人激动的"}
69
+        ]
70
+      },
71
+      {
72
+        "lessonId": 3,
73
+        "lessonName": "Unit 3",
74
+        "entries": [
75
+          {"word": "cold", "soundmark": "[kəʊld]", "translate": "感冒"},
76
+          {"word": "ill", "soundmark": "[ɪl]", "translate": "不舒服;生病的"},
77
+          {"word": "head", "soundmark": "[hed]", "translate": "头;头部"},
78
+          {"word": "runny nose", "soundmark": "[ˈrʌni]", "translate": "流鼻涕"},
79
+          {"word": "soon", "soundmark": "[suːn]", "translate": "很快;马上"},
80
+          {"word": "fever", "soundmark": "[ˈfiːvə(r)]", "translate": "发烧;发热"},
81
+          {"word": "cough", "soundmark": "[kɒf]", "translate": "咳嗽"},
82
+          {"word": "discuss", "soundmark": "[dɪˈskʌs]", "translate": "讨论;商量"},
83
+          {"word": "diet", "soundmark": "[ˈdaɪət]", "translate": "日常饮食"},
84
+          {"word": "stay up", "soundmark": null, "translate": "熬夜"},
85
+          {"word": "cry", "soundmark": "[kraɪ]", "translate": "哭;哭泣"},
86
+          {"word": "another", "soundmark": "[əˈnʌðə(r)]", "translate": "另一;不同的(人或事物)"},
87
+          {"word": "call", "soundmark": "[kɔːl]", "translate": "(给……)打电话"},
88
+          {"word": "email", "soundmark": "[ˈiːmeɪl]", "translate": "电子邮件"},
89
+          {"word": "unhappy", "soundmark": "[ʌnˈhæpi]", "translate": "不快乐的;难过的"},
90
+          {"word": "glass", "soundmark": "[ɡlɑːs]", "translate": "一杯(的量);玻璃"},
91
+          {"word": "may", "soundmark": "[meɪ]", "translate": "也许;可能"},
92
+          {"word": "add", "soundmark": "[æd]", "translate": "补充说;增加"},
93
+          {"word": "video", "soundmark": "[ˈvɪdiəʊ]", "translate": "视频;录像"},
94
+          {"word": "better", "soundmark": "[ˈbetə(r)]", "translate": "舒畅些的;(病势)好转的"}
95
+        ]
96
+      },
97
+      {
98
+        "lessonId": 4,
99
+        "lessonName": "Unit 4",
100
+        "entries": [
101
+          {"word": "money", "soundmark": "[ˈmʌni]", "translate": "钱"},
102
+          {"word": "pocket money", "soundmark": "[ˈpɒkɪt]", "translate": "零花钱"},
103
+          {"word": "schoolbag", "soundmark": "[ˈskuːlbæɡ]", "translate": "书包"},
104
+          {"word": "goods", "soundmark": "[ɡʊdz]", "translate": "商品"},
105
+          {"word": "drink", "soundmark": "[drɪŋk]", "translate": "饮料"},
106
+          {"word": "service", "soundmark": "[ˈsɜːvɪs]", "translate": "服务"},
107
+          {"word": "haircut", "soundmark": "[ˈheəkʌt]", "translate": "理发;发型"},
108
+          {"word": "microscope", "soundmark": "[ˈmaɪkrəskəʊp]", "translate": "显微镜"},
109
+          {"word": "lucky", "soundmark": "[ˈlʌki]", "translate": "幸运的"},
110
+          {"word": "half", "soundmark": "[hɑːf]", "translate": "一半"},
111
+          {"word": "save up", "soundmark": null, "translate": "攒钱"},
112
+          {"word": "sale", "soundmark": "[seɪl]", "translate": "特价销售;出售"},
113
+          {"word": "ticket", "soundmark": "[ˈtɪkɪt]", "translate": "票"},
114
+          {"word": "manage", "soundmark": "[ˈmænɪdʒ]", "translate": "管理"},
115
+          {"word": "sell", "soundmark": "[sel]", "translate": "出售;售卖"},
116
+          {"word": "jar", "soundmark": "[dʒɑː(r)]", "translate": "罐子"},
117
+          {"word": "for example", "soundmark": "[ɪɡˈzɑːmpl]", "translate": "例如"}
118
+        ]
119
+      },
120
+      {
121
+        "lessonId": 5,
122
+        "lessonName": "Unit 5",
123
+        "entries": [
124
+          {"word": "planet", "soundmark": "[ˈplænɪt]", "translate": "行星"},
125
+          {"word": "earth", "soundmark": "[ɜːθ]", "translate": "(also Earth)地球"},
126
+          {"word": "sky", "soundmark": "[skaɪ]", "translate": "天;天空"},
127
+          {"word": "daytime", "soundmark": "[ˈdeɪtaɪm]", "translate": "白天"},
128
+          {"word": "cloud", "soundmark": "[klaʊd]", "translate": "云"},
129
+          {"word": "moon", "soundmark": "[muːn]", "translate": "(also the Moon)月球;月亮;卫星"},
130
+          {"word": "star", "soundmark": "[stɑː(r)]", "translate": "恒星;星"},
131
+          {"word": "space", "soundmark": "[speɪs]", "translate": "太空;空间"},
132
+          {"word": "outer space", "soundmark": "[ˈaʊtə(r)]", "translate": "外太空"},
133
+          {"word": "space station", "soundmark": null, "translate": "空间站"},
134
+          {"word": "ocean", "soundmark": "[ˈəʊʃn]", "translate": "大海;海洋"},
135
+          {"word": "marble", "soundmark": "[ˈmɑːbl]", "translate": "(玻璃)弹子"},
136
+          {"word": "satellite", "soundmark": "[ˈsætəlaɪt]", "translate": "人造卫星"},
137
+          {"word": "soil", "soundmark": "[sɔɪl]", "translate": "土壤"},
138
+          {"word": "alien", "soundmark": "[ˈeɪliən]", "translate": "外星生物"},
139
+          {"word": "sunrise", "soundmark": "[ˈsʌnraɪz]", "translate": "日出"},
140
+          {"word": "rover", "soundmark": "[ˈrəʊvə(r)]", "translate": "探测器"},
141
+          {"word": "into", "soundmark": "[ˈɪntə]", "translate": "朝;进入"},
142
+          {"word": "telescope", "soundmark": "[ˈtelɪskəʊp]", "translate": "望远镜"},
143
+          {"word": "astronaut", "soundmark": "[ˈæstrənɔːt]", "translate": "航天员;宇航员"},
144
+          {"word": "spaceship", "soundmark": "[ˈspeɪsʃɪp]", "translate": "宇宙飞船"},
145
+          {"word": "month", "soundmark": "[mʌnθ]", "translate": "月;月份"},
146
+          {"word": "taikonaut", "soundmark": "[ˈtaɪkənɔːt]", "translate": "中国航天员"},
147
+          {"word": "cloth", "soundmark": "[klɒθ]", "translate": "(一块)布;织物"},
148
+          {"word": "toothpaste", "soundmark": "[ˈtuːθpeɪst]", "translate": "牙膏"},
149
+          {"word": "question", "soundmark": "[ˈkwestʃən]", "translate": "问题"},
150
+          {"word": "sunset", "soundmark": "[ˈsʌnset]", "translate": "日落"},
151
+          {"word": "time", "soundmark": "[taɪm]", "translate": "次;回"},
152
+          {"word": "Mars", "soundmark": "[mɑːz]", "translate": "火星"}
153
+        ]
154
+      },
155
+      {
156
+        "lessonId": 6,
157
+        "lessonName": "Unit 6",
158
+        "entries": [
159
+          {"word": "power", "soundmark": "[ˈpaʊə(r)]", "translate": "能;能量"},
160
+          {"word": "electricity", "soundmark": "[ɪˌlekˈtrɪsəti]", "translate": "电"},
161
+          {"word": "solar", "soundmark": "[ˈsəʊlə(r)]", "translate": "太阳的"},
162
+          {"word": "type", "soundmark": "[taɪp]", "translate": "类型;种类"},
163
+          {"word": "energy", "soundmark": "[ˈenədʒi]", "translate": "能源"},
164
+          {"word": "light", "soundmark": "[laɪt]", "translate": "照亮"},
165
+          {"word": "heat", "soundmark": "[hiːt]", "translate": "加热;(使)变暖;热量"},
166
+          {"word": "cool", "soundmark": "[kuːl]", "translate": "(使)变凉,冷却"},
167
+          {"word": "run", "soundmark": "[rʌn]", "translate": "(使)运转"},
168
+          {"word": "resource", "soundmark": "[rɪˈsɔːs]", "translate": "资源"},
169
+          {"word": "run out", "soundmark": null, "translate": "用完"},
170
+          {"word": "change", "soundmark": "[tʃeɪndʒ]", "translate": "(使)不同;改变"},
171
+          {"word": "quick", "soundmark": "[kwɪk]", "translate": "迅速的;快的"},
172
+          {"word": "shower", "soundmark": "[ˈʃaʊə(r)]", "translate": "淋浴"},
173
+          {"word": "unplug", "soundmark": "[ˌʌnˈplʌɡ]", "translate": "拔掉……的电源插头"},
174
+          {"word": "difference", "soundmark": "[ˈdɪfrəns]", "translate": "差别;不同(之处)"},
175
+          {"word": "reduce", "soundmark": "[rɪˈdjuːs]", "translate": "减少"},
176
+          {"word": "air conditioner", "soundmark": "[ˈeə kəndɪʃənə(r)]", "translate": "空调机"},
177
+          {"word": "drive", "soundmark": "[draɪv]", "translate": "驾驶;开车"},
178
+          {"word": "reuse", "soundmark": "[ˌriːˈjuːz]", "translate": "再次使用;重复使用"},
179
+          {"word": "own", "soundmark": "[əʊn]", "translate": "自己的"},
180
+          {"word": "market", "soundmark": "[ˈmɑːkɪt]", "translate": "集市;市场"},
181
+          {"word": "bottle", "soundmark": "[ˈbɒtl]", "translate": "瓶子"},
182
+          {"word": "top", "soundmark": "[tɒp]", "translate": "(位置、级别或程度)最高的"},
183
+          {"word": "useful", "soundmark": "[ˈjuːsfl]", "translate": "有用的;有益的"},
184
+          {"word": "dirty", "soundmark": "[ˈdɜːti]", "translate": "脏的"},
185
+          {"word": "side", "soundmark": "[saɪd]", "translate": "一面;一边"}
186
+        ]
187
+      }
188
+    ]
189
+  },
190
+  {
191
+    "label": "英语六年级上常用表达法",
192
+    "miaoguoBookId": 299,
193
+    "bookIdOld": 205,
194
+    "wordNum": 54,
195
+    "units": [
196
+      {
197
+        "lessonId": 1,
198
+        "lessonName": "Unit 1",
199
+        "entries": [
200
+          {"word": "How was your weekend?", "translate": "你周末过得怎么样?"},
201
+          {"word": "It was great! I climbed the Great Wall.", "translate": "非常棒!我去爬长城了。"},
202
+          {"word": "What did you do, Leo?", "translate": "你做什么了,利奥?"},
203
+          {"word": "I visited the \"Gingerbread House\" last Saturday.", "translate": "我上个星期六去参观“姜饼屋”了。"},
204
+          {"word": "Where did you go over the summer holidays, Binbin?", "translate": "你暑假去哪儿了,斌斌?"},
205
+          {"word": "I went to Xiˈan with my family.", "translate": "我和家人去西安了。"},
206
+          {"word": "What did you do there?", "translate": "你们在那儿做了些什么?"},
207
+          {"word": "We went to see the Terracotta Warriors.", "translate": "我们去看兵马俑了。"},
208
+          {"word": "What else did you do?", "translate": "你们还做什么了?"}
209
+        ]
210
+      },
211
+      {
212
+        "lessonId": 2,
213
+        "lessonName": "Unit 2",
214
+        "entries": [
215
+          {"word": "How was your Mid-Autumn Festival holiday, Binbin?", "translate": "你中秋假期过得怎么样,斌斌?"},
216
+          {"word": "It was great.", "translate": "非常棒!"},
217
+          {"word": "Did you take a trip?", "translate": "你们去旅行了吗?"},
218
+          {"word": "No, we didnˈt.", "translate": "不,我们没有。"},
219
+          {"word": "Did you eat mooncakes?", "translate": "你们吃月饼了吗?"},
220
+          {"word": "Yes, we did.", "translate": "是的,我们吃了。"},
221
+          {"word": "My mother and I went to a marathon on Sunday.", "translate": "我和妈妈上周日去看了一场马拉松比赛。"},
222
+          {"word": "What did you like about it?", "translate": "你喜欢它哪一点?"},
223
+          {"word": "I liked watching the runners.", "translate": "我喜欢看参赛者(跑步)。"},
224
+          {"word": "What did you do last weekend?", "translate": "你上周末做什么了?"}
225
+        ]
226
+      },
227
+      {
228
+        "lessonId": 3,
229
+        "lessonName": "Unit 3",
230
+        "entries": [
231
+          {"word": "How do you feel?", "translate": "你感觉怎么样?"},
232
+          {"word": "I feel ill. My head hurts and I have a runny nose.", "translate": "我感觉不舒服。我头痛还流鼻涕。"},
233
+          {"word": "Iˈm sorry to hear that. Maybe you should see a doctor.", "translate": "对此我感到难过。也许你应该去看医生。"},
234
+          {"word": "How can we live a healthy life?", "translate": "我们怎样能过健康的生活?"},
235
+          {"word": "We need to eat healthy food. We should exercise too.", "translate": "我们需要吃健康的食物。我们还需要运动。"},
236
+          {"word": "Have a healthy diet.", "translate": "(保持)健康的饮食。"},
237
+          {"word": "Donˈt stay up late.", "translate": "不要熬夜。"},
238
+          {"word": "Think about happy things.", "translate": "想开心的事情。"},
239
+          {"word": "Join clubs and teams.", "translate": "加入俱乐部和团队。"}
240
+        ]
241
+      },
242
+      {
243
+        "lessonId": 4,
244
+        "lessonName": "Unit 4",
245
+        "entries": [
246
+          {"word": "How are you going to spend it?", "translate": "你打算怎么花(这些钱)?"},
247
+          {"word": "Iˈm going to buy a schoolbag.", "translate": "我打算买一个书包。"},
248
+          {"word": "I also want to buy some animal books.", "translate": "我还想买一些动物类书籍。"},
249
+          {"word": "What else are you going to buy?", "translate": "你还打算买什么?"},
250
+          {"word": "Iˈm going to buy a pair of sunglasses for Grandpa.", "translate": "我打算给爷爷买一副太阳镜。"},
251
+          {"word": "I also want to buy a microscope.", "translate": "我还想买一个显微镜。"}
252
+        ]
253
+      },
254
+      {
255
+        "lessonId": 5,
256
+        "lessonName": "Unit 5",
257
+        "entries": [
258
+          {"word": "What can you see in the sky?", "translate": "你能在天空中看到什么?"},
259
+          {"word": "We can see the Sun and clouds.", "translate": "我们能看到太阳和云。"},
260
+          {"word": "At night, we can see the Moon and the stars.", "translate": "在晚上,我们能看到月亮和星星。"},
261
+          {"word": "Is there any water on Mars?", "translate": "火星上有水吗?"},
262
+          {"word": "Yes, there is. There is soil too.", "translate": "是,有的。那里还有土壤。"},
263
+          {"word": "Are there any aliens?", "translate": "那儿有外星生物吗?"},
264
+          {"word": "I donˈt think so. They say there arenˈt any living things.", "translate": "我不这样认为。据说那里没有生物。"},
265
+          {"word": "China put a rover on Mars.", "translate": "中国在火星上放置了探测器。"},
266
+          {"word": "The taikonauts get up early in the morning.", "translate": "中国航天员很早就起床。"}
267
+        ]
268
+      },
269
+      {
270
+        "lessonId": 6,
271
+        "lessonName": "Unit 6",
272
+        "entries": [
273
+          {"word": "What do you know about it?", "translate": "关于它你知道些什么?"},
274
+          {"word": "Running water can make electricity.", "translate": "流水可以发电。"},
275
+          {"word": "What else do you want to know about water?", "translate": "关于水你还想了解些什么?"},
276
+          {"word": "Where does water come from?", "translate": "水从哪儿来?"},
277
+          {"word": "Wind power, solar power and water power are types of green energy.", "translate": "风能、太阳能和水能是不同类型的绿色能源。"},
278
+          {"word": "But many resources are running out.", "translate": "但是很多资源快要耗尽了。"},
279
+          {"word": "What should we do?", "translate": "我们该怎么办?"},
280
+          {"word": "How can we save energy?", "translate": "我们怎样才能节约能源?"},
281
+          {"word": "We can take quick showers.", "translate": "我们可以快速淋浴。"},
282
+          {"word": "We can also use LED lighting.", "translate": "我们还可以使用LED照明。"},
283
+          {"word": "We should use air conditioners less.", "translate": "我们应该少用空调。"}
284
+        ]
285
+      }
286
+    ]
287
+  }
288
+]

+ 202 - 0
.vscode/秒过知识库更新/source_miaoguo_literacy_2026_fall.json

@@ -0,0 +1,202 @@
1
+[
2
+  {
3
+    "word": "结账",
4
+    "templateWord": "结算",
5
+    "pinyin": "jié zhàng",
6
+    "explain": "结算账目,也指结算消费的费用:饭后结账。",
7
+    "english": ["settle accounts", "pay the bill"],
8
+    "synonym": ["结算", "买单"],
9
+    "antonym": [],
10
+    "sourceUrl": "https://www.zdic.net/hans/结账"
11
+  },
12
+  {
13
+    "word": "航线",
14
+    "templateWord": "路线",
15
+    "pinyin": "háng xiàn",
16
+    "explain": "飞机或船舶预先规划的航行路线。",
17
+    "english": ["air or shipping route"],
18
+    "synonym": ["航路", "路线"],
19
+    "antonym": [],
20
+    "sourceUrl": "https://www.zdic.net/hans/航线"
21
+  },
22
+  {
23
+    "word": "热量",
24
+    "templateWord": "能量",
25
+    "pinyin": "rè liàng",
26
+    "explain": "1.由于温度差别而转移的能量。\n2.食物经人体消化吸收后可以提供的能量。",
27
+    "english": ["heat", "quantity of heat"],
28
+    "synonym": ["能量"],
29
+    "antonym": [],
30
+    "sourceUrl": "https://www.zdic.net/hans/热量"
31
+  },
32
+  {
33
+    "word": "星斗",
34
+    "templateWord": "星星",
35
+    "pinyin": "xīng dǒu",
36
+    "explain": "星的总称:满天星斗。",
37
+    "english": ["stars"],
38
+    "synonym": ["星星", "星辰"],
39
+    "antonym": [],
40
+    "sourceUrl": "https://www.zdic.net/hans/星斗"
41
+  },
42
+  {
43
+    "word": "兄友弟恭",
44
+    "templateWord": "父慈子孝",
45
+    "pinyin": "xiōng yǒu dì gōng",
46
+    "explain": "哥哥对弟弟友爱,弟弟对哥哥恭敬。形容兄弟间互爱互敬。",
47
+    "english": ["brothers show mutual love and respect"],
48
+    "synonym": [],
49
+    "antonym": [],
50
+    "sourceUrl": "https://www.zdic.net/hans/兄友弟恭"
51
+  },
52
+  {
53
+    "word": "湘菜",
54
+    "templateWord": "湘绣",
55
+    "pinyin": "xiāng cài",
56
+    "explain": "湖南风味的菜肴。",
57
+    "english": ["Hunan cuisine"],
58
+    "synonym": ["湖南菜"],
59
+    "antonym": [],
60
+    "sourceUrl": "https://www.zdic.net/hans/湘菜"
61
+  },
62
+  {
63
+    "word": "粤菜",
64
+    "templateWord": "湘绣",
65
+    "pinyin": "yuè cài",
66
+    "explain": "以广东风味为代表的菜肴。",
67
+    "english": ["Cantonese cuisine"],
68
+    "synonym": ["广东菜"],
69
+    "antonym": [],
70
+    "sourceUrl": "https://www.zdic.net/hans/粤菜"
71
+  },
72
+  {
73
+    "word": "苏绣",
74
+    "templateWord": "蜀绣",
75
+    "pinyin": "sū xiù",
76
+    "explain": "江苏苏州出产的刺绣。",
77
+    "english": ["Suzhou embroidery"],
78
+    "synonym": [],
79
+    "antonym": [],
80
+    "sourceUrl": "https://www.zdic.net/hans/苏绣"
81
+  },
82
+  {
83
+    "word": "滇剧",
84
+    "templateWord": "沪剧",
85
+    "pinyin": "diān jù",
86
+    "explain": "云南的主要戏曲剧种之一。唱腔以皮黄为主,流行于云南以及四川、贵州的部分地区。",
87
+    "english": ["Yunnan opera", "Dian opera"],
88
+    "synonym": [],
89
+    "antonym": [],
90
+    "sourceUrl": "https://www.zdic.net/hans/滇剧"
91
+  },
92
+  {
93
+    "word": "民居",
94
+    "templateWord": "住宅",
95
+    "pinyin": "mín jū",
96
+    "explain": "民间房舍;百姓居住的房屋。",
97
+    "english": ["dwelling", "folk house"],
98
+    "synonym": ["民宅", "民房"],
99
+    "antonym": [],
100
+    "sourceUrl": "https://www.zdic.net/hans/民居"
101
+  },
102
+  {
103
+    "word": "公事",
104
+    "templateWord": "事情",
105
+    "pinyin": "gōng shì",
106
+    "explain": "公家的事;集体的事(区别于“私事”):公事公办。",
107
+    "english": ["official business"],
108
+    "synonym": ["公务"],
109
+    "antonym": ["私事"],
110
+    "sourceUrl": "https://www.zdic.net/hans/公事"
111
+  },
112
+  {
113
+    "word": "处世",
114
+    "templateWord": "为人处世",
115
+    "pinyin": "chǔ shì",
116
+    "explain": "在社会上活动,跟人交往:立身处世。",
117
+    "english": ["conduct oneself in society"],
118
+    "synonym": ["待人接物", "为人处世"],
119
+    "antonym": [],
120
+    "sourceUrl": "https://www.zdic.net/hans/处世"
121
+  },
122
+  {
123
+    "word": "回敬",
124
+    "templateWord": "回报",
125
+    "pinyin": "huí jìng",
126
+    "explain": "回报别人给予的敬意或馈赠;也指用同样的方式回应。",
127
+    "english": ["reciprocate", "return a courtesy"],
128
+    "synonym": ["回报", "回赠"],
129
+    "antonym": [],
130
+    "sourceUrl": "https://www.zdic.net/hans/回敬"
131
+  },
132
+  {
133
+    "word": "落空",
134
+    "templateWord": "失败",
135
+    "pinyin": "luò kōng",
136
+    "explain": "没有达到目的或得到预期的结果:希望落空。",
137
+    "english": ["come to nothing", "fall through"],
138
+    "synonym": ["破灭", "失败"],
139
+    "antonym": ["实现"],
140
+    "sourceUrl": "https://www.zdic.net/hans/落空"
141
+  },
142
+  {
143
+    "word": "表明",
144
+    "templateWord": "表示",
145
+    "pinyin": "biǎo míng",
146
+    "explain": "清楚地表示:表明态度。",
147
+    "english": ["indicate", "make known"],
148
+    "synonym": ["表示", "说明"],
149
+    "antonym": ["隐瞒"],
150
+    "sourceUrl": "https://www.zdic.net/hans/表明"
151
+  },
152
+  {
153
+    "word": "进一步",
154
+    "templateWord": "为人处世",
155
+    "pinyin": "jìn yī bù",
156
+    "explain": "表示事情在原有基础上向前发展或程度提高:进一步了解情况。",
157
+    "english": ["further", "go a step further"],
158
+    "synonym": ["深入"],
159
+    "antonym": [],
160
+    "sourceUrl": "https://www.zdic.net/hans/进一步"
161
+  },
162
+  {
163
+    "word": "自制",
164
+    "templateWord": "制作",
165
+    "pinyin": "zì zhì",
166
+    "explain": "1.自己制造:自制教具。\n2.克制自己:难以自制。",
167
+    "english": ["self-made", "self-control"],
168
+    "synonym": ["自造", "克制"],
169
+    "antonym": [],
170
+    "sourceUrl": "https://www.zdic.net/hans/自制"
171
+  },
172
+  {
173
+    "word": "不由得",
174
+    "templateWord": "禁不住",
175
+    "pinyin": "bù yóu de",
176
+    "explain": "1.不禁,忍不住:不由得笑了起来。\n2.不容许:不由得你不信。",
177
+    "english": ["cannot help", "cannot but"],
178
+    "synonym": ["不禁", "忍不住"],
179
+    "antonym": [],
180
+    "sourceUrl": "https://www.zdic.net/hans/不由得"
181
+  },
182
+  {
183
+    "word": "甜丝丝",
184
+    "templateWord": "甜津津",
185
+    "pinyin": "tián sī sī",
186
+    "explain": "状态词。形容有甜味;也形容感到幸福愉快:心里甜丝丝的。",
187
+    "english": ["pleasantly sweet"],
188
+    "synonym": ["甜津津", "甜滋滋"],
189
+    "antonym": ["苦涩"],
190
+    "sourceUrl": "https://www.zdic.net/hans/甜丝丝"
191
+  },
192
+  {
193
+    "word": "入神",
194
+    "templateWord": "专心",
195
+    "pinyin": "rù shén",
196
+    "explain": "1.对某事物兴趣浓厚而精神高度集中:听得入神。\n2.形容技艺达到精妙的境界。",
197
+    "english": ["be absorbed", "be entranced"],
198
+    "synonym": ["入迷", "专心", "专注"],
199
+    "antonym": ["分心", "走神"],
200
+    "sourceUrl": "https://www.zdic.net/hans/入神"
201
+  }
202
+]

+ 581 - 0
.vscode/秒过知识库更新/update_knowledge_base_2026_fall.mjs

@@ -0,0 +1,581 @@
1
+#!/usr/bin/env node
2
+
3
+import assert from "node:assert/strict";
4
+import fs from "node:fs";
5
+import path from "node:path";
6
+import { fileURLToPath } from "node:url";
7
+import mysql from "mysql2/promise";
8
+import config from "../../src/config/dev.js";
9
+
10
+const taskDir = path.dirname(fileURLToPath(import.meta.url));
11
+const chineseSourcePath = path.join(taskDir, "source_chinese_2026_fall.json");
12
+const englishSourcePath = path.join(taskDir, "source_english_2026_fall.json");
13
+const chineseSources = JSON.parse(fs.readFileSync(chineseSourcePath, "utf8"));
14
+const englishSources = JSON.parse(fs.readFileSync(englishSourcePath, "utf8"));
15
+
16
+const flags = new Set(process.argv.slice(2));
17
+const knownFlags = new Set(["--dry-run", "--apply", "--audit"]);
18
+for (const flag of flags) {
19
+  assert(knownFlags.has(flag), `不支持的参数:${flag}`);
20
+}
21
+assert(
22
+  ["--dry-run", "--apply", "--audit"].filter((flag) => flags.has(flag)).length <= 1,
23
+  "--dry-run、--apply、--audit 只能选择一个",
24
+);
25
+const mode = flags.has("--apply") ? "apply" : flags.has("--audit") ? "audit" : "dry-run";
26
+
27
+const targetMiaoguoBookIds = [...chineseSources, ...englishSources].map(
28
+  (source) => source.miaoguoBookId,
29
+);
30
+const targetHanziBookIds = chineseSources.map((source) => source.bookIdOld);
31
+const targetEnglishBookIds = englishSources.map((source) => source.bookIdOld);
32
+
33
+function nowForFile() {
34
+  return new Date().toISOString().replaceAll(":", "-").replaceAll(".", "-");
35
+}
36
+
37
+function writeJson(filePath, data) {
38
+  fs.writeFileSync(filePath, `${JSON.stringify(data, null, 2)}\n`, "utf8");
39
+}
40
+
41
+function countChineseWords(source) {
42
+  if (source.unitType === 2) {
43
+    return source.units.reduce(
44
+      (total, unit) => total + unit.example.split(",").filter(Boolean).length,
45
+      0,
46
+    );
47
+  }
48
+  return source.units.reduce((total, unit) => total + Array.from(unit.example).length, 0);
49
+}
50
+
51
+function flattenEnglish(source) {
52
+  return source.units.flatMap((unit) =>
53
+    unit.entries.map((entry, index) => ({
54
+      Word: entry.word,
55
+      WordRemark: null,
56
+      Level: null,
57
+      BookID: source.bookIdOld,
58
+      LessonID: unit.lessonId,
59
+      LessonName: unit.lessonName,
60
+      Soundmark: entry.soundmark ?? null,
61
+      Translate: entry.translate,
62
+      EnglishExplanation: null,
63
+      ExampleSentence: null,
64
+      Sort: index + 1,
65
+    })),
66
+  );
67
+}
68
+
69
+function validateSources() {
70
+  assert.equal(chineseSources.length, 8, "本批次应有 8 个语文数据集");
71
+  assert.equal(englishSources.length, 2, "本批次应有 2 个英语数据集");
72
+  assert.equal(
73
+    new Set(targetMiaoguoBookIds).size,
74
+    targetMiaoguoBookIds.length,
75
+    "MiaoguoBook ID 不能重复",
76
+  );
77
+  assert.equal(
78
+    new Set([...targetHanziBookIds, ...targetEnglishBookIds]).size,
79
+    targetHanziBookIds.length + targetEnglishBookIds.length,
80
+    "BookIDOld 不能重复",
81
+  );
82
+
83
+  for (const source of chineseSources) {
84
+    assert([1, 2, 5].includes(source.unitType), `${source.label} UnitType 不正确`);
85
+    assert(source.units.length > 0, `${source.label} 没有单元`);
86
+    for (const unit of source.units) {
87
+      assert(unit.name?.length > 0, `${source.label} 存在空 Name`);
88
+      assert(unit.example?.length > 0, `${source.label}/${unit.name} 存在空 Example`);
89
+    }
90
+    assert.equal(
91
+      countChineseWords(source),
92
+      source.wordNum,
93
+      `${source.label} 由 Example 计算出的字/词数与 WordNum 不一致`,
94
+    );
95
+    if (source.unitType === 1) {
96
+      assert.equal(
97
+        source.officialWordNum + source.blueCharacterCount,
98
+        source.wordNum,
99
+        `${source.label} 黑字数 + 蓝色多音字数与 WordNum 不一致`,
100
+      );
101
+    }
102
+  }
103
+
104
+  for (const source of englishSources) {
105
+    assert(source.units.length > 0, `${source.label} 没有单元`);
106
+    assert.deepEqual(
107
+      source.units.map((unit) => unit.lessonId),
108
+      source.units.map((_, index) => index + 1),
109
+      `${source.label} LessonID 必须从 1 连续递增`,
110
+    );
111
+    for (const unit of source.units) {
112
+      assert.equal(unit.lessonName, `Unit ${unit.lessonId}`, `${source.label} LessonName 不正确`);
113
+      for (const entry of unit.entries) {
114
+        assert(entry.word?.length > 0, `${source.label}/${unit.lessonName} 存在空 Word`);
115
+        assert(entry.translate?.length > 0, `${source.label}/${unit.lessonName} 存在空 Translate`);
116
+        if (entry.soundmark != null) {
117
+          assert(
118
+            entry.soundmark.startsWith("[") && entry.soundmark.endsWith("]"),
119
+            `${source.label}/${entry.word} 音标必须使用方括号`,
120
+          );
121
+        }
122
+      }
123
+    }
124
+    assert.equal(
125
+      flattenEnglish(source).length,
126
+      source.wordNum,
127
+      `${source.label} 条目数与 WordNum 不一致`,
128
+    );
129
+  }
130
+}
131
+
132
+async function readState(connection, forUpdate = false) {
133
+  const lock = forUpdate ? " FOR UPDATE" : "";
134
+  const [books] = await connection.query(
135
+    `SELECT * FROM MiaoguoBook WHERE ID IN (?) ORDER BY ID${lock}`,
136
+    [targetMiaoguoBookIds],
137
+  );
138
+  const [hanziRows] = await connection.query(
139
+    `SELECT * FROM HanziUnit WHERE HanziBookID IN (?) ORDER BY HanziBookID,OrderID,ID${lock}`,
140
+    [targetHanziBookIds],
141
+  );
142
+  const [englishRows] = await connection.query(
143
+    `SELECT * FROM Words WHERE BookID IN (?) ORDER BY BookID,LessonID,Sort,ID${lock}`,
144
+    [targetEnglishBookIds],
145
+  );
146
+  return { books, hanziRows, englishRows };
147
+}
148
+
149
+function validateDatabaseMappings(state) {
150
+  assert.equal(state.books.length, targetMiaoguoBookIds.length, "目标 MiaoguoBook 记录不完整");
151
+  for (const source of [...chineseSources, ...englishSources]) {
152
+    const book = state.books.find((row) => row.ID === source.miaoguoBookId);
153
+    assert(book, `MiaoguoBook.ID=${source.miaoguoBookId} 不存在`);
154
+    assert.equal(
155
+      book.BookIDOld,
156
+      source.bookIdOld,
157
+      `${source.label} 的 BookIDOld 与源数据映射不一致`,
158
+    );
159
+  }
160
+}
161
+
162
+async function validateHanziDictionary(connection) {
163
+  const chars = [
164
+    ...new Set(
165
+      chineseSources
166
+        .filter((source) => source.unitType === 1 || source.unitType === 5)
167
+        .flatMap((source) => source.units.flatMap((unit) => Array.from(unit.example))),
168
+    ),
169
+  ];
170
+  const [rows] = await connection.query("SELECT DISTINCT Name FROM HanziWord WHERE Name IN (?)", [
171
+    chars,
172
+  ]);
173
+  const found = new Set(rows.map((row) => row.Name));
174
+  const missing = chars.filter((char) => !found.has(char));
175
+  assert.equal(missing.length, 0, `HanziWord 缺少 ${missing.length} 个字:${missing.join("")}`);
176
+  return { checkedDistinctCharacters: chars.length, missing: [] };
177
+}
178
+
179
+function buildChinesePlan(source, state) {
180
+  const existing = state.hanziRows.filter((row) => row.HanziBookID === source.bookIdOld);
181
+  assert(
182
+    existing.length <= source.units.length,
183
+    `${source.label} 现有 ${existing.length} 行、新版只有 ${source.units.length} 行;语文禁止删除,不能自动执行`,
184
+  );
185
+
186
+  const matched = Array(source.units.length).fill(null);
187
+  const usedIds = new Set();
188
+  const buckets = new Map();
189
+  for (const row of existing) {
190
+    const rows = buckets.get(row.Name) ?? [];
191
+    rows.push(row);
192
+    buckets.set(row.Name, rows);
193
+  }
194
+
195
+  for (let index = 0; index < source.units.length; index += 1) {
196
+    const candidates = buckets.get(source.units[index].name) ?? [];
197
+    const row = candidates.find((candidate) => !usedIds.has(candidate.ID));
198
+    if (row) {
199
+      matched[index] = row;
200
+      usedIds.add(row.ID);
201
+    }
202
+  }
203
+
204
+  const unusedRows = existing.filter((row) => !usedIds.has(row.ID));
205
+  let unusedIndex = 0;
206
+  for (let index = 0; index < source.units.length; index += 1) {
207
+    if (!matched[index] && unusedIndex < unusedRows.length) {
208
+      matched[index] = unusedRows[unusedIndex];
209
+      usedIds.add(unusedRows[unusedIndex].ID);
210
+      unusedIndex += 1;
211
+    }
212
+  }
213
+
214
+  const operations = source.units.map((unit, index) => {
215
+    const old = matched[index];
216
+    return {
217
+      action: old ? (old.Name === unit.name ? "UPDATE_SAME_NAME" : "UPDATE_REPURPOSE") : "INSERT",
218
+      id: old?.ID ?? null,
219
+      oldName: old?.Name ?? null,
220
+      oldExample: old?.Example ?? null,
221
+      oldIsLocked: old?.IsLocked ?? null,
222
+      name: unit.name,
223
+      example: unit.example,
224
+      unitType: source.unitType,
225
+      orderId: index + 1,
226
+      isLocked: old?.IsLocked ?? 1,
227
+    };
228
+  });
229
+
230
+  return {
231
+    label: source.label,
232
+    miaoguoBookId: source.miaoguoBookId,
233
+    bookIdOld: source.bookIdOld,
234
+    currentRows: existing.length,
235
+    targetRows: source.units.length,
236
+    currentWordNum: state.books.find((book) => book.ID === source.miaoguoBookId).WordNum,
237
+    targetWordNum: source.wordNum,
238
+    currentUnitNum: state.books.find((book) => book.ID === source.miaoguoBookId).UnitNum,
239
+    targetUnitNum: source.units.length,
240
+    sameNameUpdates: operations.filter((item) => item.action === "UPDATE_SAME_NAME").length,
241
+    repurposedUpdates: operations.filter((item) => item.action === "UPDATE_REPURPOSE").length,
242
+    inserts: operations.filter((item) => item.action === "INSERT").length,
243
+    deletes: 0,
244
+    operations,
245
+  };
246
+}
247
+
248
+function buildPlan(state, dictionaryCheck) {
249
+  const chinese = chineseSources.map((source) => buildChinesePlan(source, state));
250
+  const english = englishSources.map((source) => {
251
+    const currentRows = state.englishRows.filter((row) => row.BookID === source.bookIdOld);
252
+    const book = state.books.find((row) => row.ID === source.miaoguoBookId);
253
+    return {
254
+      label: source.label,
255
+      miaoguoBookId: source.miaoguoBookId,
256
+      bookIdOld: source.bookIdOld,
257
+      currentRows: currentRows.length,
258
+      deleteRows: currentRows.length,
259
+      insertRows: flattenEnglish(source).length,
260
+      currentUnitNum: book.UnitNum,
261
+      targetUnitNum: source.units.length,
262
+      currentWordNum: book.WordNum,
263
+      targetWordNum: source.wordNum,
264
+      perUnit: source.units.map((unit) => ({
265
+        lessonId: unit.lessonId,
266
+        lessonName: unit.lessonName,
267
+        count: unit.entries.length,
268
+      })),
269
+      sortPolicy: "每单元从 1 连续递增,接口按 LessonID,Sort,ID 排序",
270
+    };
271
+  });
272
+  return {
273
+    generatedAt: new Date().toISOString(),
274
+    mode,
275
+    safetyRules: {
276
+      chinese: "只执行 UPDATE/INSERT,永不 DELETE",
277
+      english: "事务内按 BookID 删除旧数据并重建;事务前先落盘备份",
278
+      metadata: "同步更新 MiaoguoBook.UnitNum 和 WordNum",
279
+      transaction: "任一写入或逐条核验失败即 ROLLBACK",
280
+    },
281
+    dictionaryCheck,
282
+    chinese,
283
+    english,
284
+  };
285
+}
286
+
287
+async function applyChinese(connection, plan) {
288
+  for (const bookPlan of plan.chinese) {
289
+    for (const operation of bookPlan.operations) {
290
+      if (operation.action === "INSERT") {
291
+        const [result] = await connection.execute(
292
+          `INSERT INTO HanziUnit
293
+             (HanziBookID,UnitType,Name,Example,IsLocked,OrderID)
294
+           VALUES (?,?,?,?,?,?)`,
295
+          [
296
+            bookPlan.bookIdOld,
297
+            operation.unitType,
298
+            operation.name,
299
+            operation.example,
300
+            operation.isLocked,
301
+            operation.orderId,
302
+          ],
303
+        );
304
+        operation.id = result.insertId;
305
+      } else {
306
+        const [result] = await connection.execute(
307
+          `UPDATE HanziUnit
308
+              SET HanziBookID=?,UnitType=?,Name=?,Example=?,IsLocked=?,OrderID=?
309
+            WHERE ID=?`,
310
+          [
311
+            bookPlan.bookIdOld,
312
+            operation.unitType,
313
+            operation.name,
314
+            operation.example,
315
+            operation.isLocked,
316
+            operation.orderId,
317
+            operation.id,
318
+          ],
319
+        );
320
+        assert.equal(result.affectedRows, 1, `HanziUnit.ID=${operation.id} 更新失败`);
321
+      }
322
+    }
323
+    const [result] = await connection.execute(
324
+      "UPDATE MiaoguoBook SET UnitNum=?,WordNum=? WHERE ID=? AND BookIDOld=?",
325
+      [bookPlan.targetUnitNum, bookPlan.targetWordNum, bookPlan.miaoguoBookId, bookPlan.bookIdOld],
326
+    );
327
+    assert.equal(result.affectedRows, 1, `${bookPlan.label} MiaoguoBook 更新失败`);
328
+  }
329
+}
330
+
331
+async function applyEnglish(connection, plan) {
332
+  for (const source of englishSources) {
333
+    await connection.execute("DELETE FROM Words WHERE BookID=?", [source.bookIdOld]);
334
+    for (const row of flattenEnglish(source)) {
335
+      await connection.execute(
336
+        `INSERT INTO Words
337
+           (Word,WordRemark,Level,BookID,LessonID,LessonName,Soundmark,Translate,
338
+            EnglishExplanation,ExampleSentence,Sort)
339
+         VALUES (?,?,?,?,?,?,?,?,?,?,?)`,
340
+        [
341
+          row.Word,
342
+          row.WordRemark,
343
+          row.Level,
344
+          row.BookID,
345
+          row.LessonID,
346
+          row.LessonName,
347
+          row.Soundmark,
348
+          row.Translate,
349
+          row.EnglishExplanation,
350
+          row.ExampleSentence,
351
+          row.Sort,
352
+        ],
353
+      );
354
+    }
355
+    const englishPlan = plan.english.find((item) => item.bookIdOld === source.bookIdOld);
356
+    const [result] = await connection.execute(
357
+      "UPDATE MiaoguoBook SET UnitNum=?,WordNum=? WHERE ID=? AND BookIDOld=?",
358
+      [
359
+        englishPlan.targetUnitNum,
360
+        englishPlan.targetWordNum,
361
+        englishPlan.miaoguoBookId,
362
+        englishPlan.bookIdOld,
363
+      ],
364
+    );
365
+    assert.equal(result.affectedRows, 1, `${source.label} MiaoguoBook 更新失败`);
366
+  }
367
+}
368
+
369
+function assertEnglishRow(actual, expected, label, index) {
370
+  for (const field of [
371
+    "Word",
372
+    "WordRemark",
373
+    "Level",
374
+    "BookID",
375
+    "LessonID",
376
+    "LessonName",
377
+    "Soundmark",
378
+    "Translate",
379
+    "EnglishExplanation",
380
+    "ExampleSentence",
381
+    "Sort",
382
+  ]) {
383
+    assert.equal(actual[field], expected[field], `${label} 第 ${index + 1} 行 ${field} 不一致`);
384
+  }
385
+}
386
+
387
+async function auditDatabase(connection) {
388
+  const state = await readState(connection);
389
+  validateDatabaseMappings(state);
390
+  const booksById = new Map(state.books.map((book) => [book.ID, book]));
391
+  const result = { passed: true, books: [], chinese: [], english: [] };
392
+
393
+  for (const source of chineseSources) {
394
+    const rows = state.hanziRows.filter((row) => row.HanziBookID === source.bookIdOld);
395
+    assert.equal(rows.length, source.units.length, `${source.label} HanziUnit 行数不一致`);
396
+    rows.forEach((row, index) => {
397
+      assert.equal(row.HanziBookID, source.bookIdOld, `${source.label} 第 ${index + 1} 行 BookID 不一致`);
398
+      assert.equal(row.UnitType, source.unitType, `${source.label} 第 ${index + 1} 行 UnitType 不一致`);
399
+      assert.equal(row.Name, source.units[index].name, `${source.label} 第 ${index + 1} 行 Name 不一致`);
400
+      assert.equal(
401
+        row.Example,
402
+        source.units[index].example,
403
+        `${source.label} 第 ${index + 1} 行 Example 不一致`,
404
+      );
405
+      assert.equal(row.OrderID, index + 1, `${source.label} 第 ${index + 1} 行 OrderID 不一致`);
406
+    });
407
+    const book = booksById.get(source.miaoguoBookId);
408
+    assert.equal(book.UnitNum, source.units.length, `${source.label} UnitNum 不一致`);
409
+    assert.equal(book.WordNum, source.wordNum, `${source.label} WordNum 不一致`);
410
+    result.chinese.push({
411
+      label: source.label,
412
+      miaoguoBookId: source.miaoguoBookId,
413
+      bookIdOld: source.bookIdOld,
414
+      rows: rows.length,
415
+      unitNum: book.UnitNum,
416
+      wordNum: book.WordNum,
417
+      orderIdRange: rows.length ? [rows[0].OrderID, rows.at(-1).OrderID] : [],
418
+      duplicateOrderIds: rows.length - new Set(rows.map((row) => row.OrderID)).size,
419
+    });
420
+  }
421
+
422
+  for (const source of englishSources) {
423
+    const actual = state.englishRows.filter((row) => row.BookID === source.bookIdOld);
424
+    const expected = flattenEnglish(source);
425
+    assert.equal(actual.length, expected.length, `${source.label} Words 行数不一致`);
426
+    actual.forEach((row, index) => assertEnglishRow(row, expected[index], source.label, index));
427
+    const book = booksById.get(source.miaoguoBookId);
428
+    assert.equal(book.UnitNum, source.units.length, `${source.label} UnitNum 不一致`);
429
+    assert.equal(book.WordNum, source.wordNum, `${source.label} WordNum 不一致`);
430
+    result.english.push({
431
+      label: source.label,
432
+      miaoguoBookId: source.miaoguoBookId,
433
+      bookIdOld: source.bookIdOld,
434
+      rows: actual.length,
435
+      unitNum: book.UnitNum,
436
+      wordNum: book.WordNum,
437
+      perUnit: source.units.map((unit) => ({
438
+        lessonId: unit.lessonId,
439
+        rows: actual.filter((row) => row.LessonID === unit.lessonId).length,
440
+      })),
441
+    });
442
+  }
443
+
444
+  result.books = [...chineseSources, ...englishSources].map((source) => {
445
+    const book = booksById.get(source.miaoguoBookId);
446
+    return {
447
+      id: book.ID,
448
+      bookName: book.BookName,
449
+      bookIdOld: book.BookIDOld,
450
+      unitNum: book.UnitNum,
451
+      wordNum: book.WordNum,
452
+    };
453
+  });
454
+  return result;
455
+}
456
+
457
+async function auditChineseIdPreservation(connection, backupHanziRows) {
458
+  const oldIds = backupHanziRows.map((row) => row.ID);
459
+  const [rows] = await connection.query("SELECT ID FROM HanziUnit WHERE ID IN (?)", [oldIds]);
460
+  const existingIds = new Set(rows.map((row) => row.ID));
461
+  const missingIds = oldIds.filter((id) => !existingIds.has(id));
462
+  assert.equal(missingIds.length, 0, `有 ${missingIds.length} 个语文旧 ID 被删除:${missingIds.join(",")}`);
463
+  return {
464
+    oldRows: oldIds.length,
465
+    oldIdsStillPresent: rows.length,
466
+    missingIds,
467
+    newRows: chineseSources.reduce((total, source) => total + source.units.length, 0) - oldIds.length,
468
+  };
469
+}
470
+
471
+async function main() {
472
+  validateSources();
473
+  const connection = await mysql.createConnection(config.database);
474
+  try {
475
+    const dictionaryCheck = await validateHanziDictionary(connection);
476
+    const initialState = await readState(connection);
477
+    validateDatabaseMappings(initialState);
478
+
479
+    if (mode === "audit") {
480
+      const audit = await auditDatabase(connection);
481
+      const applyReportPath = path.join(taskDir, "apply_report_2026_fall.json");
482
+      assert(fs.existsSync(applyReportPath), `找不到执行报告:${applyReportPath}`);
483
+      const applyReport = JSON.parse(fs.readFileSync(applyReportPath, "utf8"));
484
+      assert(fs.existsSync(applyReport.backupPath), `找不到更新前备份:${applyReport.backupPath}`);
485
+      const backup = JSON.parse(fs.readFileSync(applyReport.backupPath, "utf8"));
486
+      const chineseIdPreservation = await auditChineseIdPreservation(connection, backup.hanziRows);
487
+      const report = {
488
+        generatedAt: new Date().toISOString(),
489
+        mode,
490
+        dictionaryCheck,
491
+        chineseIdPreservation,
492
+        audit,
493
+      };
494
+      const reportPath = path.join(taskDir, "audit_report_2026_fall.json");
495
+      writeJson(reportPath, report);
496
+      console.log(`AUDIT PASS: ${reportPath}`);
497
+      return;
498
+    }
499
+
500
+    let plan = buildPlan(initialState, dictionaryCheck);
501
+    if (mode === "dry-run") {
502
+      const reportPath = path.join(taskDir, "dry_run_report_2026_fall.json");
503
+      writeJson(reportPath, plan);
504
+      console.log(`DRY RUN PASS: ${reportPath}`);
505
+      console.log(
506
+        JSON.stringify(
507
+          {
508
+            chinese: plan.chinese.map((item) => ({
509
+              label: item.label,
510
+              rows: `${item.currentRows}->${item.targetRows}`,
511
+              unitNum: `${item.currentUnitNum}->${item.targetUnitNum}`,
512
+              wordNum: `${item.currentWordNum}->${item.targetWordNum}`,
513
+              sameNameUpdates: item.sameNameUpdates,
514
+              repurposedUpdates: item.repurposedUpdates,
515
+              inserts: item.inserts,
516
+              deletes: item.deletes,
517
+            })),
518
+            english: plan.english,
519
+            dictionaryCheck,
520
+          },
521
+          null,
522
+          2,
523
+        ),
524
+      );
525
+      return;
526
+    }
527
+
528
+    await connection.beginTransaction();
529
+    try {
530
+      const lockedState = await readState(connection, true);
531
+      validateDatabaseMappings(lockedState);
532
+      plan = buildPlan(lockedState, dictionaryCheck);
533
+
534
+      const backupDir = path.join(taskDir, "backups");
535
+      fs.mkdirSync(backupDir, { recursive: true });
536
+      const backupPath = path.join(backupDir, `before_2026_fall_${nowForFile()}.json`);
537
+      writeJson(backupPath, {
538
+        createdAt: new Date().toISOString(),
539
+        note: "所有目标表写入前、事务锁定后的完整备份",
540
+        targetMiaoguoBookIds,
541
+        targetHanziBookIds,
542
+        targetEnglishBookIds,
543
+        ...lockedState,
544
+      });
545
+
546
+      await applyChinese(connection, plan);
547
+      await applyEnglish(connection, plan);
548
+      const transactionAudit = await auditDatabase(connection);
549
+      await connection.commit();
550
+
551
+      const committedAudit = await auditDatabase(connection);
552
+      const chineseIdPreservation = await auditChineseIdPreservation(
553
+        connection,
554
+        lockedState.hanziRows,
555
+      );
556
+      const report = {
557
+        generatedAt: new Date().toISOString(),
558
+        mode,
559
+        backupPath,
560
+        plan,
561
+        transactionAudit,
562
+        committedAudit,
563
+        chineseIdPreservation,
564
+      };
565
+      const reportPath = path.join(taskDir, "apply_report_2026_fall.json");
566
+      writeJson(reportPath, report);
567
+      console.log(`APPLY AND AUDIT PASS: ${reportPath}`);
568
+      console.log(`BACKUP: ${backupPath}`);
569
+    } catch (error) {
570
+      await connection.rollback();
571
+      throw error;
572
+    }
573
+  } finally {
574
+    await connection.end();
575
+  }
576
+}
577
+
578
+main().catch((error) => {
579
+  console.error(error);
580
+  process.exitCode = 1;
581
+});

+ 372 - 0
.vscode/秒过知识库更新/update_miaoguo_literacy_2026_fall.mjs

@@ -0,0 +1,372 @@
1
+#!/usr/bin/env node
2
+
3
+import assert from "node:assert/strict";
4
+import fs from "node:fs";
5
+import path from "node:path";
6
+import { fileURLToPath } from "node:url";
7
+import mysql from "mysql2/promise";
8
+import config from "../../src/config/dev.js";
9
+
10
+const taskDir = path.dirname(fileURLToPath(import.meta.url));
11
+const sourcePath = path.join(taskDir, "source_miaoguo_literacy_2026_fall.json");
12
+const chineseSourcePath = path.join(taskDir, "source_chinese_2026_fall.json");
13
+const sources = JSON.parse(fs.readFileSync(sourcePath, "utf8"));
14
+const chineseSources = JSON.parse(fs.readFileSync(chineseSourcePath, "utf8"));
15
+
16
+const flags = new Set(process.argv.slice(2));
17
+const knownFlags = new Set(["--dry-run", "--apply", "--audit"]);
18
+for (const flag of flags) assert(knownFlags.has(flag), `不支持的参数:${flag}`);
19
+assert(
20
+  ["--dry-run", "--apply", "--audit"].filter((flag) => flags.has(flag)).length <= 1,
21
+  "--dry-run、--apply、--audit 只能选择一个",
22
+);
23
+const mode = flags.has("--apply") ? "apply" : flags.has("--audit") ? "audit" : "dry-run";
24
+
25
+function nowForFile() {
26
+  return new Date().toISOString().replaceAll(":", "-").replaceAll(".", "-");
27
+}
28
+
29
+function writeJson(filePath, data) {
30
+  fs.writeFileSync(filePath, `${JSON.stringify(data, null, 2)}\n`, "utf8");
31
+}
32
+
33
+function splitWords(example) {
34
+  return example.split(",").filter(Boolean);
35
+}
36
+
37
+function finalVocabularyWords() {
38
+  return [
39
+    ...new Set(
40
+      chineseSources
41
+        .filter((source) => source.unitType === 2)
42
+        .flatMap((source) => source.units.flatMap((unit) => splitWords(unit.example))),
43
+    ),
44
+  ];
45
+}
46
+
47
+function buildTianKong(word, pinyin) {
48
+  const chars = Array.from(word);
49
+  const syllables = pinyin.split(" ");
50
+  assert.equal(chars.length, syllables.length, `${word} 的字数与拼音音节数不一致`);
51
+  const seen = new Set();
52
+  const result = [];
53
+  for (let index = 0; index < chars.length; index += 1) {
54
+    const char = chars[index];
55
+    if (seen.has(char)) continue;
56
+    seen.add(char);
57
+    result.push(
58
+      chars
59
+        .map((current, currentIndex) => (current === char ? syllables[currentIndex] : current))
60
+        .join(""),
61
+    );
62
+  }
63
+  return result;
64
+}
65
+
66
+function validateSources() {
67
+  assert.equal(sources.length, 20, "本批次应补录 20 个词语");
68
+  assert.equal(new Set(sources.map((source) => source.word)).size, sources.length, "补录词语不能重复");
69
+  const vocabulary = new Set(finalVocabularyWords());
70
+  for (const source of sources) {
71
+    assert(vocabulary.has(source.word), `${source.word} 不在新版词语表中`);
72
+    assert(source.templateWord?.length > 0, `${source.word} 缺少模板词`);
73
+    assert(source.pinyin?.length > 0, `${source.word} 缺少拼音`);
74
+    assert(source.explain?.length > 0, `${source.word} 缺少释义`);
75
+    assert(source.english?.length > 0, `${source.word} 缺少英文释义`);
76
+    assert(Array.isArray(source.synonym), `${source.word} synonym 必须是数组`);
77
+    assert(Array.isArray(source.antonym), `${source.word} antonym 必须是数组`);
78
+    buildTianKong(source.word, source.pinyin);
79
+  }
80
+}
81
+
82
+async function loadCharacterAssets(connection) {
83
+  const chars = [...new Set(sources.flatMap((source) => Array.from(source.word)))];
84
+  const [rows] = await connection.query(
85
+    `SELECT ID,Name,KaitiUrl,BiShunUrl
86
+       FROM HanziWord
87
+      WHERE Name IN (?)
88
+        AND KaitiUrl IS NOT NULL AND KaitiUrl<>''
89
+        AND BiShunUrl IS NOT NULL AND BiShunUrl<>''
90
+      ORDER BY Name,ID`,
91
+    [chars],
92
+  );
93
+  const assets = new Map();
94
+  for (const row of rows) {
95
+    if (!assets.has(row.Name)) {
96
+      assets.set(row.Name, { kaitiUrl: row.KaitiUrl, biShunUrl: row.BiShunUrl });
97
+    }
98
+  }
99
+  const missing = chars.filter((char) => !assets.has(char));
100
+  assert.equal(missing.length, 0, `HanziWord 缺少字形资源:${missing.join("")}`);
101
+  return { assets, distinctCharacters: chars.length };
102
+}
103
+
104
+async function validateTemplates(connection) {
105
+  const templateWords = [...new Set(sources.map((source) => source.templateWord))];
106
+  const [rows] = await connection.query(
107
+    `SELECT ID,Word,SearchType,JSONString
108
+       FROM MiaoguoLiteracy
109
+      WHERE Word IN (?) AND SearchType='zici'
110
+      ORDER BY Word,ID`,
111
+    [templateWords],
112
+  );
113
+  const templates = new Map();
114
+  for (const row of rows) {
115
+    if (templates.has(row.Word) || !row.JSONString) continue;
116
+    try {
117
+      const json = JSON.parse(row.JSONString);
118
+      if (json.CHN?.PinYin?.[0]) templates.set(row.Word, row);
119
+    } catch {
120
+      // 继续寻找同词的下一条可用记录。
121
+    }
122
+  }
123
+  const missing = templateWords.filter((word) => !templates.has(word));
124
+  assert.equal(missing.length, 0, `找不到具有完整 CHN 的模板词:${missing.join("、")}`);
125
+  return templates;
126
+}
127
+
128
+function buildPayload(source, assets) {
129
+  const chars = Array.from(source.word);
130
+  const payload = {
131
+    ENG: {
132
+      Word: source.word,
133
+      Soundmark: "",
134
+      Paraphrase: [{ PartOfSpeech: "", ParaphraseList: source.english }],
135
+    },
136
+    CHN: {
137
+      HanZi: source.word,
138
+      HanZiImageUrl: "",
139
+      BiShunUrl: "",
140
+      KaitiArr: chars.map((char) => assets.get(char).kaitiUrl),
141
+      BiShunArr2: chars.map((char) => assets.get(char).biShunUrl),
142
+      PinYin: [{ pinyin: source.pinyin, explain: source.explain }],
143
+      CombineWords: {},
144
+      Antonym: source.antonym,
145
+      Synonym: source.synonym,
146
+      TianKong: buildTianKong(source.word, source.pinyin),
147
+      PinyinTone: source.pinyin,
148
+    },
149
+  };
150
+  assert.equal(payload.CHN.KaitiArr.length, chars.length, `${source.word} 楷体图数量不正确`);
151
+  assert.equal(payload.CHN.BiShunArr2.length, chars.length, `${source.word} 笔顺图数量不正确`);
152
+  return payload;
153
+}
154
+
155
+function inspectLiteracyRow(row) {
156
+  if (!row?.JSONString) return { ok: false, reason: row ? "EMPTY_JSON" : "NO_ROW" };
157
+  try {
158
+    const json = JSON.parse(row.JSONString);
159
+    if (!json.CHN) return { ok: false, reason: "MISSING_CHN" };
160
+    if (!json.CHN.PinYin?.[0]?.pinyin || !json.CHN.PinYin?.[0]?.explain) {
161
+      return { ok: false, reason: "INVALID_CHN_STRUCTURE" };
162
+    }
163
+    return { ok: true, reason: "OK", json };
164
+  } catch {
165
+    return { ok: false, reason: "INVALID_JSON" };
166
+  }
167
+}
168
+
169
+async function readTargetRows(connection, forUpdate = false) {
170
+  const lock = forUpdate ? " FOR UPDATE" : "";
171
+  const [rows] = await connection.query(
172
+    `SELECT * FROM MiaoguoLiteracy WHERE Word IN (?) ORDER BY Word,SearchType DESC,ID${lock}`,
173
+    [sources.map((source) => source.word)],
174
+  );
175
+  return rows;
176
+}
177
+
178
+async function auditAllVocabulary(connection) {
179
+  const words = finalVocabularyWords();
180
+  const [rows] = await connection.query(
181
+    `SELECT ID,Word,SearchType,JSONString
182
+       FROM MiaoguoLiteracy
183
+      WHERE Word IN (?)
184
+        AND SearchType<>'shici'
185
+        AND SearchType<>'eng'
186
+      ORDER BY Word,SearchType DESC,ID`,
187
+    [words],
188
+  );
189
+  const selectedRows = new Map();
190
+  for (const row of rows) {
191
+    if (!selectedRows.has(row.Word)) selectedRows.set(row.Word, row);
192
+  }
193
+  const problems = [];
194
+  for (const word of words) {
195
+    const row = selectedRows.get(word);
196
+    const check = inspectLiteracyRow(row);
197
+    if (!check.ok) problems.push({ word, reason: check.reason, selectedRowId: row?.ID ?? null });
198
+  }
199
+  return {
200
+    passed: problems.length === 0,
201
+    finalVocabularyWords: words.length,
202
+    selectedUsableRows: words.length - problems.length,
203
+    problems,
204
+  };
205
+}
206
+
207
+async function auditInsertedRows(connection, expectedRows) {
208
+  const rows = await readTargetRows(connection);
209
+  assert.equal(rows.length, sources.length, "补录词语行数不等于 20");
210
+  const actualByWord = new Map(rows.map((row) => [row.Word, row]));
211
+  const checks = [];
212
+  for (const expected of expectedRows) {
213
+    const actual = actualByWord.get(expected.word);
214
+    assert(actual, `${expected.word} 写入后不存在`);
215
+    assert.equal(actual.SearchType, "zici", `${expected.word} SearchType 不正确`);
216
+    assert.equal(actual.Author, "", `${expected.word} Author 不正确`);
217
+    assert.equal(actual.ShiciUrl, "", `${expected.word} ShiciUrl 不正确`);
218
+    const actualJson = JSON.parse(actual.JSONString);
219
+    assert.deepEqual(actualJson, expected.payload, `${expected.word} JSONString 与拟写数据不一致`);
220
+    checks.push({
221
+      id: actual.ID,
222
+      word: actual.Word,
223
+      searchType: actual.SearchType,
224
+      pinyin: actualJson.CHN.PinYin[0].pinyin,
225
+      explain: actualJson.CHN.PinYin[0].explain,
226
+      kaitiImages: actualJson.CHN.KaitiArr.length,
227
+      strokeAnimations: actualJson.CHN.BiShunArr2.length,
228
+    });
229
+  }
230
+  return checks;
231
+}
232
+
233
+async function main() {
234
+  validateSources();
235
+  const connection = await mysql.createConnection(config.database);
236
+  try {
237
+    const { assets, distinctCharacters } = await loadCharacterAssets(connection);
238
+    const templates = await validateTemplates(connection);
239
+    const expectedRows = sources.map((source) => ({
240
+      word: source.word,
241
+      templateWord: source.templateWord,
242
+      templateId: templates.get(source.templateWord).ID,
243
+      pinyin: source.pinyin,
244
+      explain: source.explain,
245
+      sourceUrl: source.sourceUrl,
246
+      payload: buildPayload(source, assets),
247
+    }));
248
+
249
+    if (mode === "audit") {
250
+      const insertedRows = await auditInsertedRows(connection, expectedRows);
251
+      const vocabularyAudit = await auditAllVocabulary(connection);
252
+      assert(vocabularyAudit.passed, `全部词语复查仍有 ${vocabularyAudit.problems.length} 个问题`);
253
+      const report = {
254
+        generatedAt: new Date().toISOString(),
255
+        mode,
256
+        passed: true,
257
+        insertedRows,
258
+        vocabularyAudit,
259
+      };
260
+      const reportPath = path.join(taskDir, "miaoguo_literacy_post_apply_audit_2026_fall.json");
261
+      writeJson(reportPath, report);
262
+      console.log(`AUDIT PASS: ${reportPath}`);
263
+      return;
264
+    }
265
+
266
+    const existingRows = await readTargetRows(connection);
267
+    assert.equal(existingRows.length, 0, "目标词语已经存在记录,拒绝重复插入");
268
+    const dryRun = {
269
+      generatedAt: new Date().toISOString(),
270
+      mode,
271
+      targetRows: expectedRows.length,
272
+      existingRows: existingRows.length,
273
+      distinctCharacters,
274
+      templateWords: [...new Set(sources.map((source) => source.templateWord))],
275
+      proposedRows: expectedRows,
276
+    };
277
+
278
+    if (mode === "dry-run") {
279
+      const reportPath = path.join(taskDir, "miaoguo_literacy_dry_run_2026_fall.json");
280
+      writeJson(reportPath, dryRun);
281
+      console.log(`DRY RUN PASS: ${reportPath}`);
282
+      console.log(
283
+        JSON.stringify(
284
+          expectedRows.map((row) => ({
285
+            word: row.word,
286
+            templateWord: row.templateWord,
287
+            pinyin: row.pinyin,
288
+            explain: row.explain,
289
+            kaitiImages: row.payload.CHN.KaitiArr.length,
290
+            strokeAnimations: row.payload.CHN.BiShunArr2.length,
291
+          })),
292
+          null,
293
+          2,
294
+        ),
295
+      );
296
+      return;
297
+    }
298
+
299
+    await connection.beginTransaction();
300
+    try {
301
+      const lockedTargetRows = await readTargetRows(connection, true);
302
+      assert.equal(lockedTargetRows.length, 0, "事务开始后发现目标词语已有记录,拒绝重复插入");
303
+      const templateRows = [...templates.values()];
304
+      const characterRows = [...assets.entries()].map(([name, value]) => ({ name, ...value }));
305
+      const backupDir = path.join(taskDir, "backups");
306
+      fs.mkdirSync(backupDir, { recursive: true });
307
+      const backupPath = path.join(
308
+        backupDir,
309
+        `before_miaoguo_literacy_2026_fall_${nowForFile()}.json`,
310
+      );
311
+      writeJson(backupPath, {
312
+        createdAt: new Date().toISOString(),
313
+        note: "20 个目标词写入前的目标记录、模板记录和汉字资源备份",
314
+        targetWords: sources.map((source) => source.word),
315
+        targetRows: lockedTargetRows,
316
+        templateRows,
317
+        characterRows,
318
+      });
319
+
320
+      const insertIds = [];
321
+      for (const row of expectedRows) {
322
+        const [result] = await connection.execute(
323
+          `INSERT INTO MiaoguoLiteracy
324
+             (Word,SearchType,Author,ShiciUrl,CreateTime,JSONString)
325
+           VALUES (?,?,'','',CURRENT_TIMESTAMP,?)`,
326
+          [row.word, "zici", JSON.stringify(row.payload)],
327
+        );
328
+        insertIds.push({ word: row.word, id: result.insertId });
329
+      }
330
+
331
+      const transactionAudit = await auditInsertedRows(connection, expectedRows);
332
+      const transactionVocabularyAudit = await auditAllVocabulary(connection);
333
+      assert(
334
+        transactionVocabularyAudit.passed,
335
+        `事务内全部词语复查仍有 ${transactionVocabularyAudit.problems.length} 个问题`,
336
+      );
337
+      await connection.commit();
338
+
339
+      const committedAudit = await auditInsertedRows(connection, expectedRows);
340
+      const committedVocabularyAudit = await auditAllVocabulary(connection);
341
+      assert(
342
+        committedVocabularyAudit.passed,
343
+        `提交后全部词语复查仍有 ${committedVocabularyAudit.problems.length} 个问题`,
344
+      );
345
+      const report = {
346
+        generatedAt: new Date().toISOString(),
347
+        mode,
348
+        backupPath,
349
+        insertIds,
350
+        proposedRows: expectedRows,
351
+        transactionAudit,
352
+        transactionVocabularyAudit,
353
+        committedAudit,
354
+        committedVocabularyAudit,
355
+      };
356
+      const reportPath = path.join(taskDir, "miaoguo_literacy_apply_report_2026_fall.json");
357
+      writeJson(reportPath, report);
358
+      console.log(`APPLY AND AUDIT PASS: ${reportPath}`);
359
+      console.log(`BACKUP: ${backupPath}`);
360
+    } catch (error) {
361
+      await connection.rollback();
362
+      throw error;
363
+    }
364
+  } finally {
365
+    await connection.end();
366
+  }
367
+}
368
+
369
+main().catch((error) => {
370
+  console.error(error);
371
+  process.exitCode = 1;
372
+});