| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- // 为 UserID=2 的雅思卡片补充 ContentType=3 例句
- // 逻辑:从 ContentType=2 提取单词 -> 在雅思 Words(BookID 212-217) 取 ExampleSentence JSON -> 写入 ContentType=3
- // 用法:
- // DRY=1 node update_card_examples.js # 预检,打印匹配情况,不写库
- // node update_card_examples.js # 正式写入
- import { query } from '../../../src/util/db.js';
- const DRY = process.env.DRY === '1';
- const USER_ID = 2;
- const MIN_CARD_ID = 1671933;
- const BOOK_IDS = [212, 213, 214, 215, 216, 217];
- function extractWord(content) {
- if (!content) return null;
- // 1) [读 src='...text=WORD&...'] 中的 text= 参数
- const m1 = content.match(/text=([^&\s'"]+)/);
- if (m1) {
- try {
- const w = decodeURIComponent(m1[1]).trim();
- if (w) return w;
- } catch {
- /* ignore */
- }
- }
- // 2) 兜底:行首 "WORD 的基本中文释义"
- const m2 = content.match(/^([A-Za-z][A-Za-z'’.\-\s]*?)\s*的基本中文释义/);
- if (m2) return m2[1].trim();
- return null;
- }
- async function main() {
- const cards = await query(
- `select MiaoguoCardID from kylx365_db.MiaoguoCard where UserID=? and MiaoguoCardID>=? order by MiaoguoCardID`,
- [USER_ID, MIN_CARD_ID]
- );
- console.log(`目标卡片数: ${cards.length}`);
- if (!cards.length) return;
- const cardIds = cards.map((c) => c.MiaoguoCardID);
- const inSql = '(' + cardIds.join(',') + ')';
- const contents = await query(
- `select MiaoguoContentID, MiaoguoCardID, ContentType, Content from kylx365_db.MiaoguoContent where MiaoguoCardID in ${inSql} and ContentType in (2,3) order by MiaoguoCardID, ContentType`
- );
- // 建立 card -> {2: row, 3: row}
- const map = new Map();
- for (const r of contents) {
- if (!map.has(r.MiaoguoCardID)) map.set(r.MiaoguoCardID, {});
- map.get(r.MiaoguoCardID)[r.ContentType] = r;
- }
- // 收集所有要查的单词
- const wordToCards = new Map(); // lowerWord -> [{cardId, content3Id}]
- for (const [cardId, rec] of map) {
- const c2 = rec[2];
- if (!c2) continue;
- const w = extractWord(c2.Content);
- if (!w) {
- console.warn(` ✗ 无法提取单词 card=${cardId}`);
- continue;
- }
- const c3 = rec[3];
- if (!c3) {
- console.warn(` ✗ 缺少 ContentType=3 行 card=${cardId}`);
- continue;
- }
- const key = w.toLowerCase();
- if (!wordToCards.has(key)) wordToCards.set(key, []);
- wordToCards.get(key).push({ cardId, content3Id: c3.MiaoguoContentID, word: w });
- }
- // 一次性查雅思例句
- const words = [...wordToCards.keys()];
- const examples = new Map();
- if (words.length) {
- const rows = await query(
- `select Word, ExampleSentence from kylx365_db.Words where BookID in (${BOOK_IDS.join(',')}) and LOWER(Word) in (?)`,
- [words]
- );
- for (const r of rows) examples.set(r.Word.toLowerCase(), r.ExampleSentence);
- }
- let matched = 0,
- unmatched = 0,
- updated = 0,
- skipped = 0;
- for (const [, list] of wordToCards) {
- for (const item of list) {
- const ex = examples.get(item.word.toLowerCase());
- if (!ex) {
- unmatched++;
- console.warn(` ✗ 雅思词库无例句: "${item.word}" (card=${item.cardId})`);
- continue;
- }
- matched++;
- if (DRY) {
- console.log(` · ${item.word} (card=${item.cardId}) -> 例句 ${ex.length} 字符`);
- continue;
- }
- await query('update kylx365_db.MiaoguoContent set Content=? where MiaoguoContentID=?', [
- ex,
- item.content3Id,
- ]);
- updated++;
- }
- }
- console.log(
- `\n预检=${DRY ? '是' : '否'} | 卡片派生词 ${wordToCards.size} | 匹配例句 ${matched} | 无例句 ${unmatched} | 已写入 ${updated}`
- );
- }
- main()
- .then(() => process.exit(0))
- .catch((e) => {
- console.error(e);
- process.exit(1);
- });
|