From b5639dd6c195bf8c68dbf5b6bb2070a3c9f710ae Mon Sep 17 00:00:00 2001 From: zyronon Date: Tue, 19 Aug 2025 02:02:37 +0800 Subject: [PATCH] fix:fix getCurrentStudyWord function,fix Setting page --- src/assets/css/style.scss | 1 + src/hooks/dict.ts | 156 +++--- src/pages/pc/article/StudyArticle.vue | 6 +- .../pc/article/components/TypingArticle.vue | 2 +- src/pages/pc/components/base/Switch.vue | 13 +- src/pages/pc/components/base/Textarea.vue | 25 +- src/pages/pc/components/base/radio/Radio.vue | 1 + .../pc/components/base/select/Option.vue | 6 +- .../pc/components/base/select/Select.vue | 22 +- src/pages/pc/{ => setting}/Setting.vue | 479 +++++++----------- src/pages/pc/setting/SettingItem.vue | 22 + src/pages/pc/word/WordHomePage.vue | 6 +- src/router.ts | 2 +- src/stores/base.ts | 4 +- src/stores/setting.ts | 12 +- src/utils/const.ts | 2 +- src/utils/index.ts | 27 + 17 files changed, 363 insertions(+), 423 deletions(-) rename src/pages/pc/{ => setting}/Setting.vue (50%) create mode 100644 src/pages/pc/setting/SettingItem.vue diff --git a/src/assets/css/style.scss b/src/assets/css/style.scss index a08e09b4..995d0cce 100644 --- a/src/assets/css/style.scss +++ b/src/assets/css/style.scss @@ -164,6 +164,7 @@ html, body { overflow-x: hidden; color: var(--color-main-text); font-family: var(--font-family); + background: var(--color-primary); -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } diff --git a/src/hooks/dict.ts b/src/hooks/dict.ts index 626204ce..2a5b71dc 100644 --- a/src/hooks/dict.ts +++ b/src/hooks/dict.ts @@ -1,5 +1,8 @@ import {Article, Word} from "@/types/types.ts"; import {useBaseStore} from "@/stores/base.ts"; +import {useSettingStore} from "@/stores/setting.ts"; +import {getDefaultWord} from "@/types/func.ts"; +import {getRandomN, splitIntoN} from "@/utils"; export function useWordOptions() { const store = useBaseStore() @@ -83,105 +86,98 @@ export function useArticleOptions() { } export function getCurrentStudyWord() { - // console.time() + console.log('getCurrentStudyWord') const store = useBaseStore() let data = {new: [], review: [], write: []} let dict = store.sdict; - if (dict.words?.length) { - const getList = (startIndex: number, endIndex: number) => dict.words.slice(startIndex, endIndex) - - const perDay = store.sdict.perDayStudyNumber; - const totalNeed = perDay * 3; + let isTest = false + let words = dict.words.slice() + if (isTest) { + words = Array.from({length: 10}).map((v, i) => { + return getDefaultWord({word: String(i)}) + }) + } + if (words?.length) { + const settingStore = useSettingStore() + //忽略时是否加上自定义的简单词 + let ignoreList = [store.allIgnoreWords, store.knownWords][settingStore.ignoreSimpleWord ? 0 : 1] + const perDay = dict.perDayStudyNumber; let start = dict.lastLearnIndex; - let end = start + dict.perDayStudyNumber - - if (dict.complete) { + let complete = dict.complete; + if (isTest) { + start = 1 + complete = true + } + let end = start + let list = dict.words.slice(start) + if (complete) { //如果是已完成,那么把应该学的新词放到复习词组里面 - dict.words.slice(start, end).map(item => { - if (!store.knownWords.includes(item.word)) { - data.review.push(item) + for (let item of list) { + if (!ignoreList.includes(item.word.toLowerCase())) { + if (data.review.length < perDay) { + data.review.push(item) + } else break } - }) - //如果起点index 减去总默写不足的话,那就直接从最后面取 - //todo 这里有空了,优化成往前滚动取值 - if (start - totalNeed < 0) { - end = dict.length - } else { - end = start + end++ } } else { - dict.words.slice(start, end).map(item => { - if (!store.knownWords.includes(item.word)) { - data.new.push(item) + //从start往后取perDay个单词,作为当前练习单词 + for (let item of list) { + if (!ignoreList.includes(item.word.toLowerCase())) { + if (data.new.length < perDay) { + data.new.push(item) + } else break } - }) - end = start - start = start - dict.perDayStudyNumber - if (start < 0) start = 0 - //取上一次学习的单词用于复习 - let list = getList(start, end) - list.map(item => { - if (!store.knownWords.includes(item.word)) { - data.review.push(item) + end++ + } + //从start往前取perDay个单词,作为当前复习单词,取到0为止 + list = dict.words.slice(0, start).toReversed() + for (let item of list) { + if (!ignoreList.includes(item.word.toLowerCase())) { + if (data.review.length < perDay) { + data.review.push(item) + } else break } - }) - - end = start + start-- + } } - // console.log(start,end) - // end = start - // start = start - dict.perDayStudyNumber * 3 - // //在上次学习再往前取前3次学习的单词用于默写 - // list = getList(start, end) - // list.map(item => { - // if (!store.knownWords.includes(item.word)) { - // data.write.push(item) - // } - // }) - - //write数组放的是上上次之前的单词,总的数量为perDayStudyNumber * 3,取单词的规则为:从后往前取6个perDayStudyNumber的,越靠前的取的单词越多。 // 上上次更早的单词 - if (end > 0) { - const allWords = dict.words; - const candidateWords = allWords.slice(0, end).filter(w => !store.knownWords.includes(w.word)); + //默认只取start之前的单词 + let candidateWords = dict.words.slice(0, start).toReversed() + //但如果已完成,则滚动取值 + if (complete) candidateWords = candidateWords.concat(dict.words.slice(end).toReversed()) + candidateWords = candidateWords.filter(w => !ignoreList.includes(w.word.toLowerCase())); + // console.log(candidateWords.map(v => v.word)) + //最终要获取的单词数量 + const totalNeed = perDay * 3; + if (candidateWords.length <= totalNeed) { + data.write = candidateWords + } else { + //write数组放的是上上次之前的单词,总的数量为perDayStudyNumber * 3,取单词的规则为:从后往前取6个perDayStudyNumber的,越靠前的取的单词越多。 + let days = 6 + // 分6组,每组最多 perDay 个 + const groups: Word[][] = splitIntoN(candidateWords.slice(0, days * perDay), 6) + // console.log('groups', groups) - // 分6组,每组 perDay 个 - const groupCount = 6; - const groupSize = perDay; - const groups: Word[][] = []; - for (let i = 0; i < groupCount; i++) { - const start = candidateWords.length - (i + 1) * groupSize; - const end = candidateWords.length - i * groupSize; - if (start < 0 && end <= 0) break; - groups.unshift(candidateWords.slice(Math.max(0, start), Math.max(0, end))); - } - - // 分配数量,靠前组多,靠后组少 - // 例如分配比例 [1,2,3,4,5,6] - const ratio = [1, 2, 3, 4, 5, 6]; + // 分配数量,靠前组多,靠后组少,例如分配比例 [6,5,4,3,2,1] + const ratio = Array.from({length: days}, (_, i) => i + 1).reverse(); const ratioSum = ratio.reduce((a, b) => a + b, 0); - const realRatio = ratio.map(r => Math.round(r * totalNeed / ratioSum)); + const realRatio = ratio.map(r => Math.round(r / ratioSum * totalNeed)); + // console.log(ratio, ratioSum, realRatio, realRatio.reduce((a, b) => a + b, 0)) - // 按比例从每组取单词 + // 按比例从每组随机取单词 let writeWords: Word[] = []; - for (let i = 0; i < groups.length; i++) { - writeWords = writeWords.concat(groups[i].slice(-realRatio[i])); - } - // 如果数量不够,补足 - if (writeWords.length < totalNeed) { - const extra = candidateWords.filter(w => !writeWords.includes(w)).slice(-(totalNeed - writeWords.length)); - writeWords = writeWords.concat(extra); - } - // 最终数量截断 - writeWords = writeWords.slice(-totalNeed); - - //这里需要反转一下,越靠近今天的单词,越先练习 - data.write = writeWords.reverse(); + groups.map((v, i) => { + writeWords = writeWords.concat(getRandomN(v, realRatio[i])) + }) + // console.log('writeWords', writeWords) + data.write = writeWords; } } - // console.timeEnd() - // console.log('data', data) + // console.log('data-new', data.new.map(v => v.word)) + // console.log('data-review', data.review.map(v => v.word)) + // console.log('data-write', data.write.map(v => v.word)) return data } diff --git a/src/pages/pc/article/StudyArticle.vue b/src/pages/pc/article/StudyArticle.vue index 8fface4d..f1510933 100644 --- a/src/pages/pc/article/StudyArticle.vue +++ b/src/pages/pc/article/StudyArticle.vue @@ -157,7 +157,7 @@ function setArticle(val: Article) { articleData.article.sections.map((v, i) => { v.map((w, j) => { w.words.map(s => { - if (!store.knownWordsWithSimpleWords.includes(s.word.toLowerCase()) && !s.isSymbol) { + if (!store.allIgnoreWords.includes(s.word.toLowerCase()) && !s.isSymbol) { statisticsStore.total++ } }) @@ -199,13 +199,13 @@ function wrong(word: Word) { if (!store.wrong.words.find((v: Word) => v.word.toLowerCase() === lowerName)) { store.wrong.words.push(word) } - if (!store.knownWordsWithSimpleWords.includes(lowerName)) { + if (!store.allIgnoreWords.includes(lowerName)) { //todo } } function nextWord(word: ArticleWord) { - if (!store.knownWordsWithSimpleWords.includes(word.word.toLowerCase()) && !word.isSymbol) { + if (!store.allIgnoreWords.includes(word.word.toLowerCase()) && !word.isSymbol) { statisticsStore.inputWordNumber++ } } diff --git a/src/pages/pc/article/components/TypingArticle.vue b/src/pages/pc/article/components/TypingArticle.vue index cd4535cd..8793478d 100644 --- a/src/pages/pc/article/components/TypingArticle.vue +++ b/src/pages/pc/article/components/TypingArticle.vue @@ -160,7 +160,7 @@ function nextSentence() { input = wrong = '' //todo 计得把略过的单词加上统计里面去 - // if (!store.knownWordsWithSimpleWords.includes(currentWord.word.toLowerCase()) && !currentWord.isSymbol) { + // if (!store.allIgnoreWords.includes(currentWord.word.toLowerCase()) && !currentWord.isSymbol) { // statisticsStore.inputNumber++ // } diff --git a/src/pages/pc/components/base/Switch.vue b/src/pages/pc/components/base/Switch.vue index a0b996ce..a3396fe2 100644 --- a/src/pages/pc/components/base/Switch.vue +++ b/src/pages/pc/components/base/Switch.vue @@ -1,15 +1,20 @@ + + + + diff --git a/src/pages/pc/word/WordHomePage.vue b/src/pages/pc/word/WordHomePage.vue index a6d04aba..17de57c2 100644 --- a/src/pages/pc/word/WordHomePage.vue +++ b/src/pages/pc/word/WordHomePage.vue @@ -31,9 +31,9 @@ let currentStudy = $ref({ write: [] }) -//todo 当选完词返回时,计算今日任务时,还是老的词典 -onMounted(init) -watch(() => store.load, init) +watch(() => store.load, n => { + if (n) init() +}, {immediate: true}) async function init() { if (store.word.studyIndex >= 3) { diff --git a/src/router.ts b/src/router.ts index 8ef2457a..d1c90c1a 100644 --- a/src/router.ts +++ b/src/router.ts @@ -10,7 +10,7 @@ import StudyWord from "@/pages/pc/word/StudyWord.vue"; import BookDetail from "@/pages/pc/article/BookDetail.vue"; import DictList from "@/pages/pc/word/DictList.vue"; import BookList from "@/pages/pc/article/BookList.vue"; -import Setting from "@/pages/pc/Setting.vue"; +import Setting from "@/pages/pc/setting/Setting.vue"; export const routes: RouteRecordRaw[] = [ { diff --git a/src/stores/base.ts b/src/stores/base.ts index 331cfb01..8b0a785c 100644 --- a/src/stores/base.ts +++ b/src/stores/base.ts @@ -77,8 +77,8 @@ export const useBaseStore = defineStore('base', { knownWords(): string[] { return this.known.words.map((v: Word) => v.word.toLowerCase()) }, - knownWordsWithSimpleWords() { - return this.known.words.map((v: Word) => v.word.toLowerCase()).concat(this.simpleWords) + allIgnoreWords() { + return this.known.words.map((v: Word) => v.word.toLowerCase()).concat(this.simpleWords.map((v: string) => v.toLowerCase())) }, currentStudyWordDict(): Dict { if (this.word.studyIndex >= 0) { diff --git a/src/stores/setting.ts b/src/stores/setting.ts index f8a484eb..75f889e3 100644 --- a/src/stores/setting.ts +++ b/src/stores/setting.ts @@ -22,7 +22,6 @@ export interface SettingState { repeatCustomCount?: number, dictation: boolean, translate: boolean, - detail: boolean, showNearWord: boolean ignoreCase: boolean allowWordTip: boolean @@ -36,17 +35,14 @@ export interface SettingState { showPanel: boolean, sideExpand: boolean, theme: string, - collapse: boolean, - chapterWordNumber: number, shortcutKeyMap: Record, first: boolean firstTime: number load: boolean conflictNotice: boolean // 其他脚本/插件冲突提示 + ignoreSimpleWord: boolean // 忽略简单词 } -export const DefaultChapterWordNumber = 30 - export const getDefaultSettingState = (): SettingState => ({ showToolbar: true, show: false, @@ -67,7 +63,6 @@ export const getDefaultSettingState = (): SettingState => ({ repeatCustomCount: null, dictation: false, translate: true, - detail: false, showNearWord: true, ignoreCase: true, @@ -80,13 +75,12 @@ export const getDefaultSettingState = (): SettingState => ({ }, waitTimeForChangeWord: 300, theme: 'auto', - collapse: false, - chapterWordNumber: DefaultChapterWordNumber, shortcutKeyMap: cloneDeep(DefaultShortcutKeyMap), first: true, firstTime: Date.now(), load: false, - conflictNotice: true + conflictNotice: true, + ignoreSimpleWord: false }) export const useSettingStore = defineStore('setting', { diff --git a/src/utils/const.ts b/src/utils/const.ts index 98e4043a..9012407d 100644 --- a/src/utils/const.ts +++ b/src/utils/const.ts @@ -14,7 +14,7 @@ export const SAVE_DICT_KEY = { } export const SAVE_SETTING_KEY = { key: 'typing-word-setting', - version: 9 + version: 10 } export const EXPORT_DATA_KEY = { key: 'typing-word-export', diff --git a/src/utils/index.ts b/src/utils/index.ts index 0d769404..d29c5c76 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -587,3 +587,30 @@ export function groupBy>(array: T[], key: string) return result; }, {}); } + +//随机取N个 +export function getRandomN(arr: any[], n: number) { + const copy = [...arr] + for (let i = copy.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [copy[i], copy[j]] = [copy[j], copy[i]] // 交换 + } + return copy.slice(0, n) +} + +//数组分成N份 +export function splitIntoN(arr: any[], n: number) { + const result = [] + const len = arr.length + const base = Math.floor(len / n) // 每份至少这么多 + let extra = len % n // 前几份多 1 个 + + let index = 0 + for (let i = 0; i < n; i++) { + const size = base + (extra > 0 ? 1 : 0) + result.push(arr.slice(index, index + size)) + index += size + if (extra > 0) extra-- + } + return result +}