From c9df97b4eabe1ad85235c9b99c54114d694aae86 Mon Sep 17 00:00:00 2001 From: Zyronon Date: Tue, 25 Nov 2025 01:25:17 +0800 Subject: [PATCH] wip --- ... 中忽略人名(基于 editArticle.nameList).md | 71 ++++++++ ...管理弹框(读取与保存 editArticle.nameList).md | 69 +++++++ .trae/documents/静态首页移动端适配.md | 109 +++++++++++ .../001&002-Excuse Me.lrc | 15 ++ .../001&002-Excuse Me.mp3 | Bin 0 -> 819138 bytes .../003&004-Sorry, Sir..lrc | 20 ++ .../003&004-Sorry, Sir..mp3 | Bin 0 -> 1189435 bytes .../005&006-Nice to Meet You..lrc | 28 +++ .../005&006-Nice to Meet You..mp3 | Bin 0 -> 1374185 bytes .../007&008-Are You a Teacher.lrc | 24 +++ .../007&008-Are You a Teacher.mp3 | Bin 0 -> 1254494 bytes .../009&010-How Are You Today.lrc | 22 +++ .../009&010-How Are You Today.mp3 | Bin 0 -> 1083107 bytes .../011&012-Is This Your Shirt.lrc | 24 +++ .../011&012-Is This Your Shirt.mp3 | Bin 0 -> 1173182 bytes .../013&014-A New Dress.lrc | 21 +++ .../013&014-A New Dress.mp3 | Bin 0 -> 1123134 bytes .../015&016-Your Passports, Please..lrc | 26 +++ .../015&016-Your Passports, Please..mp3 | Bin 0 -> 1488855 bytes .../017&018-How do you do.lrc | 26 +++ .../017&018-How do you do.mp3 | Bin 0 -> 1631460 bytes .../019&020-Tired and Thirsty.lrc | 22 +++ .../019&020-Tired and Thirsty.mp3 | Bin 0 -> 1223220 bytes .../021&022-Which Book.lrc | 16 ++ .../021&022-Which Book.mp3 | Bin 0 -> 889197 bytes .../023&024-Which Glasses.lrc | 17 ++ .../023&024-Which Glasses.mp3 | Bin 0 -> 934653 bytes .../025&026-Mrs. Smith's Kitchen.lrc | 20 ++ .../025&026-Mrs. Smith's Kitchen.mp3 | Bin 0 -> 1381683 bytes .../027&028-Mrs. Smith's Living Room.lrc | 21 +++ .../027&028-Mrs. Smith's Living Room.mp3 | Bin 0 -> 1488022 bytes .../029&030-Come In, Amy..lrc | 17 ++ .../029&030-Come In, Amy..mp3 | Bin 0 -> 1094363 bytes .../031&032-Where's Sally.lrc | 22 +++ .../031&032-Where's Sally.mp3 | Bin 0 -> 1169007 bytes .../033&034-A Fine Day.lrc | 19 ++ .../033&034-A Fine Day.mp3 | Bin 0 -> 1334135 bytes .../035&036-Our Village.lrc | 23 +++ .../035&036-Our Village.mp3 | Bin 0 -> 1598514 bytes .../037&038-Making a Bookcase.lrc | 26 +++ .../039&040-Don't Drop It.lrc | 20 ++ src/hooks/event.ts | 3 +- .../article/components/TypingArticle.vue | 172 +++++++++++------- src/pages/word/components/TypeWord.vue | 6 +- 44 files changed, 782 insertions(+), 77 deletions(-) create mode 100644 .trae/documents/在 TypingArticle.vue 中忽略人名(基于 editArticle.nameList).md create mode 100644 .trae/documents/完善人物名称管理弹框(读取与保存 editArticle.nameList).md create mode 100644 .trae/documents/静态首页移动端适配.md create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/001&002-Excuse Me.lrc create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/001&002-Excuse Me.mp3 create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/003&004-Sorry, Sir..lrc create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/003&004-Sorry, Sir..mp3 create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/005&006-Nice to Meet You..lrc create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/005&006-Nice to Meet You..mp3 create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/007&008-Are You a Teacher.lrc create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/007&008-Are You a Teacher.mp3 create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/009&010-How Are You Today.lrc create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/009&010-How Are You Today.mp3 create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/011&012-Is This Your Shirt.lrc create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/011&012-Is This Your Shirt.mp3 create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/013&014-A New Dress.lrc create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/013&014-A New Dress.mp3 create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/015&016-Your Passports, Please..lrc create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/015&016-Your Passports, Please..mp3 create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/017&018-How do you do.lrc create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/017&018-How do you do.mp3 create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/019&020-Tired and Thirsty.lrc create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/019&020-Tired and Thirsty.mp3 create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/021&022-Which Book.lrc create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/021&022-Which Book.mp3 create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/023&024-Which Glasses.lrc create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/023&024-Which Glasses.mp3 create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/025&026-Mrs. Smith's Kitchen.lrc create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/025&026-Mrs. Smith's Kitchen.mp3 create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/027&028-Mrs. Smith's Living Room.lrc create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/027&028-Mrs. Smith's Living Room.mp3 create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/029&030-Come In, Amy..lrc create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/029&030-Come In, Amy..mp3 create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/031&032-Where's Sally.lrc create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/031&032-Where's Sally.mp3 create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/033&034-A Fine Day.lrc create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/033&034-A Fine Day.mp3 create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/035&036-Our Village.lrc create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/035&036-Our Village.mp3 create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/037&038-Making a Bookcase.lrc create mode 100644 public/sound/article/nce1/新概念美音(第1册)(MP3+LRC)/039&040-Don't Drop It.lrc diff --git a/.trae/documents/在 TypingArticle.vue 中忽略人名(基于 editArticle.nameList).md b/.trae/documents/在 TypingArticle.vue 中忽略人名(基于 editArticle.nameList).md new file mode 100644 index 00000000..7454be32 --- /dev/null +++ b/.trae/documents/在 TypingArticle.vue 中忽略人名(基于 editArticle.nameList).md @@ -0,0 +1,71 @@ +## 目标 +- 在 `onTyping` 方法(291-382行)中判断当前/下一个单词是否为人名,并在练习时自动忽略(不要求输入、不提示错误、不停顿等待空格)。 + +## 数据来源 +- 使用 `props.article.nameList: string[]`(来自编辑页保存),作为要忽略的人名列表。 + +## 匹配策略 +- 构建一个人名集合 `nameSet`: + - `trim()` 后的字符串; + - 若开启 `ignoreCase` 则统一转小写匹配。 +- 判定函数 `isNameWord(word: ArticleWord)`: + - 仅当 `word.type === PracticeArticleWordType.Word` 时参与匹配; + - 对 `word.word` 进行同样的规范化后 `nameSet.has(...)`。 + +## 处理时机与行为 +- 在 `onTyping` 开始处、拿到 `currentWord` 后: + - 若是“人名”,则直接跳过本词;若该词 `nextSpace` 为真,连带空格也跳过(避免进入 `isSpace` 状态)。 + - 跳过后继续处理当前按键:复用已有模式(如 `isSpace` 分支里)调用 `next()` 和递归 `onTyping(e)`。 +- 在 `next()` 内也追加“人名跳过”逻辑(与已有忽略符号/数字类似),保证连续多个需要忽略的词可以被连续跳过: + - 当 `currentWord` 是人名: + - 若 `currentWord.nextSpace` 为真:`isSpace = false`; + - 递归调用 `next()` 继续到下一个词; + - 否则正常 `emit('nextWord', currentWord)`。 + +## 代码改动点 +- 在组件顶部或方法内构建 `nameSet`(建议用 `$computed`): +```ts +const nameSet = $computed(() => { + const list = props.article?.nameList ?? [] + return new Set(list.map(s => (settingStore.ignoreCase ? s.toLowerCase() : s).trim()).filter(Boolean)) +}) +function isNameWord(w: ArticleWord) { + if (w.type !== PracticeArticleWordType.Word) return false + const token = (settingStore.ignoreCase ? w.word.toLowerCase() : w.word).trim() + return nameSet.has(token) +} +``` +- 在 `onTyping` 里,`let currentWord = currentSentence.words[wordIndex]` 之后: +```ts +if (isNameWord(currentWord)) { + // 跳过当前人名,连带空格 + isSpace = false + const savedTypingFlag = isTyping + next() + isTyping = false + return onTyping(e) +} +``` +- 在 `next()` 内,设置 `currentWord` 后、`emit('nextWord', currentWord)` 之前: +```ts +if (isNameWord(currentWord)) { + // 人名与后续空格都跳过 + isSpace = false + return next() +} +``` + +## 注意事项 +- 保持与现有忽略规则一致(符号/数字已通过 `ignoreSymbol` 处理),人名跳过逻辑与其同层级。 +- 忽略人名时不触发 `wrong` 或提示音,不进入 `isSpace` 等待。 +- 若连续出现多个需要忽略的词(如人名+标点+人名),递归 `next()` 将逐个跳过。 + +## 验证 +- 在包含人名的文本中练习: + - 人名处不需要输入,光标自动跳到下一非忽略词; + - 不会卡在空格等待; + - 大小写忽略效果符合 `settingStore.ignoreCase` 设置。 + +## 交付 +- 按上述方案在 `TypingArticle.vue` 中实现辅助函数与两处调用点的改动; +- 仅修改该文件,不影响其他页面。 \ No newline at end of file diff --git a/.trae/documents/完善人物名称管理弹框(读取与保存 editArticle.nameList).md b/.trae/documents/完善人物名称管理弹框(读取与保存 editArticle.nameList).md new file mode 100644 index 00000000..a0d1de22 --- /dev/null +++ b/.trae/documents/完善人物名称管理弹框(读取与保存 editArticle.nameList).md @@ -0,0 +1,69 @@ +## 目标 +- 在“人物名称管理”弹框中使用临时变量编辑名称列表,只在点击“确定”时写回 `editArticle.nameList: string[]` + +## 数据结构 +- `editArticle.nameList: string[]` +- 临时变量:`let nameListRef = $ref([])` + +## 生命周期 +- 弹框打开时初始化:`nameListRef = cloneDeep(editArticle.nameList || [])` +- 弹框关闭时不写回:丢弃修改 + +## 交互设计 +- 弹框 `v-model="showNameDialog"`、`:footer="true"`、`@close="showNameDialog = false"`、`@ok="saveNameList"` +- 按钮: + - “添加名称” → `nameListRef.push('')` + - 每行名称使用 `BaseInput v-model="nameListRef[i]"` + - “删除”名称 → `nameListRef.splice(i,1)` + +## 保存逻辑 +- `saveNameList()`: + - 清理:`trim()` + `filter(Boolean)` + - 写回:`editArticle.nameList = cleaned` + - 关闭弹框:`showNameDialog = false` + +## 实现细节(EditArticle.vue 增加) +- 脚本: +```ts +let showNameDialog = $ref(false) +let nameListRef = $ref([]) + +watch(() => showNameDialog, (v) => { + if (v) nameListRef = cloneDeep(Array.isArray(editArticle.nameList) ? editArticle.nameList : []) +}) + +function addName() { nameListRef.push('') } +function removeName(i: number) { nameListRef.splice(i,1) } +function saveNameList() { + const cleaned = nameListRef.map(s => (s ?? '').trim()).filter(Boolean) + editArticle.nameList = cleaned +} +``` +- 模板(620-628 区域): +```vue + +
+
+
配置需要忽略的人名,练习时自动忽略这些名称
+ 添加名称 +
+ +
+
+ + 删除 +
+
+
+
+``` + +## 验证 +- 打开弹框 → 编辑临时列表 → 点击“确定”后检查 `editArticle.nameList` 是否更新;点击关闭则不更新 + +## 注意 +- 若类型仍为旧版 `string[][]`,请同步调整为 `string[]` 以与当前实现一致 \ No newline at end of file diff --git a/.trae/documents/静态首页移动端适配.md b/.trae/documents/静态首页移动端适配.md new file mode 100644 index 00000000..684a8fca --- /dev/null +++ b/.trae/documents/静态首页移动端适配.md @@ -0,0 +1,109 @@ +## 目标与范围 + +* 适配 `public/static-home.html` 在 768px 以下与 480px 以下的移动端展示与触控体验 + +* 不改变页面文案与结构,只进行样式与布局响应式改造 + +## 结构与布局 + +* 将固定宽度 `.w { width: 60vw; }` 改为容器 `.container { width: min(1200px, 92%); }` 并在模板中替换为 `.container` + +* `.card-wrap` 改为自适应栅格:`grid-template-columns: repeat(auto-fit, minmax(240px, 1fr))` + +* 移动端(<=768px)卡片单列展示;间距适当增大,避免拥挤 + +## 样式改造 + +* 标题缩放: + + * `@media (max-width: 768px) h1 { font-size: 3rem; }` + + * `@media (max-width: 480px) h1 { font-size: 2.4rem; }` + +* 主按钮组: + + * 移动端按钮全宽:`.base-button { width: 100%; margin: .5rem 0; height: 2.8rem; font-size: 1rem; }` + + * 悬浮降低透明度改为轻微位移:`transform: translateY(-1px);` + +* 内容区与间距: + + * `@media (max-width: 768px) .content { margin-top: 4rem; gap: 1.4rem; }` + + * `@media (max-width: 480px) .content { margin-top: 3.2rem; gap: 1.2rem; }` + +* 赞助区 `.sky`: + + * 图片强制全宽:`.sky a { width: 100% !important; } .sky-img { width: 100%; }` + + * 移动端上下内边距缩小,减少跳动 + +* 卡片 `.card`: + + * 移动端去掉固定 `width: 25%`,改为自适应栅格控制 + + * 增加触控阴影:`box-shadow: 0 6px 20px rgba(0,0,0,.08);` + +* 底部链接 `.bottom`: + + * 在 <=768px 改为纵向堆叠:`flex-direction: column; align-items: flex-start; gap: .6rem;` + +## 示例变更片段(将添加到