feat: save
This commit is contained in:
1
components.d.ts
vendored
1
components.d.ts
vendored
@@ -42,7 +42,6 @@ declare module 'vue' {
|
||||
IconFluentArrowBounce20Regular: typeof import('~icons/fluent/arrow-bounce20-regular')['default']
|
||||
IconFluentArrowCircleRight16Regular: typeof import('~icons/fluent/arrow-circle-right16-regular')['default']
|
||||
IconFluentArrowLeft16Regular: typeof import('~icons/fluent/arrow-left16-regular')['default']
|
||||
IconFluentArrowMove20Regular: typeof import('~icons/fluent/arrow-move20-regular')['default']
|
||||
IconFluentArrowRight16Regular: typeof import('~icons/fluent/arrow-right16-regular')['default']
|
||||
IconFluentArrowShuffle16Regular: typeof import('~icons/fluent/arrow-shuffle16-regular')['default']
|
||||
IconFluentArrowSort20Regular: typeof import('~icons/fluent/arrow-sort20-regular')['default']
|
||||
|
||||
9502
pnpm-lock.yaml
generated
9502
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -151,7 +151,9 @@ function getShortcutKeyName(key: string): string {
|
||||
'ToggleConciseMode': '切换简洁模式',
|
||||
'TogglePanel': '切换面板',
|
||||
'RandomWrite': '随机默写',
|
||||
'NextRandomWrite': '继续随机默写'
|
||||
'NextRandomWrite': '继续随机默写',
|
||||
'KnowWord': '认识单词',
|
||||
'UnknownWord': '不认识单词',
|
||||
}
|
||||
|
||||
return shortcutKeyNameMap[key] || key
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import { onMounted, provide, ref, watch } from "vue";
|
||||
import {onMounted, provide, ref, watch} from "vue";
|
||||
|
||||
import Statistics from "@/pages/word/Statistics.vue";
|
||||
import { emitter, EventKey, useEvents } from "@/utils/eventBus.ts";
|
||||
import { useSettingStore } from "@/stores/setting.ts";
|
||||
import { useRuntimeStore } from "@/stores/runtime.ts";
|
||||
import { Dict, PracticeData, PracticeMode, ShortcutKey, TaskWords, Word } from "@/types/types.ts";
|
||||
import { useDisableEventListener, useOnKeyboardEventListener, useStartKeyboardEventListener } from "@/hooks/event.ts";
|
||||
import {emitter, EventKey, useEvents} from "@/utils/eventBus.ts";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {Dict, PracticeData, PracticeMode, ShortcutKey, TaskWords, Word} from "@/types/types.ts";
|
||||
import {useDisableEventListener, useOnKeyboardEventListener, useStartKeyboardEventListener} from "@/hooks/event.ts";
|
||||
import useTheme from "@/hooks/theme.ts";
|
||||
import { getCurrentStudyWord, useWordOptions } from "@/hooks/dict.ts";
|
||||
import { _getDictDataByUrl, cloneDeep, resourceWrap, shuffle, sleep } from "@/utils";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import {getCurrentStudyWord, useWordOptions} from "@/hooks/dict.ts";
|
||||
import {_getDictDataByUrl, cloneDeep, resourceWrap, shuffle, sleep} from "@/utils";
|
||||
import {useRoute, useRouter} from "vue-router";
|
||||
import Footer from "@/pages/word/components/Footer.vue";
|
||||
import Panel from "@/components/Panel.vue";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
@@ -19,16 +19,16 @@ import Tooltip from "@/components/base/Tooltip.vue";
|
||||
import WordList from "@/components/list/WordList.vue";
|
||||
import TypeWord from "@/pages/word/components/TypeWord.vue";
|
||||
import Empty from "@/components/Empty.vue";
|
||||
import { useBaseStore } from "@/stores/base.ts";
|
||||
import { usePracticeStore } from "@/stores/practice.ts";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import {usePracticeStore} from "@/stores/practice.ts";
|
||||
import Toast from '@/components/base/toast/Toast.ts'
|
||||
import { getDefaultDict, getDefaultWord } from "@/types/func.ts";
|
||||
import {getDefaultDict, getDefaultWord} from "@/types/func.ts";
|
||||
import ConflictNotice from "@/components/ConflictNotice.vue";
|
||||
import PracticeLayout from "@/components/PracticeLayout.vue";
|
||||
|
||||
import { DICT_LIST, PracticeSaveWordKey } from "@/config/env.ts";
|
||||
import { set } from "idb-keyval";
|
||||
import { ToastInstance } from "@/components/base/toast/type.ts";
|
||||
import {DICT_LIST, PracticeSaveWordKey} from "@/config/env.ts";
|
||||
import {set} from "idb-keyval";
|
||||
import {ToastInstance} from "@/components/base/toast/type.ts";
|
||||
|
||||
const {
|
||||
isWordCollect,
|
||||
@@ -50,13 +50,14 @@ let loading = $ref(false)
|
||||
let taskWords = $ref<TaskWords>({
|
||||
new: [],
|
||||
review: [],
|
||||
write: []
|
||||
write: [],
|
||||
})
|
||||
|
||||
let data = $ref<PracticeData>({
|
||||
index: 0,
|
||||
words: [],
|
||||
wrongWords: [],
|
||||
excludeWords: [],
|
||||
})
|
||||
let isTypingWrongWord = ref(false)
|
||||
|
||||
@@ -127,12 +128,12 @@ function initData(initVal: TaskWords, init: boolean = false) {
|
||||
taskWords = initVal
|
||||
if (taskWords.new.length === 0) {
|
||||
if (taskWords.review.length) {
|
||||
readMode()
|
||||
practiceMode.value = PracticeMode.Identify
|
||||
statStore.step = 2
|
||||
data.words = taskWords.review
|
||||
} else {
|
||||
if (taskWords.write.length) {
|
||||
writeMode()
|
||||
practiceMode.value = PracticeMode.Identify
|
||||
data.words = taskWords.write
|
||||
statStore.step = 4
|
||||
} else {
|
||||
@@ -141,12 +142,13 @@ function initData(initVal: TaskWords, init: boolean = false) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
readMode()
|
||||
practiceMode.value = PracticeMode.FollowWrite
|
||||
data.words = taskWords.new
|
||||
statStore.step = 0
|
||||
}
|
||||
data.index = 0
|
||||
data.wrongWords = []
|
||||
data.excludeWords = []
|
||||
allWrongWords.clear()
|
||||
statStore.startDate = Date.now()
|
||||
statStore.inputWordNumber = 0
|
||||
@@ -160,7 +162,7 @@ function initData(initVal: TaskWords, init: boolean = false) {
|
||||
}
|
||||
}
|
||||
|
||||
const word = $computed(() => {
|
||||
const word = $computed<Word>(() => {
|
||||
return data.words[data.index] ?? getDefaultWord()
|
||||
})
|
||||
const prevWord: Word = $computed(() => {
|
||||
@@ -170,19 +172,27 @@ const nextWord: Word = $computed(() => {
|
||||
return data.words?.[data.index + 1] ?? undefined
|
||||
})
|
||||
|
||||
function readMode() {
|
||||
practiceMode.value = PracticeMode.FollowWrite
|
||||
settingStore.dictation = false
|
||||
settingStore.translate = true
|
||||
}
|
||||
|
||||
function writeMode() {
|
||||
practiceMode.value = PracticeMode.Dictation
|
||||
settingStore.dictation = true
|
||||
settingStore.translate = false
|
||||
}
|
||||
watch(practiceMode, (n) => {
|
||||
switch (n) {
|
||||
case PracticeMode.Spell:
|
||||
case PracticeMode.Dictation:
|
||||
case PracticeMode.Listen:
|
||||
settingStore.dictation = true;
|
||||
settingStore.translate = false;
|
||||
break
|
||||
case PracticeMode.FollowWrite:
|
||||
settingStore.dictation = false;
|
||||
settingStore.translate = true;
|
||||
break
|
||||
case PracticeMode.Identify:
|
||||
settingStore.dictation = false;
|
||||
settingStore.translate = false;
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
function wordLoop() {
|
||||
return data.index++
|
||||
let d = Math.floor(data.index / 6) - 1
|
||||
if (data.index > 0 && data.index % 6 === (d < 0 ? 0 : d)) {
|
||||
if (practiceMode.value === PracticeMode.FollowWrite) {
|
||||
@@ -200,7 +210,6 @@ function wordLoop() {
|
||||
let toastInstance: ToastInstance = null
|
||||
|
||||
async function next(isTyping: boolean = true) {
|
||||
debugger
|
||||
if (isTyping) {
|
||||
statStore.inputWordNumber++
|
||||
}
|
||||
@@ -262,7 +271,7 @@ async function next(isTyping: boolean = true) {
|
||||
toastInstance?.close()
|
||||
toastInstance = Toast.info('输入完成后按空格键切换下一个', {duration: 10000})
|
||||
practiceMode.value = PracticeMode.Dictation
|
||||
data.words = shuffle(taskWords.new)
|
||||
data.words = shuffle(taskWords.write)
|
||||
data.index = 0
|
||||
}
|
||||
|
||||
@@ -273,7 +282,7 @@ async function next(isTyping: boolean = true) {
|
||||
toastInstance?.close()
|
||||
toastInstance = Toast.info('输入完成后按空格键切换下一个', {duration: 10000})
|
||||
practiceMode.value = PracticeMode.Listen
|
||||
data.words = shuffle(taskWords.review)
|
||||
data.words = shuffle(taskWords.write)
|
||||
data.index = 0
|
||||
}
|
||||
|
||||
@@ -300,7 +309,7 @@ async function next(isTyping: boolean = true) {
|
||||
toastInstance?.close()
|
||||
toastInstance = Toast.info('输入完成后按空格键切换下一个', {duration: 10000})
|
||||
practiceMode.value = PracticeMode.Dictation
|
||||
data.words = shuffle(taskWords.new)
|
||||
data.words = shuffle(taskWords.review)
|
||||
data.index = 0
|
||||
}
|
||||
|
||||
@@ -355,43 +364,10 @@ async function next(isTyping: boolean = true) {
|
||||
} else {
|
||||
if (statStore.step === 0) {
|
||||
wordLoop()
|
||||
} else if (statStore.step === 1) {
|
||||
if (isTypingWrongWord.value) wordLoop()
|
||||
else data.index++
|
||||
} else if (statStore.step === 2) {
|
||||
if (isTypingWrongWord.value) wordLoop()
|
||||
else data.index++
|
||||
} else if (statStore.step === 3) {
|
||||
if (isTypingWrongWord.value) wordLoop()
|
||||
else data.index++
|
||||
} else if (statStore.step === 4) {
|
||||
if (isTypingWrongWord.value) wordLoop()
|
||||
else data.index++
|
||||
} else if (statStore.step === 5) {
|
||||
if (isTypingWrongWord.value) wordLoop()
|
||||
else data.index++
|
||||
} else if (statStore.step === 6) {
|
||||
if (isTypingWrongWord.value) wordLoop()
|
||||
else data.index++
|
||||
} else if (statStore.step === 7) {
|
||||
if (isTypingWrongWord.value) wordLoop()
|
||||
else data.index++
|
||||
} else if (statStore.step === 8) {
|
||||
} else {
|
||||
if (isTypingWrongWord.value) wordLoop()
|
||||
else data.index++
|
||||
}
|
||||
// if ([0, 2].includes(statStore.step) || isTypingWrongWord.value) {
|
||||
// wordLoop()
|
||||
// } else {
|
||||
// if (settingStore.dictation && !settingStore.translate) {
|
||||
// readMode()
|
||||
// } else {
|
||||
// writeMode()
|
||||
// await sleep(100)
|
||||
// data.index++
|
||||
// }
|
||||
// // await sleep(2000)
|
||||
// }
|
||||
}
|
||||
}
|
||||
savePracticeData()
|
||||
@@ -489,12 +465,16 @@ function play() {
|
||||
|
||||
function toggleWordSimpleWrapper() {
|
||||
if (!isWordSimple(word)) {
|
||||
toggleWordSimple(word)
|
||||
//延迟一下,不知道为什么不延迟会导致当前条目不自动定位到列表中间
|
||||
setTimeout(() => next(false))
|
||||
} else {
|
||||
toggleWordSimple(word)
|
||||
}
|
||||
let rIndex = data.excludeWords.findIndex(v => v === word.word)
|
||||
if (rIndex > -1) {
|
||||
data.excludeWords.splice(rIndex, 1)
|
||||
} else {
|
||||
data.excludeWords.push(word.word)
|
||||
}
|
||||
toggleWordSimple(word)
|
||||
}
|
||||
|
||||
function toggleTranslate() {
|
||||
|
||||
@@ -3,7 +3,7 @@ import {PracticeMode, ShortcutKey, Word} from "@/types/types.ts";
|
||||
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import {usePlayBeep, usePlayCorrect, usePlayKeyboardAudio, usePlayWordAudio} from "@/hooks/sound.ts";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts";
|
||||
import {emitter, EventKey, useEvents} from "@/utils/eventBus.ts";
|
||||
import {inject, onMounted, onUnmounted, Ref, watch} from "vue";
|
||||
import SentenceHightLightWord from "@/pages/word/components/SentenceHightLightWord.vue";
|
||||
import {usePracticeStore} from "@/stores/practice.ts";
|
||||
@@ -12,6 +12,7 @@ import {_nextTick, last, sleep} from "@/utils";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import Space from "@/pages/article/components/Space.vue";
|
||||
import Toast from "@/components/base/toast/Toast.ts";
|
||||
import Tooltip from "@/components/base/Tooltip.vue";
|
||||
|
||||
interface IProps {
|
||||
word: Word,
|
||||
@@ -69,7 +70,7 @@ watch(() => props.word, reset, {deep: true})
|
||||
function reset() {
|
||||
wrong = input = ''
|
||||
wordRepeatCount = 0
|
||||
showWordResult = inputLock = false
|
||||
showWordResult = inputLock = false
|
||||
if (settingStore.wordSound) {
|
||||
if (practiceMode.value !== PracticeMode.Dictation) {
|
||||
volumeIconRef?.play(400, true)
|
||||
@@ -121,6 +122,28 @@ const right = $computed(() => {
|
||||
}
|
||||
})
|
||||
|
||||
function know(e) {
|
||||
if (practiceMode.value === PracticeMode.Identify) {
|
||||
if (!showWordResult) {
|
||||
inputLock = showWordResult = true
|
||||
input = props.word.word
|
||||
return
|
||||
}
|
||||
}
|
||||
onTyping(e)
|
||||
}
|
||||
|
||||
function unknown(e) {
|
||||
if (practiceMode.value === PracticeMode.Identify) {
|
||||
if (!showWordResult) {
|
||||
showWordResult = true
|
||||
emit('wrong')
|
||||
return
|
||||
}
|
||||
}
|
||||
onTyping(e)
|
||||
}
|
||||
|
||||
async function onTyping(e: KeyboardEvent) {
|
||||
debugger
|
||||
let word = props.word.word
|
||||
@@ -131,10 +154,10 @@ async function onTyping(e: KeyboardEvent) {
|
||||
emit('complete')
|
||||
} else {
|
||||
//当显示单词时,提示用户正确按键
|
||||
if (showFullWord) {
|
||||
if (showWordResult) {
|
||||
pressNumber++
|
||||
if (pressNumber >= 3) {
|
||||
Toast.info(right ? '请按空格键切换' : '请按删除键重新输入')
|
||||
Toast.info(right ? '请按空格键切换' : '请按删除键重新输入', {duration: 2000})
|
||||
pressNumber = 0
|
||||
}
|
||||
}
|
||||
@@ -177,7 +200,7 @@ async function onTyping(e: KeyboardEvent) {
|
||||
} else {
|
||||
let right = false
|
||||
if (settingStore.ignoreCase) {
|
||||
right = letter.toLowerCase() === props.word.word[input.length].toLowerCase()
|
||||
right = letter.toLowerCase() === word[input.length].toLowerCase()
|
||||
} else {
|
||||
right = letter === props.word.word[input.length]
|
||||
}
|
||||
@@ -196,21 +219,26 @@ async function onTyping(e: KeyboardEvent) {
|
||||
}
|
||||
// 更新当前单词信息
|
||||
updateCurrentWordInfo();
|
||||
if (input.toLowerCase() === props.word.word.toLowerCase()) {
|
||||
//不需要把inputLock设为false,输入完成不能再输入了,只能删除,删除会打开锁
|
||||
if (input.toLowerCase() === word.toLowerCase()) {
|
||||
playCorrect()
|
||||
//不需要把inputLock设为false,输入完成不能再输入了,只能删除,删除会打开锁
|
||||
if (settingStore.autoNextWord) {
|
||||
if (settingStore.repeatCount == 100) {
|
||||
if (settingStore.repeatCustomCount <= wordRepeatCount + 1) {
|
||||
setTimeout(() => emit('complete'), settingStore.waitTimeForChangeWord)
|
||||
if ([PracticeMode.Listen, PracticeMode.Identify].includes(practiceMode.value) && !showWordResult) {
|
||||
showWordResult = true
|
||||
}
|
||||
if ([PracticeMode.Free, PracticeMode.FollowWrite, PracticeMode.Spell].includes(practiceMode.value)) {
|
||||
if (settingStore.autoNextWord) {
|
||||
if (settingStore.repeatCount == 100) {
|
||||
if (settingStore.repeatCustomCount <= wordRepeatCount + 1) {
|
||||
setTimeout(() => emit('complete'), settingStore.waitTimeForChangeWord)
|
||||
} else {
|
||||
repeat()
|
||||
}
|
||||
} else {
|
||||
repeat()
|
||||
}
|
||||
} else {
|
||||
if (settingStore.repeatCount <= wordRepeatCount + 1) {
|
||||
setTimeout(() => emit('complete'), settingStore.waitTimeForChangeWord)
|
||||
} else {
|
||||
repeat()
|
||||
if (settingStore.repeatCount <= wordRepeatCount + 1) {
|
||||
setTimeout(() => emit('complete'), settingStore.waitTimeForChangeWord)
|
||||
} else {
|
||||
repeat()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,7 +252,6 @@ function del() {
|
||||
playKeyboardAudio()
|
||||
inputLock = false
|
||||
if (showWordResult) {
|
||||
practiceMode.value = PracticeMode.Dictation
|
||||
input = ''
|
||||
showWordResult = false
|
||||
} else {
|
||||
@@ -331,18 +358,18 @@ function checkCursorPosition() {
|
||||
},)
|
||||
}
|
||||
|
||||
const word = $computed(() => {
|
||||
return {...props.word, ...{input: 'abc'}}
|
||||
})
|
||||
|
||||
useEvents([
|
||||
[ShortcutKey.KnowWord, know],
|
||||
[ShortcutKey.UnknownWord, unknown],
|
||||
])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="typing-word" ref="typingWordRef" v-if="props.word.word.length">
|
||||
<div class="typing-word" ref="typingWordRef" v-if="word.word.length">
|
||||
<div class="flex flex-col items-center">
|
||||
<div class="flex gap-1 mt-26">
|
||||
<div class="phonetic"
|
||||
:class="((settingStore.dictation || [PracticeMode.Spell,PracticeMode.Listen,PracticeMode.Dictation].includes(practiceMode)) && !showFullWord && !showWordResult) && 'word-shadow'"
|
||||
:class="!(!settingStore.dictation || showFullWord || showWordResult) && 'word-shadow'"
|
||||
v-if="settingStore.soundType === 'us' && word.phonetic0">[{{ word.phonetic0 }}]
|
||||
</div>
|
||||
<div class="phonetic"
|
||||
@@ -350,8 +377,8 @@ const word = $computed(() => {
|
||||
v-if="settingStore.soundType === 'uk' && word.phonetic1">[{{ word.phonetic1 }}]
|
||||
</div>
|
||||
<VolumeIcon
|
||||
:title="`发音(${settingStore.shortcutKeyMap[ShortcutKey.PlayWordPronunciation]})`"
|
||||
ref="volumeIconRef" :simple="true" :cb="() => playWordAudio(word.word)"/>
|
||||
:title="`发音(${settingStore.shortcutKeyMap[ShortcutKey.PlayWordPronunciation]})`"
|
||||
ref="volumeIconRef" :simple="true" :cb="() => playWordAudio(word.word)"/>
|
||||
</div>
|
||||
|
||||
<div class="word my-1"
|
||||
@@ -363,12 +390,12 @@ const word = $computed(() => {
|
||||
<div v-if="practiceMode === PracticeMode.Dictation">
|
||||
<div class="letter text-align-center w-full inline-block"
|
||||
v-opacity="showWordResult || showFullWord">
|
||||
{{ props.word.word }}
|
||||
{{ word.word }}
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 w-120 dictation"
|
||||
:style="{minHeight: settingStore.fontSize.wordForeignFontSize +'px'}"
|
||||
:class="showWordResult ? (right ? 'right' : 'wrong') : ''">
|
||||
class="mt-2 w-120 dictation"
|
||||
:style="{minHeight: settingStore.fontSize.wordForeignFontSize +'px'}"
|
||||
:class="showWordResult ? (right ? 'right' : 'wrong') : ''">
|
||||
<template v-for="i in input">
|
||||
<span class="l" v-if="i !== ' '">{{ i }}</span>
|
||||
<Space class="l" v-else :is-wrong="showWordResult ? (!right) : false" :is-wait="!showWordResult"/>
|
||||
@@ -396,13 +423,19 @@ const word = $computed(() => {
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div class="mt-4" v-if="practiceMode === PracticeMode.Identify && !showWordResult">
|
||||
<BaseButton size="large" @click="showWordResult = true;emit('wrong')">不认识</BaseButton>
|
||||
<BaseButton size="large" @click="emit('complete')">我认识</BaseButton>
|
||||
<div class="mt-4 flex gap-4" v-if="practiceMode === PracticeMode.Identify && !showWordResult">
|
||||
<BaseButton
|
||||
:keyboard="`快捷键(${settingStore.shortcutKeyMap[ShortcutKey.KnowWord]})`"
|
||||
size="large" @click="know">我认识
|
||||
</BaseButton>
|
||||
<BaseButton
|
||||
:keyboard="`快捷键(${settingStore.shortcutKeyMap[ShortcutKey.UnknownWord]})`"
|
||||
size="large" @click="unknown">不认识
|
||||
</BaseButton>
|
||||
</div>
|
||||
|
||||
<div class="translate anim flex flex-col gap-2 my-3"
|
||||
v-opacity="(settingStore.translate && ![PracticeMode.Listen,PracticeMode.Identify].includes(practiceMode)) || showWordResult || showFullWord"
|
||||
<div class="translate flex flex-col gap-2 my-3"
|
||||
v-opacity="settingStore.translate || ![PracticeMode.Listen,PracticeMode.Identify].includes(practiceMode) || showWordResult || showFullWord"
|
||||
:style="{
|
||||
fontSize: settingStore.fontSize.wordTranslateFontSize +'px',
|
||||
}"
|
||||
@@ -410,8 +443,8 @@ const word = $computed(() => {
|
||||
<div class="flex" v-for="(v,i) in word.trans">
|
||||
<div class="shrink-0" :class="v.pos ? 'w-12 en-article-family' : '-ml-3'">{{ v.pos }}</div>
|
||||
<span
|
||||
v-if="(settingStore.dictation || [PracticeMode.Spell,PracticeMode.Listen].includes(practiceMode)) && !showFullWord"
|
||||
v-html="hideWordInTranslation(v.cn, word.word)"></span>
|
||||
v-if="([PracticeMode.Listen,PracticeMode.Identify].includes(practiceMode) || settingStore.dictation) && !(showWordResult || showFullWord)"
|
||||
v-html="hideWordInTranslation(v.cn, word.word)"></span>
|
||||
<span v-else>{{ v.cn }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -423,26 +456,27 @@ const word = $computed(() => {
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="sentence" v-for="item in word.sentences">
|
||||
<SentenceHightLightWord class="text-xl" :text="item.c" :word="word.word"
|
||||
:dictation="((settingStore.dictation || [PracticeMode.Spell,PracticeMode.Listen].includes(practiceMode)) && !showFullWord)"/>
|
||||
:dictation="!(!settingStore.dictation || showFullWord || showWordResult)"/>
|
||||
<div class="text-base anim"
|
||||
v-opacity="(settingStore.translate && ![PracticeMode.Listen].includes(practiceMode)) || showFullWord">
|
||||
v-opacity="settingStore.translate || showFullWord || showWordResult">
|
||||
{{ item.cn }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line-white my-2 mb-5 anim" v-opacity="settingStore.translate || showFullWord"></div>
|
||||
<div class="line-white my-2 mb-5 anim"
|
||||
v-opacity="settingStore.translate || showFullWord || showWordResult"></div>
|
||||
</template>
|
||||
|
||||
<div class="anim"
|
||||
v-opacity="(settingStore.translate && !(settingStore.dictation || [PracticeMode.Spell].includes(practiceMode))) || showFullWord ">
|
||||
v-opacity="settingStore.translate || showFullWord || showWordResult">
|
||||
<template v-if="word?.phrases?.length">
|
||||
<div class="flex">
|
||||
<div class="label">短语</div>
|
||||
<div class="flex flex-col">
|
||||
<div class="flex items-center gap-4" v-for="item in word.phrases">
|
||||
<SentenceHightLightWord class="en" :text="item.c" :word="word.word"
|
||||
:dictation="((settingStore.dictation || [PracticeMode.Spell,PracticeMode.Listen].includes(practiceMode)) && !showFullWord)"/>
|
||||
<div class="cn anim" v-opacity="settingStore.translate">{{ item.cn }}</div>
|
||||
:dictation="!(!settingStore.dictation || showFullWord || showWordResult)"/>
|
||||
<div class="cn anim" v-opacity="settingStore.translate || showFullWord || showWordResult">{{ item.cn }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -510,7 +544,7 @@ const word = $computed(() => {
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dictation {
|
||||
border-bottom: 1px solid black;
|
||||
border-bottom: 2px solid black;
|
||||
}
|
||||
|
||||
.typing-word {
|
||||
|
||||
@@ -117,7 +117,9 @@ export enum ShortcutKey {
|
||||
ToggleConciseMode = 'ToggleConciseMode',
|
||||
TogglePanel = 'TogglePanel',
|
||||
RandomWrite = 'RandomWrite',
|
||||
NextRandomWrite = 'NextRandomWrite'
|
||||
NextRandomWrite = 'NextRandomWrite',
|
||||
KnowWord = 'KnowWord',
|
||||
UnknownWord = 'UnknownWord',
|
||||
}
|
||||
|
||||
export const DefaultShortcutKeyMap = {
|
||||
@@ -139,6 +141,8 @@ export const DefaultShortcutKeyMap = {
|
||||
[ShortcutKey.TogglePanel]: 'Ctrl+L',
|
||||
[ShortcutKey.RandomWrite]: 'Ctrl+R',
|
||||
[ShortcutKey.NextRandomWrite]: 'Ctrl+Shift+R',
|
||||
[ShortcutKey.KnowWord]: '1',
|
||||
[ShortcutKey.UnknownWord]: '2',
|
||||
}
|
||||
|
||||
export enum TranslateEngine {
|
||||
@@ -189,6 +193,7 @@ export interface PracticeData {
|
||||
index: number,
|
||||
words: any[],
|
||||
wrongWords: any[],
|
||||
excludeWords: any[],
|
||||
}
|
||||
|
||||
export interface TaskWords {
|
||||
@@ -211,7 +216,6 @@ export enum PracticeArticleWordType {
|
||||
}
|
||||
|
||||
export enum PracticeMode {
|
||||
Free,
|
||||
FollowWrite,//跟写
|
||||
Spell,
|
||||
Identify,
|
||||
|
||||
Reference in New Issue
Block a user