diff --git a/index.html b/index.html index b75567c4..c725424e 100644 --- a/index.html +++ b/index.html @@ -1,34 +1,34 @@ - - - - TypeWords练习英语 - - - + + +
diff --git a/src/assets/css/style.scss b/src/assets/css/style.scss index 0ff0b10d..5ab4b294 100644 --- a/src/assets/css/style.scss +++ b/src/assets/css/style.scss @@ -17,10 +17,11 @@ --practice-wrapper-translateX: 1px; --article-width: 50vw; + --article-toolbar-width: 50rem; --toolbar-width: 50rem; --panel-width: 24rem; --space: 1rem; - --stat-gap: 2rem; + --stat-gap: 1rem; --shadow: rgba(0, 0, 0, 0.08) 0px 4px 12px; --panel-margin-left: calc(50% + var(--toolbar-width) / 2 + 1rem); --article-panel-margin-left: calc(50% + var(--article-width) / 2 + 1rem); @@ -416,7 +417,7 @@ a { .book { @extend .anim; - @apply p-4 rounded-md relative cursor-pointer bg-third hover:bg-card-active flex flex-col justify-between; + @apply p-4 rounded-md relative cursor-pointer bg-third hover:bg-card-active flex flex-col justify-between shrink-0; $w: 6rem; width: $w; height: calc($w * 1.4); diff --git a/src/pages/pc/article/ArticleHomePage.vue b/src/pages/pc/article/ArticleHomePage.vue index 8e6fd056..52957e03 100644 --- a/src/pages/pc/article/ArticleHomePage.vue +++ b/src/pages/pc/article/ArticleHomePage.vue @@ -126,7 +126,7 @@ async function goBookDetail(val: DictResource) {
创建个人书籍
-
+
() +let editArticle = $ref
(getDefaultArticle()) + +useStartKeyboardEventListener() function write() { // console.log('write') @@ -27,81 +49,427 @@ function write() { } //TODO 需要判断是否已忽略 +//todo 使用场景是? function repeat() { // console.log('repeat') - emitter.emit(EventKey.resetWord) - practiceRef.getCurrentPractice() + getCurrentPractice() } function prev() { // console.log('next') - if (store.currentBook.chapterIndex === 0) { + if (store.sbook.lastLearnIndex === 0) { ElMessage.warning('已经在第一章了~') } else { - store.currentBook.chapterIndex-- - repeat() + store.sbook.lastLearnIndex-- + getCurrentPractice() } } -function toggleShowTranslate() { - settingStore.translate = !settingStore.translate -} - -function toggleDictation() { - settingStore.dictation = !settingStore.dictation -} +const toggleShowTranslate = () => settingStore.translate = !settingStore.translate +const toggleDictation = () => settingStore.dictation = !settingStore.dictation +const togglePanel = () => settingStore.showPanel = !settingStore.showPanel +const skip = () => typingArticleRef?.nextSentence() +const collect = () => toggleArticleCollect(articleData.article) +const shortcutKeyEdit = () => edit() function toggleConciseMode() { settingStore.showToolbar = !settingStore.showToolbar settingStore.showPanel = settingStore.showToolbar } -function togglePanel() { - settingStore.showPanel = !settingStore.showPanel +function next() { + if (store.sbook.lastLearnIndex >= articleData.list.length - 1) { + store.sbook.lastLearnIndex = 0 + //todo 这里应该弹窗 + } else store.sbook.lastLearnIndex++ + getCurrentPractice() } -function jumpSpecifiedChapter(val: number) { - store.currentBook.chapterIndex = val - repeat() +function init() { + if (!store.sbook?.articles?.length) { + router.push('/article') + return + } + articleData.list = cloneDeep(store.sbook.articles) + getCurrentPractice() + console.log('init', articleData.article) } +function setArticle(val: Article) { + statisticsStore.inputWordNumber = 0 + statisticsStore.wrong = 0 + statisticsStore.total = 0 + statisticsStore.startDate = Date.now() + + articleData.list[store.sbook.lastLearnIndex] = val + articleData.article = val + articleData.sectionIndex = 0 + articleData.sentenceIndex = 0 + articleData.wordIndex = 0 + articleData.stringIndex = 0 + articleData.article.sections.map((v, i) => { + v.map((w, j) => { + w.words.map(s => { + if (!store.knownWordsWithSimpleWords.includes(s.word.toLowerCase()) && !s.isSymbol) { + statisticsStore.total++ + } + }) + }) + }) +} + +function getCurrentPractice() { + emitter.emit(EventKey.resetWord) + let currentArticle = articleData.list[store.sbook.lastLearnIndex] + let article = getDefaultArticle(currentArticle) + // console.log('article', article) + if (article.sections.length) { + setArticle(article) + } else { + genArticleSectionData(article) + setArticle(article) + } +} + +function saveArticle(val: Article) { + console.log('saveArticle', val, JSON.stringify(val.lrcPosition)) + console.log('saveArticle', val.textTranslate) + showEditArticle = false + let rIndex = store.sbook.articles.findIndex(v => v.id === val.id) + if (rIndex > -1) { + store.sbook.articles[rIndex] = cloneDeep(val) + } + setArticle(val) +} + +function edit(val: Article = articleData.article) { + editArticle = val + showEditArticle = true +} + +function wrong(word: Word) { + let lowerName = word.word.toLowerCase(); + if (!store.wrong.words.find((v: Word) => v.word.toLowerCase() === lowerName)) { + store.wrong.words.push(word) + } + if (!store.knownWordsWithSimpleWords.includes(lowerName)) { + //todo + } +} + +function nextWord(word: ArticleWord) { + if (!store.knownWordsWithSimpleWords.includes(word.word.toLowerCase()) && !word.isSymbol) { + statisticsStore.inputWordNumber++ + } +} + +function changeArticle(val: ArticleItem) { + let rIndex = articleData.list.findIndex(v => v.id === val.item.id) + if (rIndex > -1) { + store.sbook.lastLearnIndex = rIndex + getCurrentPractice() + } +} + +const { + isArticleCollect, + toggleArticleCollect +} = useArticleOptions() + +function play() { + typingArticleRef?.play() +} + +function show() { + typingArticleRef?.showSentence() +} + + +function onKeyUp() { + typingArticleRef.hideSentence() +} + +async function onKeyDown(e: KeyboardEvent) { + // console.log('e', e) + switch (e.key) { + case 'Backspace': + typingArticleRef.del() + break + } +} + +useOnKeyboardEventListener(onKeyDown, onKeyUp) + + +onMounted(init) + +useEvents([ + [EventKey.write, write], + [EventKey.repeatStudy, repeat], + [EventKey.continueStudy, next], + + [ShortcutKey.PreviousChapter, prev], + [ShortcutKey.RepeatChapter, repeat], + [ShortcutKey.DictationChapter, write], + [ShortcutKey.ToggleShowTranslate, toggleShowTranslate], + [ShortcutKey.ToggleDictation, toggleDictation], + [ShortcutKey.ToggleTheme, toggleTheme], + [ShortcutKey.ToggleConciseMode, toggleConciseMode], + [ShortcutKey.TogglePanel, togglePanel], + [ShortcutKey.NextChapter, next], + [ShortcutKey.PlayWordPronunciation, play], + [ShortcutKey.ShowWord, show], + [ShortcutKey.Next, skip], + [ShortcutKey.ToggleCollect, collect], + [ShortcutKey.EditArticle, shortcutKeyEdit], +]) + +let speedMinute = $ref(0) +let timer = $ref(0) onMounted(() => { - emitter.on(EventKey.write, write) - emitter.on(EventKey.repeatStudy, repeat) - emitter.on(EventKey.jumpSpecifiedChapter, jumpSpecifiedChapter) - - emitter.on(ShortcutKey.PreviousChapter, prev) - emitter.on(ShortcutKey.RepeatChapter, repeat) - emitter.on(ShortcutKey.DictationChapter, write) - emitter.on(ShortcutKey.ToggleShowTranslate, toggleShowTranslate) - emitter.on(ShortcutKey.ToggleDictation, toggleDictation) - emitter.on(ShortcutKey.ToggleTheme, toggleTheme) - emitter.on(ShortcutKey.ToggleConciseMode, toggleConciseMode) - emitter.on(ShortcutKey.TogglePanel, togglePanel) + timer = setInterval(() => { + speedMinute = Math.floor((Date.now() - statisticsStore.startDate) / 1000 / 60) + }, 1000) }) onUnmounted(() => { - emitter.off(EventKey.write, write) - emitter.off(EventKey.repeatStudy, repeat) - emitter.off(EventKey.jumpSpecifiedChapter, jumpSpecifiedChapter) - - emitter.off(ShortcutKey.PreviousChapter, prev) - emitter.off(ShortcutKey.RepeatChapter, repeat) - emitter.off(ShortcutKey.DictationChapter, write) - emitter.off(ShortcutKey.ToggleShowTranslate, toggleShowTranslate) - emitter.off(ShortcutKey.ToggleDictation, toggleDictation) - emitter.off(ShortcutKey.ToggleTheme, toggleTheme) - emitter.off(ShortcutKey.ToggleConciseMode, toggleConciseMode) - emitter.off(ShortcutKey.TogglePanel, togglePanel) + timer && clearInterval(timer) }) -useStartKeyboardEventListener() +let audioRef = $ref() +const {playSentenceAudio} = usePlaySentenceAudio() diff --git a/src/pages/pc/article/practice-article/TypingArticle.vue b/src/pages/pc/article/components/TypingArticle.vue similarity index 99% rename from src/pages/pc/article/practice-article/TypingArticle.vue rename to src/pages/pc/article/components/TypingArticle.vue index 387ad98a..90f70c68 100644 --- a/src/pages/pc/article/practice-article/TypingArticle.vue +++ b/src/pages/pc/article/components/TypingArticle.vue @@ -21,7 +21,6 @@ interface IProps { sentenceIndex?: number, wordIndex?: number, stringIndex?: number, - active: boolean, } const props = withDefaults(defineProps(), { @@ -30,7 +29,6 @@ const props = withDefaults(defineProps(), { sentenceIndex: 0, wordIndex: 0, stringIndex: 0, - active: true, }) const emit = defineEmits<{ @@ -38,7 +36,8 @@ const emit = defineEmits<{ wrong: [val: Word], play: [val: Sentence], nextWord: [val: ArticleWord], - over: [], + complete: [], + next: [], edit: [val: Article] }>() @@ -175,7 +174,7 @@ function nextSentence() { if (!props.article.sections[sectionIndex]) { console.log('打完了') isEnd = true - emit('over') + emit('complete') } else { emit('play', props.article.sections[sectionIndex][0]) } @@ -186,7 +185,6 @@ function nextSentence() { } function onTyping(e: KeyboardEvent) { - if (!props.active) return if (!props.article.sections.length) return // console.log('keyDown', e.key, e.code, e.keyCode) wrong = '' @@ -458,7 +456,7 @@ let showQuestions = $ref(false)
下一章 + @click="emit('next')">下一章
diff --git a/src/pages/pc/article/practice-article/index.vue b/src/pages/pc/article/practice-article/index.vue deleted file mode 100644 index 689305f7..00000000 --- a/src/pages/pc/article/practice-article/index.vue +++ /dev/null @@ -1,520 +0,0 @@ - - - - - diff --git a/src/pages/pc/components/list/DictList.vue b/src/pages/pc/components/list/DictList.vue index a1330364..aefa5f7e 100644 --- a/src/pages/pc/components/list/DictList.vue +++ b/src/pages/pc/components/list/DictList.vue @@ -18,7 +18,7 @@ const emit = defineEmits<{