feat:save
This commit is contained in:
@@ -25,7 +25,7 @@ export function useWordOptions() {
|
||||
}
|
||||
|
||||
function isWordSimple(val: Word) {
|
||||
return !!store.simple.words.find(v => v.word.toLowerCase() === val.word.toLowerCase())
|
||||
return !!store.known.words.find(v => v.word.toLowerCase() === val.word.toLowerCase())
|
||||
}
|
||||
|
||||
function toggleWordSimple(val: Word) {
|
||||
@@ -110,7 +110,7 @@ export function getCurrentStudyWord() {
|
||||
// console.time()
|
||||
const store = useBaseStore()
|
||||
let data = {new: [], review: [], write: []}
|
||||
let dict = store.currentStudyWordDict;
|
||||
let dict = store.sdict;
|
||||
if (dict.words?.length) {
|
||||
for (let i = dict.lastLearnIndex; i < dict.words.length; i++) {
|
||||
if (data.new.length >= dict.perDayStudyNumber) break
|
||||
|
||||
@@ -92,11 +92,9 @@ export function usePlayWordAudio() {
|
||||
const audio = $ref(new Audio())
|
||||
|
||||
function playAudio(word: string) {
|
||||
let url = ''
|
||||
let url = `${PronunciationApi}${word}&type=2`
|
||||
if (settingStore.wordSoundType === 'uk') {
|
||||
url = `${PronunciationApi}${word}&type=1`
|
||||
} else if (settingStore.wordSoundType === 'us') {
|
||||
url = `${PronunciationApi}${word}&type=2`
|
||||
}
|
||||
audio.src = url
|
||||
audio.volume = settingStore.wordSoundVolume / 100
|
||||
|
||||
@@ -12,8 +12,6 @@ import {useSettingStore} from "@/stores/setting.ts";
|
||||
import {syncMyDictList} from "@/hooks/dict.ts";
|
||||
|
||||
const store = useBaseStore()
|
||||
const runtimeStore = useRuntimeStore()
|
||||
const settingStore = useSettingStore()
|
||||
|
||||
let wordData = $ref({
|
||||
words: [],
|
||||
@@ -21,11 +19,7 @@ let wordData = $ref({
|
||||
})
|
||||
|
||||
function getCurrentPractice() {
|
||||
if (store.chapter.length) {
|
||||
wordData.index = 0
|
||||
wordData.words = cloneDeep(store.chapter)
|
||||
emitter.emit(EventKey.resetWord)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function sort(list: Word[]) {
|
||||
@@ -66,4 +60,4 @@ defineExpose({getCurrentPractice})
|
||||
flex: 1;
|
||||
display: flex;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -82,7 +82,7 @@ function changeCollect() {
|
||||
<header>
|
||||
<div class="tabs">
|
||||
<div class="tab" :class="tabIndex === 0 && 'active'" @click="tabIndex = 0">当前</div>
|
||||
<div class="tab" :class="tabIndex === 1 && 'active'" @click="tabIndex = 1">{{ store.collect.name }}</div>
|
||||
<div class="tab" :class="tabIndex === 1 && 'active'" @click="tabIndex = 1">{{ store.collectWord.name }}</div>
|
||||
<div class="tab" :class="tabIndex === 2 && 'active'" @click="tabIndex = 2">{{ store.known.name }}</div>
|
||||
<div class="tab" :class="tabIndex === 3 && 'active'" @click="tabIndex = 3">{{ store.wrong.name }}</div>
|
||||
</div>
|
||||
|
||||
@@ -18,6 +18,7 @@ import {useRoute, useRouter} from "vue-router";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import EditBook from "@/pages/pc/article/components/EditBook.vue";
|
||||
import {_getDictDataByUrl, _nextTick} from "@/utils";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts";
|
||||
|
||||
const runtimeStore = useRuntimeStore()
|
||||
const base = useBaseStore()
|
||||
@@ -292,18 +293,26 @@ function formClose() {
|
||||
}
|
||||
|
||||
async function addMyStudyList() {
|
||||
|
||||
//把其他的词典的单词数据都删掉,全保存在内存里太卡了
|
||||
base.word.bookList.slice(3).map(v => {
|
||||
if (!v.custom) {
|
||||
v.words = []
|
||||
}
|
||||
})
|
||||
let rIndex = base.word.bookList.findIndex(v => v.name === runtimeStore.editDict.name)
|
||||
if (runtimeStore.editDict.words.length < runtimeStore.editDict.perDayStudyNumber) {
|
||||
runtimeStore.editDict.perDayStudyNumber = runtimeStore.editDict.words.length
|
||||
}
|
||||
if (rIndex > -1) {
|
||||
base.word.studyIndex = rIndex
|
||||
base.word.bookList[base.word.studyIndex].words = runtimeStore.editDict.words
|
||||
base.word.bookList[base.word.studyIndex].perDayStudyNumber = runtimeStore.editDict.perDayStudyNumber
|
||||
} else {
|
||||
base.word.bookList.push(runtimeStore.editDict)
|
||||
base.word.studyIndex = base.word.bookList.length - 1
|
||||
}
|
||||
|
||||
router.back()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import Dialog from "@/pages/pc/components/dialog/Dialog.vue";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import Ring from "@/pages/pc/components/Ring.vue";
|
||||
import Tooltip from "@/pages/pc/components/Tooltip.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import {ShortcutKey} from "@/types.ts";
|
||||
import {emitter, EventKey, useEvent, useEvents} from "@/utils/eventBus.ts";
|
||||
@@ -23,7 +21,7 @@ useEvent(EventKey.openStatModal, () => {
|
||||
total: statStore.total,
|
||||
wrong: statStore.wrong,
|
||||
}
|
||||
store.sdict.lastLearnIndex = store.sdict.lastLearnIndex + store.sdict.perDayStudyNumber
|
||||
store.sdict.lastLearnIndex = store.sdict.lastLearnIndex + statStore.newWordNumber
|
||||
store.sdict.statistics.push(data as any)
|
||||
store.sdict.statistics.sort((a, b) => a.startDate - b.startDate)
|
||||
|
||||
@@ -46,6 +44,7 @@ function options(emitType: 'write' | 'repeat' | 'next') {
|
||||
emitter.emit(EventKey[emitType])
|
||||
}
|
||||
|
||||
//todo
|
||||
const isEnd = $computed(() => {
|
||||
return false
|
||||
})
|
||||
@@ -79,7 +78,9 @@ const isEnd = $computed(() => {
|
||||
</div>
|
||||
|
||||
<div class="text-xl text-center flex flex-col justify-around">
|
||||
<div>非常棒! 坚持了 <span class="color-green font-bold text-2xl">{{ dayjs().diff(statStore.startDate, 'm') }}</span>
|
||||
<div>非常棒! 坚持了 <span class="color-green font-bold text-2xl">{{
|
||||
dayjs().diff(statStore.startDate, 'm')
|
||||
}}</span>
|
||||
分钟
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,12 +8,10 @@ import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import Dialog from "@/pages/pc/components/dialog/Dialog.vue";
|
||||
import {_getAccomplishDate, _getAccomplishDays, _getDictDataByUrl, useNav} from "@/utils";
|
||||
import BasePage from "@/pages/pc/components/BasePage.vue";
|
||||
import {Dict, DictResource, getDefaultDict} from "@/types.ts";
|
||||
import {onMounted} from "vue";
|
||||
import {DictResource, getDefaultDict} from "@/types.ts";
|
||||
import {onMounted, watch} from "vue";
|
||||
import {getCurrentStudyWord} from "@/hooks/dict.ts";
|
||||
import {EventKey, useEvent} from "@/utils/eventBus.ts";
|
||||
import DictListPanel from "@/pages/pc/components/DictListPanel.vue";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import Book from "@/pages/pc/components/Book.vue";
|
||||
import PopConfirm from "@/pages/pc/components/PopConfirm.vue";
|
||||
@@ -34,17 +32,30 @@ let currentStudy = $ref({
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
if (!currentStudy.new.length) {
|
||||
currentStudy = getCurrentStudyWord()
|
||||
}
|
||||
init()
|
||||
})
|
||||
|
||||
useEvent(EventKey.changeDict, () => {
|
||||
currentStudy = getCurrentStudyWord()
|
||||
watch(() => store.load, () => {
|
||||
init()
|
||||
})
|
||||
|
||||
async function init() {
|
||||
if (store.word.studyIndex >= 3) {
|
||||
if (!store.sdict.custom && !store.sdict.words.length) {
|
||||
store.word.bookList[store.word.studyIndex] = await _getDictDataByUrl(store.sdict)
|
||||
}
|
||||
}
|
||||
console.log(store.sdict)
|
||||
if (!currentStudy.new.length && store.sdict.words.length) {
|
||||
currentStudy = getCurrentStudyWord()
|
||||
}
|
||||
}
|
||||
|
||||
function study() {
|
||||
if (store.sdict.id) {
|
||||
if (!store.sdict.words.length) {
|
||||
return ElMessage.warning('没有单词可学习!')
|
||||
}
|
||||
nav('study-word', {}, currentStudy)
|
||||
} else {
|
||||
ElMessage.warning('请先选择一本词典')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import {inject, onMounted, onUnmounted, provide} from "vue"
|
||||
import {inject, onMounted, onUnmounted} from "vue"
|
||||
import {usePracticeStore} from "@/stores/practice.ts";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import {ShortcutKey, StudyData} from "@/types.ts";
|
||||
@@ -10,7 +10,6 @@ import IconWrapper from "@/pages/pc/components/IconWrapper.vue";
|
||||
import Tooltip from "@/pages/pc/components/Tooltip.vue";
|
||||
import TranslateSetting from "@/pages/pc/components/toolbar/TranslateSetting.vue";
|
||||
import RepeatSetting from "@/pages/pc/components/toolbar/RepeatSetting.vue";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts";
|
||||
|
||||
const statisticsStore = usePracticeStore()
|
||||
const settingStore = useSettingStore()
|
||||
|
||||
@@ -77,33 +77,30 @@ function repeat() {
|
||||
|
||||
async function onTyping(e: KeyboardEvent) {
|
||||
if (inputLock) return
|
||||
console.log('onTyping')
|
||||
inputLock = true
|
||||
let letter = e.key
|
||||
let isTypingRight = false
|
||||
let isWordRight = false
|
||||
if (settingStore.ignoreCase) {
|
||||
isTypingRight = letter.toLowerCase() === props.word.word[input.length].toLowerCase()
|
||||
isWordRight = (input + letter).toLowerCase() === props.word.word.toLowerCase()
|
||||
} else {
|
||||
isTypingRight = letter === props.word.word[input.length]
|
||||
isWordRight = (input + letter) === props.word.word
|
||||
}
|
||||
if (isTypingRight) {
|
||||
input += letter
|
||||
wrong = ''
|
||||
playKeyboardAudio()
|
||||
} else {
|
||||
emit('wrong')
|
||||
wrong = letter
|
||||
playKeyboardAudio()
|
||||
playBeep()
|
||||
volumeIconRef?.play()
|
||||
setTimeout(() => {
|
||||
wrong = ''
|
||||
}, 500)
|
||||
emit('wrong')
|
||||
}
|
||||
|
||||
if (isWordRight) {
|
||||
if (input.toLowerCase() === props.word.word.toLowerCase()) {
|
||||
playCorrect()
|
||||
if (settingStore.repeatCount == 100) {
|
||||
if (settingStore.repeatCustomCount <= wordRepeatCount + 1) {
|
||||
@@ -212,13 +209,15 @@ let tab = $ref(2)
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="line-white my-4"></div>
|
||||
<div class="tabs">
|
||||
<div @click="tab = 0" class="tab" :class="tab === 0 && 'active'">短语</div>
|
||||
<div @click="tab = 1" class="tab" :class="tab === 1 && 'active'">同近义词</div>
|
||||
<div @click="tab = 2" class="tab" :class="tab === 2 && 'active'">同根词</div>
|
||||
<div @click="tab = 3" class="tab" :class="tab === 3 && 'active'">词源</div>
|
||||
</div>
|
||||
<template v-if="word.phrases.length || word.synos.length || word.relWords.root || word.etymology.length">
|
||||
<div class="line-white my-4"></div>
|
||||
<div class="tabs">
|
||||
<div @click="tab = 0" class="tab" :class="tab === 0 && 'active'">短语</div>
|
||||
<div @click="tab = 1" class="tab" :class="tab === 1 && 'active'">同近义词</div>
|
||||
<div @click="tab = 2" class="tab" :class="tab === 2 && 'active'">同根词</div>
|
||||
<div @click="tab = 3" class="tab" :class="tab === 3 && 'active'">词源</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-if="tab === 0">
|
||||
<div class="my-2" v-for="item in word.phrases">
|
||||
<SentenceHightLightWord class="text-lg" :text="item.c" :word="word.word" :high-light="false"
|
||||
|
||||
@@ -51,7 +51,7 @@ const {
|
||||
toggleWordSimple
|
||||
} = useWordOptions()
|
||||
|
||||
let allWrongWords = []
|
||||
let allWrongWords = new Set()
|
||||
|
||||
let data = $ref<StudyData>({
|
||||
index: 0,
|
||||
@@ -65,7 +65,7 @@ watch(() => props.data, () => {
|
||||
data.words = props.data.new
|
||||
data.index = 0
|
||||
data.wrongWords = []
|
||||
allWrongWords = []
|
||||
allWrongWords = new Set()
|
||||
|
||||
statStore.step = 0
|
||||
statStore.startDate = Date.now()
|
||||
@@ -127,21 +127,28 @@ function next(isTyping: boolean = true) {
|
||||
} else {
|
||||
data.index++
|
||||
isTyping && statStore.inputWordNumber++
|
||||
// console.log('这个词完了')
|
||||
console.log('这个词完了')
|
||||
}
|
||||
}
|
||||
|
||||
function wordWrong() {
|
||||
if (!store.wrong.words.find((v: Word) => v.word.toLowerCase() === word.word.toLowerCase())) {
|
||||
store.wrong.words.push(word)
|
||||
}
|
||||
if (!data.wrongWords.find((v: Word) => v.word.toLowerCase() === word.word.toLowerCase())) {
|
||||
data.wrongWords.push(word)
|
||||
}
|
||||
if (!allWrongWords.find((v: Word) => v.word.toLowerCase() === word.word.toLowerCase())) {
|
||||
allWrongWords.push(word)
|
||||
function onTypeWrong() {
|
||||
let temp = word.word.toLowerCase()
|
||||
if (!allWrongWords.has(word.word.toLowerCase())) {
|
||||
allWrongWords.add(word.word.toLowerCase())
|
||||
statStore.wrong++
|
||||
}
|
||||
//todo 后续要测试有非常的多的错词时,这会还卡不卡
|
||||
setTimeout(() => {
|
||||
requestAnimationFrame(() => {
|
||||
if (!store.wrong.words.find((v: Word) => v.word.toLowerCase() === temp)) {
|
||||
store.wrong.words.push(word)
|
||||
store.wrong.length = store.wrong.words.length
|
||||
}
|
||||
if (!data.wrongWords.find((v: Word) => v.word.toLowerCase() === temp)) {
|
||||
data.wrongWords.push(word)
|
||||
}
|
||||
})
|
||||
}, 500)
|
||||
}
|
||||
|
||||
function onKeyUp(e: KeyboardEvent) {
|
||||
@@ -235,7 +242,7 @@ useEvents([
|
||||
v-loading="!store.load"
|
||||
ref="typingRef"
|
||||
:word="word"
|
||||
@wrong="wordWrong"
|
||||
@wrong="onTypeWrong"
|
||||
@complete="next"
|
||||
/>
|
||||
<Footer
|
||||
|
||||
@@ -91,10 +91,10 @@ export const useBaseStore = defineStore('base', {
|
||||
return this.word.bookList[0]
|
||||
},
|
||||
collectWord(): Dict {
|
||||
return this.word.bookList[1]
|
||||
return this.word.bookList[0]
|
||||
},
|
||||
collectArticle(): Dict {
|
||||
return this.word.bookList[2]
|
||||
return this.article.bookList[0]
|
||||
},
|
||||
simple(): Dict {
|
||||
return this.word.bookList[2]
|
||||
@@ -132,9 +132,6 @@ export const useBaseStore = defineStore('base', {
|
||||
sdict(): Dict {
|
||||
return this.currentStudyWordDict
|
||||
},
|
||||
sword() {
|
||||
return this.currentStudy.word
|
||||
},
|
||||
currentStudyProgress(): number {
|
||||
if (!this.sdict.words?.length) return 0
|
||||
return _getStudyProgress(this.sdict.lastLearnIndex, this.sdict.words?.length)
|
||||
@@ -142,9 +139,6 @@ export const useBaseStore = defineStore('base', {
|
||||
currentArticleCollectDict(): Dict {
|
||||
return this.article.bookList[0]
|
||||
},
|
||||
chapter(state: BaseState): Word[] {
|
||||
return this.currentDict.chapterWords[this.currentDict.chapterIndex] ?? []
|
||||
},
|
||||
currentBook(): Dict {
|
||||
return this.article.bookList[this.article.studyIndex] ?? {}
|
||||
},
|
||||
@@ -173,14 +167,6 @@ export const useBaseStore = defineStore('base', {
|
||||
console.error('读取本地dict数据失败', e)
|
||||
}
|
||||
|
||||
if (this.word.studyIndex >= 3) {
|
||||
// await _checkDictWords(this.currentStudyWordDict)
|
||||
let current: Dict = this.word.bookList[this.word.studyIndex]
|
||||
if (!current.custom) {
|
||||
this.word.bookList[this.word.studyIndex] = await _getDictDataByUrl(current)
|
||||
}
|
||||
console.log('this.current', current)
|
||||
}
|
||||
if (this.article.studyIndex >= 1) {
|
||||
let current = this.article.bookList[this.article.studyIndex]
|
||||
let dictResourceUrl = `./dicts/${current.language}/${current.type}/${current.translateLanguage}/${current.url}`;
|
||||
@@ -197,91 +183,7 @@ export const useBaseStore = defineStore('base', {
|
||||
resolve(true)
|
||||
})
|
||||
},
|
||||
async changeDict(dict: Dict, practiceType?: DictType, chapterIndex?: number, wordIndex?: number) {
|
||||
},
|
||||
async changeWordDict(dict: Dict) {
|
||||
this.wordDictList.map((v) => v.words = [])
|
||||
// await checkDictHasTranslate(newDict)
|
||||
let rIndex = this.wordDictList.findIndex((v: Dict) => v.id === dict.id)
|
||||
if (rIndex > -1) {
|
||||
this.wordDictList[rIndex] = Object.assign(dict, this.wordDictList[rIndex])
|
||||
this.currentStudy.word.dictIndex = rIndex
|
||||
} else {
|
||||
this.wordDictList.push(getDefaultDict(dict))
|
||||
this.currentStudy.word.dictIndex = this.wordDictList.length - 1
|
||||
}
|
||||
// await _checkDictWords(this.currentStudyWordDict)
|
||||
|
||||
console.log(' store.currentStudyWordDict', this.currentStudyWordDict)
|
||||
emitter.emit(EventKey.changeDict)
|
||||
},
|
||||
async changeArticleDict(dict: Dict) {
|
||||
//TODO 保存统计
|
||||
// this.saveStatistics()
|
||||
console.log('changeDict', cloneDeep(dict),)
|
||||
if ([DictType.collect,
|
||||
DictType.simple,
|
||||
DictType.wrong].includes(dict.type)) {
|
||||
} else {
|
||||
//TODO 需要和其他需要下载的地方统一
|
||||
let url = `./dicts/${dict.language}/${dict.type}/${dict.translateLanguage}/${dict.url}`;
|
||||
if (dict.type === DictType.article) {
|
||||
if (!dict.articles.length) {
|
||||
let r = await fetch(url)
|
||||
let v = await r.json()
|
||||
v.map(s => {
|
||||
s.id = nanoid(6)
|
||||
})
|
||||
dict.articles = cloneDeep(v)
|
||||
} else {
|
||||
dict.length = dict.articles.length
|
||||
}
|
||||
} else {
|
||||
//如果不是自定义词典,并且有url地址才去下载
|
||||
if (!dict.custom && dict.url) {
|
||||
if (!dict.originWords.length) {
|
||||
let v = await getDictFile(url)
|
||||
v.map(s => {
|
||||
s.id = nanoid(6)
|
||||
})
|
||||
dict.originWords = cloneDeep(v)
|
||||
if (dict.sort === Sort.normal) {
|
||||
dict.words = cloneDeep(dict.originWords)
|
||||
} else if (dict.sort === Sort.random) {
|
||||
dict.words = shuffle(dict.originWords)
|
||||
} else {
|
||||
dict.words = reverse(dict.originWords)
|
||||
}
|
||||
dict.words.map(v => v.checked = false)
|
||||
dict.length = dict.words.length
|
||||
} else {
|
||||
dict.length = dict.words.length
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// await checkDictHasTranslate(dict)
|
||||
let rIndex = this.myDictList.findIndex((v: Dict) => v.id === dict.id)
|
||||
if (rIndex > -1) {
|
||||
this.myDictList[rIndex] = dict
|
||||
this.current.index = rIndex
|
||||
} else {
|
||||
this.myDictList.push(cloneDeep(dict))
|
||||
this.current.index = this.myDictList.length - 1
|
||||
}
|
||||
|
||||
emitter.emit(EventKey.changeDict)
|
||||
},
|
||||
delWordDict(dict: Dict) {
|
||||
let oldId = this.currentStudyWordDict.id;
|
||||
let rIndex = this.wordDictList.findIndex((v: Dict) => v.id === dict.id)
|
||||
if (rIndex > -1) {
|
||||
this.wordDictList.splice(rIndex, 1)
|
||||
}
|
||||
rIndex = this.wordDictList.findIndex((v: Dict) => v.id === oldId)
|
||||
if (rIndex > -1) {
|
||||
this.currentStudy.word.dictIndex = rIndex
|
||||
}
|
||||
async changeDict() {
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user