From 7a3475cee10a72f1e1242894a8540afa2ac74d63 Mon Sep 17 00:00:00 2001 From: Zyronon Date: Wed, 24 Dec 2025 02:10:24 +0800 Subject: [PATCH] wip --- components.d.ts | 4 +- package.json | 1 + pnpm-lock.yaml | 10 + src/config/env.ts | 3 +- src/hooks/dict.ts | 12 +- src/pages/word/PracticeWords.vue | 489 +++++++++++++-------------- src/pages/word/WordsPage.vue | 33 +- src/pages/word/components/Footer.vue | 73 ++-- src/stores/practice.ts | 23 +- src/types/types.ts | 395 ++++++++++++---------- 10 files changed, 537 insertions(+), 506 deletions(-) diff --git a/components.d.ts b/components.d.ts index 20e2399b..ea0d8f0b 100644 --- a/components.d.ts +++ b/components.d.ts @@ -19,7 +19,6 @@ declare module 'vue' { BaseList: typeof import('./src/components/list/BaseList.vue')['default'] BasePage: typeof import('./src/components/BasePage.vue')['default'] BaseTable: typeof import('./src/components/BaseTable.vue')['default'] - BaseTable2: typeof import('./src/components/BaseTable2.vue')['default'] Book: typeof import('./src/components/Book.vue')['default'] ChannelIcons: typeof import('./src/components/ChannelIcons/ChannelIcons.vue')['default'] Checkbox: typeof import('./src/components/base/checkbox/Checkbox.vue')['default'] @@ -51,7 +50,6 @@ declare module 'vue' { IconFluentArrowClockwise20Regular: typeof import('~icons/fluent/arrow-clockwise20-regular')['default'] IconFluentArrowDownload20Regular: typeof import('~icons/fluent/arrow-download20-regular')['default'] IconFluentArrowLeft16Regular: typeof import('~icons/fluent/arrow-left16-regular')['default'] - IconFluentArrowMove20Regular: typeof import('~icons/fluent/arrow-move20-regular')['default'] IconFluentArrowRepeatAll20Regular: typeof import('~icons/fluent/arrow-repeat-all20-regular')['default'] IconFluentArrowRight16Regular: typeof import('~icons/fluent/arrow-right16-regular')['default'] IconFluentArrowShuffle16Regular: typeof import('~icons/fluent/arrow-shuffle16-regular')['default'] @@ -125,10 +123,12 @@ declare module 'vue' { IconMaterialSymbolsMail: typeof import('~icons/material-symbols/mail')['default'] IconMdiSparkles: typeof import('~icons/mdi/sparkles')['default'] IconPhExportLight: typeof import('~icons/ph/export-light')['default'] + IconPhMicrosoftWordLogoLight: typeof import('~icons/ph/microsoft-word-logo-light')['default'] IconRiTwitterFill: typeof import('~icons/ri/twitter-fill')['default'] IconSimpleIconsGithub: typeof import('~icons/simple-icons/github')['default'] IconSimpleIconsWechat: typeof import('~icons/simple-icons/wechat')['default'] IconSimpleIconsXiaohongshu: typeof import('~icons/simple-icons/xiaohongshu')['default'] + IconStreamlineColorPenDrawFlat: typeof import('~icons/streamline-color/pen-draw-flat')['default'] IconStreamlineDiscountPercentCoupon: typeof import('~icons/streamline/discount-percent-coupon')['default'] IconSystemUiconsImport: typeof import('~icons/system-uicons/import')['default'] IconUiwAlipay: typeof import('~icons/uiw/alipay')['default'] diff --git a/package.json b/package.json index f8e89b2a..ac71b78e 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "@iconify-json/ri": "^1.2.5", "@iconify-json/simple-icons": "^1.2.48", "@iconify-json/streamline": "^1.2.5", + "@iconify-json/streamline-color": "^1.2.2", "@iconify-json/system-uicons": "^1.2.4", "@iconify-json/uiw": "^1.2.3", "@types/file-saver": "^2.0.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5240a8fa..5910fe57 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -108,6 +108,9 @@ importers: '@iconify-json/streamline': specifier: ^1.2.5 version: 1.2.5 + '@iconify-json/streamline-color': + specifier: ^1.2.2 + version: 1.2.2 '@iconify-json/system-uicons': specifier: ^1.2.4 version: 1.2.4 @@ -571,6 +574,9 @@ packages: '@iconify-json/simple-icons@1.2.48': resolution: {integrity: sha512-EACOtZMoPJtERiAbX1De0asrrCtlwI27+03c9OJlYWsly9w1O5vcD8rTzh+kDPjo+K8FOVnq2Qy+h/CzljSKDA==} + '@iconify-json/streamline-color@1.2.2': + resolution: {integrity: sha512-+ypc4kzeKTFbHVM2uNWFqt1iR7E4XeMTI3Wa3LcmeHLPjyk6u6e9NJqqOHUU02rpA8GaN80XHySXzX+4DuZbzA==} + '@iconify-json/streamline@1.2.5': resolution: {integrity: sha512-u6l9BOJoIIPjjDXWl6D/hPDzeBk5WiaEHZ+U9SbkQ14N9hgotaYyIZVMfgF175CG1TTS06j8k15D3FM2OYaFIw==} @@ -4263,6 +4269,10 @@ snapshots: dependencies: '@iconify/types': 2.0.0 + '@iconify-json/streamline-color@1.2.2': + dependencies: + '@iconify/types': 2.0.0 + '@iconify-json/streamline@1.2.5': dependencies: '@iconify/types': 2.0.0 diff --git a/src/config/env.ts b/src/config/env.ts index c0c1ee9c..81d15e4d 100644 --- a/src/config/env.ts +++ b/src/config/env.ts @@ -19,7 +19,7 @@ export const ENV = Object.assign(map['DEV'], common) export let AppEnv = { TOKEN: localStorage.getItem('token') ?? '', - IS_OFFICIAL: true, + IS_OFFICIAL: false, IS_LOGIN: false, CAN_REQUEST: false, } @@ -92,6 +92,7 @@ export const TourConfig = { total: 7, } +export const IS_DEV = import.meta.env.MODE === 'development' export const LIB_JS_URL = { SHEPHERD: import.meta.env.MODE === 'development' diff --git a/src/hooks/dict.ts b/src/hooks/dict.ts index 1989ff1e..8253688b 100644 --- a/src/hooks/dict.ts +++ b/src/hooks/dict.ts @@ -144,12 +144,12 @@ export function getCurrentStudyWord(): TaskWords { } } - //如果是自由模式,那么统统设置到new字段里面去 - if (settingStore.wordPracticeMode === WordPracticeMode.Free) { - data.new = data.new.length ? data.new : data.review - data.review = [] - return data - } + // //如果是自由模式,那么统统设置到new字段里面去 + // if (settingStore.wordPracticeMode === WordPracticeMode.Free) { + // data.new = data.new.length ? data.new : data.review + // data.review = [] + // return data + // } // 上上次更早的单词 //默认只取start之前的单词 diff --git a/src/pages/word/PracticeWords.vue b/src/pages/word/PracticeWords.vue index 5f851143..d53c966e 100644 --- a/src/pages/word/PracticeWords.vue +++ b/src/pages/word/PracticeWords.vue @@ -12,6 +12,7 @@ import { TaskWords, Word, WordPracticeMode, + WordPracticeStage, WordPracticeType, } from '@/types/types.ts' import { @@ -45,7 +46,14 @@ import { getDefaultDict, getDefaultWord } from '@/types/func.ts' import ConflictNotice from '@/components/ConflictNotice.vue' import PracticeLayout from '@/components/PracticeLayout.vue' -import { AppEnv, DICT_LIST, LIB_JS_URL, PracticeSaveWordKey, TourConfig } from '@/config/env.ts' +import { + AppEnv, + DICT_LIST, + IS_DEV, + LIB_JS_URL, + PracticeSaveWordKey, + TourConfig, +} from '@/config/env.ts' import { ToastInstance } from '@/components/base/toast/type.ts' import { watchOnce } from '@vueuse/core' import { setUserDictProp } from '@/apis' @@ -115,11 +123,11 @@ async function loadDict() { } watch( - () => store.load, - n => { - if (n && loading) loadDict() - }, - { immediate: true } + () => store.load, + n => { + if (n && loading) loadDict() + }, + { immediate: true } ) onMounted(() => { @@ -144,50 +152,50 @@ onUnmounted(() => { }) watchOnce( - () => data.words.length, - (newVal, oldVal) => { - //如果是从无值变有值,代表是开始 - if (!oldVal && newVal) { - _nextTick(async () => { - const Shepherd = await loadJsLib('Shepherd', LIB_JS_URL.SHEPHERD) - const tour = new Shepherd.Tour(TourConfig) - tour.on('cancel', () => { - localStorage.setItem('tour-guide', '1') - }) - tour.addStep({ - id: 'step5', - text: '这里可以练习拼写单词,只需要按下键盘上对应的按键即可,没有输入框!', - attachTo: { element: '#word', on: 'bottom' }, - buttons: [ - { - text: `下一步(5/${TourConfig.total})`, - action: tour.next, - }, - ], - }) + () => data.words.length, + (newVal, oldVal) => { + //如果是从无值变有值,代表是开始 + if (!oldVal && newVal) { + _nextTick(async () => { + const Shepherd = await loadJsLib('Shepherd', LIB_JS_URL.SHEPHERD) + const tour = new Shepherd.Tour(TourConfig) + tour.on('cancel', () => { + localStorage.setItem('tour-guide', '1') + }) + tour.addStep({ + id: 'step5', + text: '这里可以练习拼写单词,只需要按下键盘上对应的按键即可,没有输入框!', + attachTo: { element: '#word', on: 'bottom' }, + buttons: [ + { + text: `下一步(5/${TourConfig.total})`, + action: tour.next, + }, + ], + }) - tour.addStep({ - id: 'step6', - text: '这里是文章练习', - attachTo: { element: '#article', on: 'top' }, - buttons: [ - { - text: `下一步(6/${TourConfig.total})`, - action() { - tour.next() - router.push('/articles') - }, + tour.addStep({ + id: 'step6', + text: '这里是文章练习', + attachTo: { element: '#article', on: 'top' }, + buttons: [ + { + text: `下一步(6/${TourConfig.total})`, + action() { + tour.next() + router.push('/articles') }, - ], - }) + }, + ], + }) - const r = localStorage.getItem('tour-guide') - if (settingStore.first && !r && !isMobile()) { - tour.start() - } - }, 500) - } + const r = localStorage.getItem('tour-guide') + if (settingStore.first && !r && !isMobile()) { + tour.start() + } + }, 500) } + } ) useStartKeyboardEventListener() @@ -197,6 +205,10 @@ function initData(initVal: TaskWords, init: boolean = false) { let d = localStorage.getItem(PracticeSaveWordKey.key) if (d && init) { try { + //todo 记得删除 + if (IS_DEV) { + throw new Error('开发环境,抛出错误跳过缓存') + } let obj = JSON.parse(d) let s = obj.val taskWords = Object.assign(taskWords, s.taskWords) @@ -211,71 +223,41 @@ function initData(initVal: TaskWords, init: boolean = false) { // taskWords = initVal //不能直接赋值,会导致 inject 的数据为默认值 taskWords = Object.assign(taskWords, initVal) - - // 检查是否为独立模式 - const isStandaloneMode = settingStore.wordPracticeMode >= WordPracticeMode.DictationOnly - - if (isStandaloneMode) { - // 独立模式:根据模式设置对应的练习类型 - switch (settingStore.wordPracticeMode) { - case WordPracticeMode.DictationOnly: - settingStore.wordPracticeType = WordPracticeType.Dictation - break - case WordPracticeMode.ListenOnly: - settingStore.wordPracticeType = WordPracticeType.Listen - break - case WordPracticeMode.IdentifyOnly: - settingStore.wordPracticeType = WordPracticeType.Identify - break - case WordPracticeMode.FollowWriteOnly: - settingStore.wordPracticeType = WordPracticeType.FollowWrite - break - } - - // 独立模式:按优先级选择起始单词列表(新词 -> 复习上次 -> 复习之前) - let selectedWords: Word[] = [] - if (taskWords.new.length > 0) { - currentWordListStage = 'new' - selectedWords = taskWords.new - } else if (taskWords.review.length > 0) { - currentWordListStage = 'review' - selectedWords = taskWords.review - } else if (taskWords.write.length > 0) { - currentWordListStage = 'write' - selectedWords = taskWords.write - } else { - Toast.warning('没有可学习的单词!') - router.push('/word') - return - } - - data.words = selectedWords - statStore.step = 0 // 独立模式不使用 step 逻辑 - statStore.total = taskWords.review.length + taskWords.new.length + taskWords.write.length - statStore.newWordNumber = taskWords.new.length - statStore.reviewWordNumber = taskWords.review.length - statStore.writeWordNumber = taskWords.write.length - } else if (taskWords.shuffle.length === 0) { - // 原有的智能模式逻辑 + + if (taskWords.shuffle.length === 0) { if (taskWords.new.length === 0) { if (taskWords.review.length) { settingStore.wordPracticeType = WordPracticeType.Identify statStore.step = 3 + statStore.stage = WordPracticeStage.IdentifyReview data.words = taskWords.review } else { if (taskWords.write.length) { settingStore.wordPracticeType = WordPracticeType.Identify data.words = taskWords.write statStore.step = 6 + statStore.stage = WordPracticeStage.IdentifyReviewAll } else { Toast.warning('没有可学习的单词!') router.push('/word') } } } else { - settingStore.wordPracticeType = WordPracticeType.FollowWrite data.words = taskWords.new statStore.step = 0 + if (settingStore.wordPracticeMode === WordPracticeMode.System) { + statStore.stage = WordPracticeStage.FollowWriteNewWord + } else if (settingStore.wordPracticeMode === WordPracticeMode.Free) { + statStore.stage = WordPracticeStage.FollowWriteNewWord + } else if (settingStore.wordPracticeMode === WordPracticeMode.IdentifyOnly) { + statStore.stage = WordPracticeStage.IdentifyNewWord + } else if (settingStore.wordPracticeMode === WordPracticeMode.DictationOnly) { + statStore.stage = WordPracticeStage.DictationNewWord + } else if (settingStore.wordPracticeMode === WordPracticeMode.ListenOnly) { + statStore.stage = WordPracticeStage.ListenNewWord + } else if (settingStore.wordPracticeMode === WordPracticeMode.FollowWriteOnly) { + statStore.stage = WordPracticeStage.FollowWriteNewWord + } } statStore.total = taskWords.review.length + taskWords.new.length + taskWords.write.length statStore.newWordNumber = taskWords.new.length @@ -285,6 +267,7 @@ function initData(initVal: TaskWords, init: boolean = false) { settingStore.wordPracticeType = WordPracticeType.Dictation data.words = taskWords.shuffle statStore.step = 10 + statStore.stage = WordPracticeStage.Shuffle statStore.total = taskWords.shuffle.length statStore.newWordNumber = 0 statStore.reviewWordNumber = 0 @@ -321,31 +304,34 @@ const nextWord: Word = $computed(() => { }) watch( - () => settingStore.wordPracticeType, - n => { - // Free 模式不自动设置,System 模式和独立模式都需要设置 - if (settingStore.wordPracticeMode === WordPracticeMode.Free) return - switch (n) { - case WordPracticeType.Spell: - case WordPracticeType.Dictation: - settingStore.dictation = true - settingStore.translate = true - break - case WordPracticeType.Listen: - settingStore.dictation = true - settingStore.translate = false - break - case WordPracticeType.FollowWrite: - settingStore.dictation = false - settingStore.translate = true - break - case WordPracticeType.Identify: - settingStore.dictation = false - settingStore.translate = false - break - } - }, - { immediate: true } + () => settingStore.wordPracticeMode, + n => { + // Free 模式不自动设置,System 模式和独立模式都需要设置 + if (settingStore.wordPracticeMode === WordPracticeMode.Free) return + switch (n) { + case WordPracticeMode.DictationOnly: + settingStore.dictation = true + settingStore.translate = true + settingStore.wordPracticeType = WordPracticeType.Dictation + break + case WordPracticeMode.ListenOnly: + settingStore.dictation = true + settingStore.translate = false + settingStore.wordPracticeType = WordPracticeType.Listen + break + case WordPracticeMode.FollowWriteOnly: + settingStore.dictation = false + settingStore.translate = true + settingStore.wordPracticeType = WordPracticeType.FollowWrite + break + case WordPracticeMode.IdentifyOnly: + settingStore.dictation = false + settingStore.translate = false + settingStore.wordPracticeType = WordPracticeType.Identify + break + } + }, + { immediate: true } ) const groupSize = 7 @@ -389,11 +375,29 @@ function goNextStep(originList, mode, msg) { } } +function nextStage(originList, log, nextStage) { + //每次都判断,因为每次都可能新增已掌握的单词 + let list = originList.filter(v => !data.excludeWords.includes(v.word)) + console.log(log) + if (list.length) { + if (toastInstance) toastInstance.close() + toastInstance = Toast.info('输入完成后按空格键切换下一个', { duration: 5000 }) + data.words = list + data.index = 0 + statStore.stage = nextStage + } else { + console.log(log + ':无单词略过') + statStore.stage = nextStage + next() + } +} + async function next(isTyping: boolean = true) { + debugger if (isTyping) statStore.inputWordNumber++ if (settingStore.wordPracticeMode === WordPracticeMode.Free) { if (data.index === data.words.length - 1) { - data.wrongWords = data.wrongWords.filter(v => (!data.excludeWords.includes(v.word))) + data.wrongWords = data.wrongWords.filter(v => !data.excludeWords.includes(v.word)) if (data.wrongWords.length) { isTypingWrongWord.value = true settingStore.wordPracticeType = WordPracticeType.FollowWrite @@ -410,62 +414,9 @@ async function next(isTyping: boolean = true) { } else { data.index++ } - } else if (settingStore.wordPracticeMode >= WordPracticeMode.DictationOnly) { - // 独立模式 - if (data.index === data.words.length - 1) { - // 处理错词 - data.wrongWords = data.wrongWords.filter(v => (!data.excludeWords.includes(v.word))) - if (data.wrongWords.length) { - isTypingWrongWord.value = true - console.log('当前学完了,但还有错词') - data.words = shuffle(cloneDeep(data.wrongWords)) - data.index = 0 - data.wrongWords = [] - } else { - isTypingWrongWord.value = false - // 按顺序切换到下一个单词列表:新词 -> 复习上次 -> 复习之前 -> 结束 - let nextWords: Word[] = [] - let nextStage: 'new' | 'review' | 'write' | 'finished' = 'finished' - - if (currentWordListStage === 'new') { - // 新词完成,切换到复习上次 - if (taskWords.review.length > 0) { - nextWords = taskWords.review - nextStage = 'review' - } else if (taskWords.write.length > 0) { - // 如果没有复习上次,直接跳到复习之前 - nextWords = taskWords.write - nextStage = 'write' - } - } else if (currentWordListStage === 'review') { - // 复习上次完成,切换到复习之前 - if (taskWords.write.length > 0) { - nextWords = taskWords.write - nextStage = 'write' - } - } - // currentWordListStage === 'write' 时,nextStage 保持为 'finished' - - if (nextStage === 'finished') { - // 全部完成 - console.log('独立模式,全完学完了') - showStatDialog = true - clearInterval(timer) - setTimeout(() => localStorage.removeItem(PracticeSaveWordKey.key), 300) - } else { - // 切换到下一个阶段 - currentWordListStage = nextStage - data.words = nextWords - data.index = 0 - // 保持相同的练习类型 - } - } - } else { - data.index++ - } } else { if (data.index === data.words.length - 1) { - if (statStore.step === 0 || isTypingWrongWord.value) { + if (statStore.stage === WordPracticeStage.FollowWriteNewWord || isTypingWrongWord.value) { if (settingStore.wordPracticeType !== WordPracticeType.Spell) { //回到最后一组的开始位置 data.index = Math.floor(data.index / groupSize) * groupSize @@ -474,7 +425,7 @@ async function next(isTyping: boolean = true) { return } } - data.wrongWords = data.wrongWords.filter(v => (!data.excludeWords.includes(v.word))) + data.wrongWords = data.wrongWords.filter(v => !data.excludeWords.includes(v.word)) if (data.wrongWords.length) { isTypingWrongWord.value = true settingStore.wordPracticeType = WordPracticeType.FollowWrite @@ -485,57 +436,87 @@ async function next(isTyping: boolean = true) { } else { isTypingWrongWord.value = false console.log('当前学完了,没错词', statStore.total, statStore.step, data.index) - //学完了,这里第 7 步如果无单词,加 3 就是 9 了 - if (statStore.step >= 8) { + + const complete = () => { console.log('全完学完了') showStatDialog = true clearInterval(timer) setTimeout(() => localStorage.removeItem(PracticeSaveWordKey.key), 300) - return; } - //开始默写之前 - if (statStore.step === 7) { - return goNextStep(shuffle(taskWords.write), WordPracticeType.Dictation, '开始默写之前') - } - - //开始听写之前 - if (statStore.step === 6) { - return goNextStep(shuffle(taskWords.write), WordPracticeType.Listen, '开始听写之前') - } - - //开始自测之前 - if (statStore.step === 5) { - return goNextStep(taskWords.write, WordPracticeType.Identify, '开始自测之前') - } - - //开始默写上次 - if (statStore.step === 4) { - return goNextStep(shuffle(taskWords.review), WordPracticeType.Dictation, '开始默写上次') - } - - //开始听写上次 - if (statStore.step === 3) { - return goNextStep(shuffle(taskWords.review), WordPracticeType.Listen, '开始听写上次') - } - - //开始自测昨日 - if (statStore.step === 2) { - return goNextStep(taskWords.review, WordPracticeType.Identify, '开始自测昨日') - } - - //开始默写新词 - if (statStore.step === 1) { - return goNextStep(shuffle(taskWords.new), WordPracticeType.Dictation, '开始默写新词') - } - - //开始听写新词 - if (statStore.step === 0) { - return goNextStep(shuffle(taskWords.new), WordPracticeType.Listen, '开始听写新词') + if (settingStore.wordPracticeMode === WordPracticeMode.System) { + if (statStore.stage === WordPracticeStage.FollowWriteNewWord) { + settingStore.wordPracticeType = WordPracticeType.Listen + return nextStage(shuffle(taskWords.new), '开始听写新词', WordPracticeStage.ListenNewWord) + } + if (statStore.stage === WordPracticeStage.ListenNewWord) { + settingStore.wordPracticeType = WordPracticeType.Dictation + return nextStage(shuffle(taskWords.new), '开始默写新词', WordPracticeStage.DictationNewWord) + } + if (statStore.stage === WordPracticeStage.DictationNewWord) { + settingStore.wordPracticeType = WordPracticeType.Identify + return nextStage(taskWords.review, '开始自测昨日', WordPracticeStage.IdentifyReview) + } + if (statStore.stage === WordPracticeStage.IdentifyReview) { + settingStore.wordPracticeType = WordPracticeType.Listen + return nextStage(shuffle(taskWords.review), '开始听写上次', WordPracticeStage.ListenReview) + } + if (statStore.stage === WordPracticeStage.ListenReview) { + settingStore.wordPracticeType = WordPracticeType.Dictation + return nextStage(shuffle(taskWords.review), '开始默写上次', WordPracticeStage.DictationReview) + } + if (statStore.stage === WordPracticeStage.DictationReview) { + settingStore.wordPracticeType = WordPracticeType.Identify + return nextStage(taskWords.write, '开始自测之前', WordPracticeStage.IdentifyReviewAll) + } + if (statStore.stage === WordPracticeStage.IdentifyReviewAll) { + settingStore.wordPracticeType = WordPracticeType.Listen + return nextStage(shuffle(taskWords.review), '开始听写之前', WordPracticeStage.ListenReviewAll) + } + if (statStore.stage === WordPracticeStage.ListenReviewAll) { + settingStore.wordPracticeType = WordPracticeType.Dictation + return nextStage(shuffle(taskWords.review), '开始默写之前', WordPracticeStage.DictationReviewAll) + } + if (statStore.stage === WordPracticeStage.DictationReviewAll) { + complete() + } + } else if (settingStore.wordPracticeMode === WordPracticeMode.ListenOnly) { + settingStore.wordPracticeType = WordPracticeType.Listen + if (statStore.stage === WordPracticeStage.ListenNewWord) { + return nextStage(taskWords.review, '开始听写昨日', WordPracticeStage.ListenReview) + } + if (statStore.stage === WordPracticeStage.ListenReview) { + return nextStage(taskWords.write, '开始听写之前', WordPracticeStage.ListenReviewAll) + } + if (statStore.stage === WordPracticeStage.ListenReviewAll) { + complete() + } + } else if (settingStore.wordPracticeMode === WordPracticeMode.DictationOnly) { + settingStore.wordPracticeType = WordPracticeType.Dictation + if (statStore.stage === WordPracticeStage.DictationNewWord) { + return nextStage(taskWords.review, '开始默写昨日', WordPracticeStage.DictationReview) + } + if (statStore.stage === WordPracticeStage.DictationReview) { + return nextStage(taskWords.write, '开始默写之前', WordPracticeStage.DictationReviewAll) + } + if (statStore.stage === WordPracticeStage.DictationReviewAll) { + complete() + } + } else if (settingStore.wordPracticeMode === WordPracticeMode.IdentifyOnly) { + settingStore.wordPracticeType = WordPracticeType.Identify + if (statStore.stage === WordPracticeStage.IdentifyNewWord) { + return nextStage(taskWords.review, '开始自测昨日', WordPracticeStage.IdentifyReview) + } + if (statStore.stage === WordPracticeStage.IdentifyReview) { + return nextStage(taskWords.write, '开始自测之前', WordPracticeStage.IdentifyReviewAll) + } + if (statStore.stage === WordPracticeStage.IdentifyReviewAll) { + complete() + } } } } else { - if (statStore.step === 0) { + if (statStore.stage === WordPracticeStage.FollowWriteNewWord) { wordLoop() } else { if (isTypingWrongWord.value) wordLoop() @@ -580,15 +561,15 @@ function onTypeWrong() { function savePracticeData() { // console.log('savePracticeData') localStorage.setItem( - PracticeSaveWordKey.key, - JSON.stringify({ - version: PracticeSaveWordKey.version, - val: { - taskWords, - practiceData: data, - statStoreData: statStore.$state, - }, - }) + PracticeSaveWordKey.key, + JSON.stringify({ + version: PracticeSaveWordKey.version, + val: { + taskWords, + practiceData: data, + statStoreData: statStore.$state, + }, + }) ) } @@ -699,8 +680,8 @@ async function continueStudy() { if (taskWords.shuffle.length) { let ignoreList = [store.allIgnoreWords, store.knownWords][settingStore.ignoreSimpleWord ? 0 : 1] temp.shuffle = shuffle(store.sdict.words.filter(v => !ignoreList.includes(v.word))).slice( - 0, - runtimeStore.routeData.total + 0, + runtimeStore.routeData.total ) if (showStatDialog) showStatDialog = false } else { @@ -782,9 +763,9 @@ useEvents([
@@ -795,11 +776,11 @@ useEvents([
@@ -809,18 +790,18 @@ useEvents([
{{ store.sdict.name }} ({{ store.sdict.lastLearnIndex }} / + >{{ store.sdict.name }} ({{ store.sdict.lastLearnIndex }} / {{ store.sdict.length }}) @@ -828,14 +809,14 @@ useEvents([
@@ -844,12 +825,12 @@ useEvents([ diff --git a/src/pages/word/WordsPage.vue b/src/pages/word/WordsPage.vue index 56273fc1..dc2e0482 100644 --- a/src/pages/word/WordsPage.vue +++ b/src/pages/word/WordsPage.vue @@ -130,6 +130,7 @@ function startPractice(practiceMode?: WordPracticeMode): void { } // 如果传入了独立模式,临时设置 wordPracticeMode if (practiceMode !== undefined) { + //todo 临时处理 localStorage.removeItem(PracticeSaveWordKey.key) settingStore.wordPracticeMode = practiceMode } @@ -377,16 +378,14 @@ let isNewHost = $ref(window.location.host === Host)
{{ currentStudy.new.length }}
新词数
- +
+
{{ currentStudy.review.length }}
+
复习上次
+
+
+
{{ currentStudy.write.length }}
+
复习之前
+
+ +
+ 智能 +
+
自由练习 diff --git a/src/pages/word/components/Footer.vue b/src/pages/word/components/Footer.vue index 48479272..f959ee57 100644 --- a/src/pages/word/components/Footer.vue +++ b/src/pages/word/components/Footer.vue @@ -2,7 +2,7 @@ import { inject, Ref } from 'vue' import { usePracticeStore } from '@/stores/practice.ts' import { useSettingStore } from '@/stores/setting.ts' -import { PracticeData, ShortcutKey } from '@/types/types.ts' +import { PracticeData, ShortcutKey, WordPracticeStage } from '@/types/types.ts' import BaseIcon from '@/components/BaseIcon.vue' import Tooltip from '@/components/base/Tooltip.vue' import Progress from '@/components/base/Progress.vue' @@ -35,43 +35,52 @@ function format(val: number, suffix: string = '', check: number = -1) { const status = $computed(() => { if (isTypingWrongWord.value) return '复习错词' - return getStepStr(statStore.step) + return getStageStr(statStore.stage) }) -function getStepStr(step: number) { +function getStageStr(stage: WordPracticeStage) { let str = '' - switch (step) { - case 0: - str += `学习新词` + switch (stage) { + case WordPracticeStage.FollowWriteNewWord: + str += `跟写新词` break - case 1: + case WordPracticeStage.IdentifyNewWord: + str += `自测新词` + break + case WordPracticeStage.ListenNewWord: str += `听写新词` break - case 2: + case WordPracticeStage.DictationNewWord: str += `默写新词` break - case 3: + case WordPracticeStage.FollowWriteReview: + str += `跟写上次学习` + break + case WordPracticeStage.IdentifyReview: str += `自测上次学习` break - case 4: - str += '听写上次学习' + case WordPracticeStage.ListenReview: + str += `听写上次学习` break - case 5: - str += '默写上次学习' + case WordPracticeStage.DictationReview: + str += `默写上次学习` break - case 6: + case WordPracticeStage.FollowWriteReviewAll: + str += '跟写之前学习' + break + case WordPracticeStage.IdentifyReviewAll: str += '自测之前学习' break - case 7: + case WordPracticeStage.ListenReviewAll: str += '听写之前学习' break - case 8: + case WordPracticeStage.DictationReviewAll: str += '默写之前学习' break - case 9: + case WordPracticeStage.Complete: str += '学习完成' break - case 10: + case WordPracticeStage.Shuffle: str += '随机复习' break } @@ -128,31 +137,31 @@ const progress = $computed(() => {
- +
- - + + {{ - (!isSimple ? '标记为已掌握' : '取消标记已掌握') + + (!isSimple ? '标记已掌握' : '取消已掌握') + `(${settingStore.shortcutKeyMap[ShortcutKey.ToggleSimple]})` }}
- +
- - + + {{ (!isCollect ? '收藏' : '取消收藏') + @@ -161,17 +170,15 @@ const progress = $computed(() => { >
- +
- - - 跳过当前单词({{ settingStore.shortcutKeyMap[ShortcutKey.Next] }}) + + 跳过单词({{ settingStore.shortcutKeyMap[ShortcutKey.Next] }})
- +
diff --git a/src/stores/practice.ts b/src/stores/practice.ts index a3bac276..c19d2037 100644 --- a/src/stores/practice.ts +++ b/src/stores/practice.ts @@ -1,21 +1,24 @@ -import {defineStore} from "pinia" +import { defineStore } from 'pinia' +import { WordPracticeStage } from '@/types/types.ts' export interface PracticeState { - step: number, - startDate: number, - spend: number, - total: number, - newWordNumber: number, - reviewWordNumber: number, - writeWordNumber: number, - inputWordNumber: number,//当前总输入了多少个单词(不包含跳过) - wrong: number, + step: number + stage: WordPracticeStage + startDate: number + spend: number + total: number + newWordNumber: number + reviewWordNumber: number + writeWordNumber: number + inputWordNumber: number //当前总输入了多少个单词(不包含跳过) + wrong: number } export const usePracticeStore = defineStore('practice', { state: (): PracticeState => { return { step: 0, + stage: WordPracticeStage.FollowWriteNewWord, spend: 0, startDate: Date.now(), total: 0, diff --git a/src/types/types.ts b/src/types/types.ts index 1af5fd77..0a096d26 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -1,40 +1,40 @@ export type Word = { - id?: string, - custom?: boolean, - word: string, - phonetic0: string, - phonetic1: string, - trans: { - pos: string, - cn: string, - }[], - sentences: { - c: string,//content - cn: string, - }[], - phrases: { - c: string, - cn: string, - }[], - synos: { - pos: string, - cn: string, - ws: string[] - }[], - relWords: { - root: string, - rels: { - pos: string, - words: { - c: string, - cn: string, - }[], - }[] - }, - etymology: { - t: string,//title - d: string,//desc - }[], + id?: string + custom?: boolean + word: string + phonetic0: string + phonetic1: string + trans: { + pos: string + cn: string + }[] + sentences: { + c: string //content + cn: string + }[] + phrases: { + c: string + cn: string + }[] + synos: { + pos: string + cn: string + ws: string[] + }[] + relWords: { + root: string + rels: { + pos: string + words: { + c: string + cn: string + }[] + }[] + } + etymology: { + t: string //title + d: string //desc + }[] } export const PronunciationApi = 'https://dict.youdao.com/dictvoice?audio=' @@ -43,216 +43,237 @@ export type TranslateLanguageType = 'en' | 'zh-CN' | 'ja' | 'de' | 'common' | '' export type LanguageType = 'en' | 'ja' | 'de' | 'code' export enum DictType { - collect = 'collect', - simple = 'simple', - wrong = 'wrong', - known = 'known', - word = 'word', - article = 'article', + collect = 'collect', + simple = 'simple', + wrong = 'wrong', + known = 'known', + word = 'word', + article = 'article', } export interface ArticleWord extends Word { - nextSpace: boolean, - symbolPosition: 'start' | 'end' | '', - input: string - type: PracticeArticleWordType + nextSpace: boolean + symbolPosition: 'start' | 'end' | '' + input: string + type: PracticeArticleWordType } export interface Sentence { - text: string, - translate: string, - words: ArticleWord[], - audioPosition: number[] + text: string + translate: string + words: ArticleWord[] + audioPosition: number[] } export interface Article { - id?: number, - title: string, - titleTranslate: string, - text: string, - textTranslate: string, - newWords: Word[], - sections: Sentence[][], - audioSrc: string, - audioFileId: string, - lrcPosition: number[][], - nameList: string[], - questions: { - stem: string, - options: string[], - correctAnswer: string[], - explanation: string - }[] + id?: number + title: string + titleTranslate: string + text: string + textTranslate: string + newWords: Word[] + sections: Sentence[][] + audioSrc: string + audioFileId: string + lrcPosition: number[][] + nameList: string[] + questions: { + stem: string + options: string[] + correctAnswer: string[] + explanation: string + }[] } export interface Statistics { - startDate: number,//开始日期 - spend: number,//花费时间 - total: number//单词数量 - new: number//新学单词数量 - review: number//复习单词数量 - wrong: number//错误数 + startDate: number //开始日期 + spend: number //花费时间 + total: number //单词数量 + new: number //新学单词数量 + review: number //复习单词数量 + wrong: number //错误数 } export enum Sort { - normal = 0, - random = 1, - reverse = 2, - reverseAll = 3, - randomAll = 4, + normal = 0, + random = 1, + reverse = 2, + reverseAll = 3, + randomAll = 4, } export enum ShortcutKey { - ShowWord = 'ShowWord', - EditArticle = 'EditArticle', - Next = 'Next', - Previous = 'Previous', - ToggleSimple = 'ToggleSimple', - ToggleCollect = 'ToggleCollect', - NextChapter = 'NextChapter', - PreviousChapter = 'PreviousChapter', - RepeatChapter = 'RepeatChapter', - DictationChapter = 'DictationChapter', - PlayWordPronunciation = 'PlayWordPronunciation', - ToggleShowTranslate = 'ToggleShowTranslate', - ToggleDictation = 'ToggleDictation', - ToggleTheme = 'ToggleTheme', - ToggleConciseMode = 'ToggleConciseMode', - TogglePanel = 'TogglePanel', - RandomWrite = 'RandomWrite', - NextRandomWrite = 'NextRandomWrite', - KnowWord = 'KnowWord', - UnknownWord = 'UnknownWord', + ShowWord = 'ShowWord', + EditArticle = 'EditArticle', + Next = 'Next', + Previous = 'Previous', + ToggleSimple = 'ToggleSimple', + ToggleCollect = 'ToggleCollect', + NextChapter = 'NextChapter', + PreviousChapter = 'PreviousChapter', + RepeatChapter = 'RepeatChapter', + DictationChapter = 'DictationChapter', + PlayWordPronunciation = 'PlayWordPronunciation', + ToggleShowTranslate = 'ToggleShowTranslate', + ToggleDictation = 'ToggleDictation', + ToggleTheme = 'ToggleTheme', + ToggleConciseMode = 'ToggleConciseMode', + TogglePanel = 'TogglePanel', + RandomWrite = 'RandomWrite', + NextRandomWrite = 'NextRandomWrite', + KnowWord = 'KnowWord', + UnknownWord = 'UnknownWord', } export const DefaultShortcutKeyMap = { - [ShortcutKey.EditArticle]: 'Ctrl+E', - [ShortcutKey.ShowWord]: 'Escape', - [ShortcutKey.Previous]: 'Alt+⬅', - [ShortcutKey.Next]: 'Tab', - [ShortcutKey.ToggleSimple]: '`', - [ShortcutKey.ToggleCollect]: 'Enter', - [ShortcutKey.PreviousChapter]: 'Ctrl+⬅', - [ShortcutKey.NextChapter]: 'Ctrl+➡', - [ShortcutKey.RepeatChapter]: 'Ctrl+Enter', - [ShortcutKey.DictationChapter]: 'Alt+Enter', - [ShortcutKey.PlayWordPronunciation]: 'Ctrl+P', - [ShortcutKey.ToggleShowTranslate]: 'Ctrl+Z', - [ShortcutKey.ToggleDictation]: 'Ctrl+I', - [ShortcutKey.ToggleTheme]: 'Ctrl+Q', - [ShortcutKey.ToggleConciseMode]: 'Ctrl+M', - [ShortcutKey.TogglePanel]: 'Ctrl+L', - [ShortcutKey.RandomWrite]: 'Ctrl+R', - [ShortcutKey.NextRandomWrite]: 'Ctrl+Shift+R', - [ShortcutKey.KnowWord]: '1', - [ShortcutKey.UnknownWord]: '2', + [ShortcutKey.EditArticle]: 'Ctrl+E', + [ShortcutKey.ShowWord]: 'Escape', + [ShortcutKey.Previous]: 'Alt+⬅', + [ShortcutKey.Next]: 'Tab', + [ShortcutKey.ToggleSimple]: '`', + [ShortcutKey.ToggleCollect]: 'Enter', + [ShortcutKey.PreviousChapter]: 'Ctrl+⬅', + [ShortcutKey.NextChapter]: 'Ctrl+➡', + [ShortcutKey.RepeatChapter]: 'Ctrl+Enter', + [ShortcutKey.DictationChapter]: 'Alt+Enter', + [ShortcutKey.PlayWordPronunciation]: 'Ctrl+P', + [ShortcutKey.ToggleShowTranslate]: 'Ctrl+Z', + [ShortcutKey.ToggleDictation]: 'Ctrl+I', + [ShortcutKey.ToggleTheme]: 'Ctrl+Q', + [ShortcutKey.ToggleConciseMode]: 'Ctrl+M', + [ShortcutKey.TogglePanel]: 'Ctrl+L', + [ShortcutKey.RandomWrite]: 'Ctrl+R', + [ShortcutKey.NextRandomWrite]: 'Ctrl+Shift+R', + [ShortcutKey.KnowWord]: '1', + [ShortcutKey.UnknownWord]: '2', } export enum TranslateEngine { - Baidu = 0, + Baidu = 0, } export type DictResource = { - id: string - name: string - description: string - url: string - length: number - category: string - tags: string[] - translateLanguage: TranslateLanguageType - //todo 可以考虑删除了 - type?: DictType - version?: number - language: LanguageType + id: string + name: string + description: string + url: string + length: number + category: string + tags: string[] + translateLanguage: TranslateLanguageType + //todo 可以考虑删除了 + type?: DictType + version?: number + language: LanguageType } export interface Dict extends DictResource { - lastLearnIndex: number, - perDayStudyNumber: number, - words: Word[], - articles: Article[], - statistics: Statistics[], - custom: boolean,//是否是自定义词典 - complete: boolean,//是否学习完成,学完了设为true,然后lastLearnIndex重置 - //后端字段 - en_name?: string - createdBy?: string - category_id?: number - is_default?: boolean - update?: boolean - cover?: string - sync?: boolean - userDictId?: number + lastLearnIndex: number + perDayStudyNumber: number + words: Word[] + articles: Article[] + statistics: Statistics[] + custom: boolean //是否是自定义词典 + complete: boolean //是否学习完成,学完了设为true,然后lastLearnIndex重置 + //后端字段 + en_name?: string + createdBy?: string + category_id?: number + is_default?: boolean + update?: boolean + cover?: string + sync?: boolean + userDictId?: number } export interface ArticleItem { - item: Article, - index: number + item: Article + index: number } export const SlideType = { - HORIZONTAL: 0, - VERTICAL: 1, + HORIZONTAL: 0, + VERTICAL: 1, } export interface PracticeData { - index: number, - words: Word[], - wrongWords: Word[], - excludeWords: string[], + index: number + words: Word[] + wrongWords: Word[] + excludeWords: string[] } export interface TaskWords { - new: Word[], - review: Word[], - write: Word[], - shuffle: Word[], + new: Word[] + review: Word[] + write: Word[] + shuffle: Word[] } export class DictId { - static wordCollect = 'wordCollect' - static wordWrong = 'wordWrong' - static wordKnown = 'wordKnown' - static articleCollect = 'articleCollect' + static wordCollect = 'wordCollect' + static wordWrong = 'wordWrong' + static wordKnown = 'wordKnown' + static articleCollect = 'articleCollect' } export enum PracticeArticleWordType { - Symbol, - Number, - Word + Symbol, + Number, + Word, } //练习模式 export enum WordPracticeMode { - System = 0, - Free = 1, - DictationOnly = 2, // 独立默写模式 - ListenOnly = 3, // 独立听写模式 - IdentifyOnly = 4, // 独立自测模式 - FollowWriteOnly = 5 // 独立跟写模式(内部会自动切换到 Spell) + System = 0, + Free = 1, + IdentifyOnly = 2, // 独立自测模式 + DictationOnly = 3, // 独立默写模式 + ListenOnly = 4, // 独立听写模式 + FollowWriteOnly = 5, // 独立跟写模式(内部会自动切换到 Spell) } //练习类型 export enum WordPracticeType { - FollowWrite,//跟写 - Spell, - Identify, - Listen, - Dictation + FollowWrite, //跟写 + Spell, + Identify, + Listen, + Dictation, } export enum CodeType { - Login = 0, - Register = 1, - ResetPwd = 2, - ChangeEmail = 3, - ChangePhoneNew = 4, - ChangePhoneOld = 5 + Login = 0, + Register = 1, + ResetPwd = 2, + ChangeEmail = 3, + ChangePhoneNew = 4, + ChangePhoneOld = 5, } export enum ImportStatus { - Idle = 0, - Success = 1, - Fail = 2 -} \ No newline at end of file + Idle = 0, + Success = 1, + Fail = 2, +} + +//练习阶段 +export enum WordPracticeStage { + FollowWriteNewWord = 0, + IdentifyNewWord = 1, + ListenNewWord = 2, + DictationNewWord = 3, + + FollowWriteReview = 4, + IdentifyReview = 5, + ListenReview = 6, + DictationReview = 7, + + FollowWriteReviewAll = 8, + IdentifyReviewAll = 9, + ListenReviewAll = 10, + DictationReviewAll = 11, + + Shuffle = 12, + Complete = 13, +}