This commit is contained in:
zyronon
2024-05-29 02:43:27 +08:00
parent 137037f2ec
commit f2faad0c64
20 changed files with 5237 additions and 4416 deletions

View File

@@ -5,15 +5,13 @@
"type": "module",
"scripts": {
"dev": "vite",
"test": "vite",
"build": "vite build",
"build-tsc": "vue-tsc && vite build",
"report": "vite build",
"preview": "vite preview",
"commit": "git-cz",
"prepare": "husky install",
"start": "vite",
"test": "",
"deploy": "push-dir --dir=dist --branch=gh-pages --cleanup",
"i18n:write": "gulp i18nwrite"
},
"dependencies": {
@@ -54,7 +52,6 @@
"esm": "^3.2.25",
"gulp": "^4.0.2",
"husky": "^8.0.3",
"push-dir": "^0.4.1",
"rollup-plugin-visualizer": "^5.9.2",
"sass": "^1.64.2",
"tslib": "^2.6.2",
@@ -65,7 +62,7 @@
"unplugin-vue-components": "^0.25.2",
"unplugin-vue-define-options": "^1.4.1",
"vite": "^5.2.11",
"vue-tsc": "^1.8.5",
"vue-tsc": "^2.0.19",
"xlsx": "^0.18.5"
},
"config": {

9147
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -63,7 +63,7 @@ function nextChapter() {
}
let stat = cloneDeep(DefaultDisplayStatistics)
const practiceStore = usePracticeStore()
const statisticsStore = usePracticeStore()
function next(isTyping: boolean = true) {
if (data.index === data.words.length - 1) {
@@ -72,12 +72,12 @@ function next(isTyping: boolean = true) {
if (stat.total === -1) {
let now = Date.now()
stat = {
startDate: practiceStore.startDate,
startDate: statisticsStore.startDate,
endDate: now,
spend: now - practiceStore.startDate,
spend: now - statisticsStore.startDate,
total: props.words.length,
correctRate: -1,
inputWordNumber: practiceStore.inputWordNumber,
inputWordNumber: statisticsStore.inputWordNumber,
wrongWordNumber: data.wrongWords.length,
wrongWords: data.wrongWords,
}
@@ -88,15 +88,14 @@ function next(isTyping: boolean = true) {
console.log('当前背完了,但还有错词')
data.words = cloneDeep(data.wrongWords)
practiceStore.total = data.words.length
practiceStore.index = data.index = 0
practiceStore.inputWordNumber = 0
practiceStore.wrongWordNumber = 0
practiceStore.repeatNumber++
statisticsStore.total = data.words.length
statisticsStore.index = data.index = 0
statisticsStore.inputWordNumber = 0
statisticsStore.wrongWordNumber = 0
data.wrongWords = []
} else {
console.log('这章节完了')
isTyping && practiceStore.inputWordNumber++
isTyping && statisticsStore.inputWordNumber++
let now = Date.now()
stat.endDate = now

View File

@@ -18,21 +18,21 @@ defineOptions({
name: 'PracticeWord'
})
const practiceStore = usePracticeStore()
const statisticsStore = usePracticeStore()
const store = useBaseStore()
const settingStore = useSettingStore()
const runtimeStore = useRuntimeStore()
const {toggleTheme} = useTheme()
const practiceRef: any = $ref()
watch(practiceStore, () => {
if (practiceStore.inputWordNumber < 1) {
return practiceStore.correctRate = -1
watch(statisticsStore, () => {
if (statisticsStore.inputWordNumber < 1) {
return statisticsStore.correctRate = -1
}
if (practiceStore.wrongWordNumber > practiceStore.inputWordNumber) {
return practiceStore.correctRate = 0
if (statisticsStore.wrongWordNumber > statisticsStore.inputWordNumber) {
return statisticsStore.correctRate = 0
}
practiceStore.correctRate = 100 - Math.trunc(((practiceStore.wrongWordNumber) / (practiceStore.inputWordNumber)) * 100)
statisticsStore.correctRate = 100 - Math.trunc(((statisticsStore.wrongWordNumber) / (statisticsStore.inputWordNumber)) * 100)
})

View File

@@ -40,7 +40,7 @@ const emit = defineEmits<{
const typingRef: any = $ref()
const store = useBaseStore()
const runtimeStore = useRuntimeStore()
const practiceStore = usePracticeStore()
const statisticsStore = usePracticeStore()
const settingStore = useSettingStore()
const {toggleTheme} = useTheme()
@@ -66,19 +66,17 @@ watch(() => props.words, () => {
data.index = props.index
data.wrongWords = []
practiceStore.wrongWords = []
practiceStore.repeatNumber = 0
practiceStore.startDate = Date.now()
practiceStore.correctRate = -1
practiceStore.inputWordNumber = 0
practiceStore.wrongWordNumber = 0
statisticsStore.startDate = Date.now()
statisticsStore.correctRate = -1
statisticsStore.inputWordNumber = 0
statisticsStore.wrongWordNumber = 0
stat = cloneDeep(DefaultDisplayStatistics)
}, {immediate: true})
watch(data, () => {
practiceStore.total = data.words.length
practiceStore.index = data.index
statisticsStore.total = data.words.length
statisticsStore.index = data.index
})
const word: Word = $computed(() => {
@@ -92,12 +90,12 @@ function next(isTyping: boolean = true) {
if (stat.total === -1) {
let now = Date.now()
stat = {
startDate: practiceStore.startDate,
startDate: statisticsStore.startDate,
endDate: now,
spend: now - practiceStore.startDate,
spend: now - statisticsStore.startDate,
total: props.words.length,
correctRate: -1,
inputWordNumber: practiceStore.inputWordNumber,
inputWordNumber: statisticsStore.inputWordNumber,
wrongWordNumber: data.wrongWords.length,
wrongWords: data.wrongWords,
}
@@ -108,15 +106,14 @@ function next(isTyping: boolean = true) {
console.log('当前背完了,但还有错词')
data.words = cloneDeep(data.wrongWords)
practiceStore.total = data.words.length
practiceStore.index = data.index = 0
practiceStore.inputWordNumber = 0
practiceStore.wrongWordNumber = 0
practiceStore.repeatNumber++
statisticsStore.total = data.words.length
statisticsStore.index = data.index = 0
statisticsStore.inputWordNumber = 0
statisticsStore.wrongWordNumber = 0
data.wrongWords = []
} else {
console.log('这章节完了')
isTyping && practiceStore.inputWordNumber++
isTyping && statisticsStore.inputWordNumber++
let now = Date.now()
stat.endDate = now
@@ -126,7 +123,7 @@ function next(isTyping: boolean = true) {
}
} else {
data.index++
isTyping && practiceStore.inputWordNumber++
isTyping && statisticsStore.inputWordNumber++
console.log('这个词完了')
if ([DictType.word].includes(store.currentDict.type)
&& store.skipWordNames.includes(word.word.toLowerCase())) {
@@ -141,7 +138,7 @@ function wordWrong() {
}
if (!data.wrongWords.find((v: Word) => v.word.toLowerCase() === word.word.toLowerCase())) {
data.wrongWords.push(word)
practiceStore.wrongWordNumber++
statisticsStore.wrongWordNumber++
}
}

View File

@@ -17,21 +17,21 @@ import DictModal from "@/pages/pc/components/dialog/DictDiglog.vue";
import {useStartKeyboardEventListener} from "@/hooks/event.ts";
import useTheme from "@/hooks/theme.ts";
const practiceStore = usePracticeStore()
const statisticsStore = usePracticeStore()
const store = useBaseStore()
const settingStore = useSettingStore()
const runtimeStore = useRuntimeStore()
const {toggleTheme} = useTheme()
const practiceRef: any = $ref()
watch(practiceStore, () => {
if (practiceStore.inputWordNumber < 1) {
return practiceStore.correctRate = -1
watch(statisticsStore, () => {
if (statisticsStore.inputWordNumber < 1) {
return statisticsStore.correctRate = -1
}
if (practiceStore.wrongWordNumber > practiceStore.inputWordNumber) {
return practiceStore.correctRate = 0
if (statisticsStore.wrongWordNumber > statisticsStore.inputWordNumber) {
return statisticsStore.correctRate = 0
}
practiceStore.correctRate = 100 - Math.trunc(((practiceStore.wrongWordNumber) / (practiceStore.inputWordNumber)) * 100)
statisticsStore.correctRate = 100 - Math.trunc(((statisticsStore.wrongWordNumber) / (statisticsStore.inputWordNumber)) * 100)
})

View File

@@ -17,21 +17,21 @@ import DictModal from "@/pages/pc/components/dialog/DictDiglog.vue";
import {useStartKeyboardEventListener} from "@/hooks/event.ts";
import useTheme from "@/hooks/theme.ts";
const practiceStore = usePracticeStore()
const statisticsStore = usePracticeStore()
const store = useBaseStore()
const settingStore = useSettingStore()
const runtimeStore = useRuntimeStore()
const {toggleTheme} = useTheme()
const practiceRef: any = $ref()
watch(practiceStore, () => {
if (practiceStore.inputWordNumber < 1) {
return practiceStore.correctRate = -1
watch(statisticsStore, () => {
if (statisticsStore.inputWordNumber < 1) {
return statisticsStore.correctRate = -1
}
if (practiceStore.wrongWordNumber > practiceStore.inputWordNumber) {
return practiceStore.correctRate = 0
if (statisticsStore.wrongWordNumber > statisticsStore.inputWordNumber) {
return statisticsStore.correctRate = 0
}
practiceStore.correctRate = 100 - Math.trunc(((practiceStore.wrongWordNumber) / (practiceStore.inputWordNumber)) * 100)
statisticsStore.correctRate = 100 - Math.trunc(((statisticsStore.wrongWordNumber) / (statisticsStore.inputWordNumber)) * 100)
})

View File

@@ -26,9 +26,9 @@ function close() {
function showAllWordModal() {
emitter.emit(EventKey.openWordListModal, {
title: runtimeStore.editDict.name,
translateLanguage: runtimeStore.editDict.translateLanguage,
list: runtimeStore.editDict.words
title: store.currentStudyWordDict.name,
translateLanguage: store.currentStudyWordDict.translateLanguage,
list: store.currentStudyWordDict.words
})
}

View File

@@ -21,7 +21,7 @@ import {useNav} from "@/utils";
const store = useBaseStore()
const settingStore = useSettingStore()
const runtimeStore = useRuntimeStore()
const practiceStore = usePracticeStore()
const statisticsStore = usePracticeStore()
const headerRef = $ref<HTMLDivElement>(null)
const moreOptionsRef = $ref<HTMLDivElement>(null)
@@ -80,6 +80,9 @@ const {nav} = useNav()
:title="`单词本(${settingStore.shortcutKeyMap[ShortcutKey.TogglePanel]})`"
icon="tdesign:menu-unfold"/>
</div>
<div class="absolute left-1/2" style="transform: translateX(-50%)">
{{ statisticsStore.step ? '复习' : '学习新词'}}
</div>
</div>
<Tooltip :title="settingStore.showToolbar?'收起':'展开'">
<Icon icon="icon-park-outline:down"
@@ -146,7 +149,6 @@ header {
.options {
display: flex;
align-items: center;
overflow: hidden;
gap:.2rem;
}
}

View File

@@ -13,7 +13,7 @@ import Tooltip from "@/pages/pc/components/Tooltip.vue";
import useTheme from "@/hooks/theme.ts";
import BaseIcon from "@/components/BaseIcon.vue";
const practiceStore = usePracticeStore()
const statisticsStore = usePracticeStore()
const store = useBaseStore()
const settingStore = useSettingStore()
const runtimeStore = useRuntimeStore()

View File

@@ -4,7 +4,7 @@ import {onMounted, onUnmounted} from "vue"
import {usePracticeStore} from "@/stores/practice.ts";
import {useSettingStore} from "@/stores/setting.ts";
const practiceStore = usePracticeStore()
const statisticsStore = usePracticeStore()
const settingStore = useSettingStore()
function format(val: number, suffix: string = '', check: number = -1) {
@@ -12,16 +12,16 @@ function format(val: number, suffix: string = '', check: number = -1) {
}
const progress = $computed(() => {
if (!practiceStore.total) return 0
if (practiceStore.index > practiceStore.total) return 100
return ((practiceStore.index / practiceStore.total) * 100)
if (!statisticsStore.total) return 0
if (statisticsStore.index > statisticsStore.total) return 100
return ((statisticsStore.index / statisticsStore.total) * 100)
})
let speedMinute = $ref(0)
let timer = $ref(0)
onMounted(() => {
timer = setInterval(() => {
speedMinute = Math.floor((Date.now() - practiceStore.startDate) / 1000 / 60)
speedMinute = Math.floor((Date.now() - statisticsStore.startDate) / 1000 / 60)
}, 1000)
})
@@ -45,22 +45,22 @@ onUnmounted(() => {
<div class="name">时间</div>
</div>
<div class="row">
<div class="num">{{ practiceStore.total }}</div>
<div class="num">{{ statisticsStore.total }}</div>
<div class="line"></div>
<div class="name">单词总数</div>
</div>
<div class="row">
<div class="num">{{ format(practiceStore.inputWordNumber, '', 0) }}</div>
<div class="num">{{ format(statisticsStore.inputWordNumber, '', 0) }}</div>
<div class="line"></div>
<div class="name">输入数</div>
</div>
<div class="row">
<div class="num">{{ format(practiceStore.wrongWordNumber, '', 0) }}</div>
<div class="num">{{ format(statisticsStore.wrongWordNumber, '', 0) }}</div>
<div class="line"></div>
<div class="name">错误数</div>
</div>
<div class="row">
<div class="num">{{ format(practiceStore.correctRate, '%') }}</div>
<div class="num">{{ format(statisticsStore.correctRate, '%') }}</div>
<div class="line"></div>
<div class="name">正确率</div>
</div>

View File

@@ -11,24 +11,21 @@ import {onMounted, reactive} from "vue";
import {cloneDeep} from "lodash-es";
import {Icon} from '@iconify/vue';
import {useSettingStore} from "@/stores/setting.ts";
import {usePracticeStore} from "@/stores/practice.ts";
import {dayjs} from "element-plus";
const store = useBaseStore()
const settingStore = useSettingStore()
let statModalIsOpen = $ref(false)
let currentStat = reactive<DisplayStatistics>(cloneDeep(DefaultDisplayStatistics))
const statStore = usePracticeStore()
let open = $ref(false)
onMounted(() => {
emitter.on(EventKey.openStatModal, (stat: DisplayStatistics) => {
if (stat) {
currentStat = {...DefaultDisplayStatistics, ...stat}
store.saveStatistics(stat)
console.log('stat', stat)
}
statModalIsOpen = true
emitter.on(EventKey.openStatModal, () => {
open = true
})
const close = () => {
statModalIsOpen = false
open = false
}
emitter.on(ShortcutKey.NextChapter, close)
@@ -38,7 +35,7 @@ onMounted(() => {
function options(emitType: 'write' | 'repeat' | 'next') {
statModalIsOpen = false
open = false
emitter.emit(EventKey[emitType])
}
@@ -53,7 +50,7 @@ const isEnd = $computed(() => {
<template>
<Dialog
:header="false"
v-model="statModalIsOpen">
v-model="open">
<div class="statistics relative flex flex-col gap-6">
<header>
<div class="text-2xl">{{ store.currentStudyWordDict.name }}</div>
@@ -61,18 +58,20 @@ const isEnd = $computed(() => {
<div class="flex justify-center gap-10">
<div class="text-xl text-center flex flex-col justify-around">
<div class="font-bold">非常棒!</div>
<div>坚持了 <span class="color-green font-bold text-2xl">10</span> 分钟</div>
<div>坚持了 <span class="color-green font-bold text-2xl">{{ dayjs().diff(statStore.startDate, 'm') }}</span>
分钟
</div>
</div>
<Ring
:value="currentStat.wrongWordNumber"
:value="statStore.newWordNumber"
desc="New"
:percentage="10"
:percentage="35"
/>
</div>
<div class="flex justify-center gap-10">
<div class="flex justify-center items-center py-3 px-10 rounded-md color-red-500 flex-col"
style="background: rgb(254,236,236)">
<div class="text-3xl">3</div>
<div class="text-3xl">{{ statStore.inputWordNumber }}</div>
<div class="center gap-2">
<Icon icon="iconamoon:close" class="text-2xl"/>
错词
@@ -80,7 +79,7 @@ const isEnd = $computed(() => {
</div>
<div class="flex justify-center items-center py-3 px-10 rounded-md color-green-600 flex-col"
style="background: rgb(231,248,241)">
<div class="text-3xl">3</div>
<div class="text-3xl">{{ statStore.total - statStore.inputWordNumber }}</div>
<div class="center gap-2">
<Icon icon="tabler:check" class="text-2xl"/>
正确
@@ -96,11 +95,6 @@ const isEnd = $computed(() => {
</Tooltip>
</div>
<div class="footer">
<BaseButton
:keyboard="settingStore.shortcutKeyMap[ShortcutKey.DictationChapter]"
@click="options('write')">
默写
</BaseButton>
<BaseButton
:keyboard="settingStore.shortcutKeyMap[ShortcutKey.RepeatChapter]"
@click="options('repeat')">
@@ -109,12 +103,17 @@ const isEnd = $computed(() => {
<BaseButton
:keyboard="settingStore.shortcutKeyMap[ShortcutKey.NextChapter]"
@click="options('next')">
{{ isEnd ? '重新练习' : '继续' }}
{{ isEnd ? '重新练习' : '再来一组' }}
</BaseButton>
<BaseButton
type="primary"
@click="options('next')">
分享
</BaseButton>
</div>
</div>
</Dialog>
<Fireworks v-if="statModalIsOpen"/>
<Fireworks v-if="open"/>
</template>
<style scoped lang="scss">
@import "@/assets/css/style";

View File

@@ -65,7 +65,7 @@ const playKeyboardAudio = usePlayKeyboardAudio()
const playWordAudio = usePlayWordAudio()
const store = useBaseStore()
const practiceStore = usePracticeStore()
const statisticsStore = usePracticeStore()
const settingStore = useSettingStore()
watch(() => props.article, () => {
@@ -97,7 +97,7 @@ function nextSentence() {
//todo 计得把略过的单词加上统计里面去
// if (!store.skipWordNamesWithSimpleWords.includes(currentWord.word.toLowerCase()) && !currentWord.isSymbol) {
// practiceStore.inputNumber++
// statisticsStore.inputNumber++
// }
sentenceIndex++

View File

@@ -31,7 +31,7 @@ import ArticleList from "@/pages/pc/components/list/ArticleList.vue";
import {useOnKeyboardEventListener} from "@/hooks/event.ts";
const store = useBaseStore()
const practiceStore = usePracticeStore()
const statisticsStore = usePracticeStore()
const runtimeStore = useRuntimeStore()
let tabIndex = $ref(0)
@@ -74,17 +74,15 @@ function setArticle(val: Article) {
let tempVal = cloneDeep(val)
articleData.articles[store.currentArticleDict.chapterIndex] = tempVal
articleData.article = tempVal
practiceStore.inputWordNumber = 0
practiceStore.wrongWordNumber = 0
practiceStore.repeatNumber = 0
practiceStore.total = 0
practiceStore.wrongWords = []
practiceStore.startDate = Date.now()
statisticsStore.inputWordNumber = 0
statisticsStore.wrongWordNumber = 0
statisticsStore.total = 0
statisticsStore.startDate = Date.now()
articleData.article.sections.map((v, i) => {
v.map((w, j) => {
w.words.map(s => {
if (!store.skipWordNamesWithSimpleWords.includes(s.word.toLowerCase()) && !s.isSymbol) {
practiceStore.total++
statisticsStore.total++
}
})
})
@@ -193,39 +191,33 @@ function wrong(word: Word) {
store.wrong.originWords.push(word)
}
if (!store.skipWordNamesWithSimpleWords.includes(lowerName)) {
if (!practiceStore.wrongWords.find((v) => v.word.toLowerCase() === lowerName)) {
practiceStore.wrongWords.push(word)
practiceStore.wrongWordNumber++
}
}
}
function over() {
if (practiceStore.wrongWordNumber === 0) {
if (statisticsStore.wrongWordNumber === 0) {
// if (false) {
console.log('这章节完了')
let now = Date.now()
let stat: DisplayStatistics = {
startDate: practiceStore.startDate,
startDate: statisticsStore.startDate,
endDate: now,
spend: now - practiceStore.startDate,
total: practiceStore.total,
spend: now - statisticsStore.startDate,
total: statisticsStore.total,
correctRate: -1,
wrongWordNumber: practiceStore.wrongWordNumber,
wrongWords: practiceStore.wrongWords,
wrongWordNumber: statisticsStore.wrongWordNumber,
}
stat.correctRate = 100 - Math.trunc(((stat.wrongWordNumber) / (stat.total)) * 100)
emitter.emit(EventKey.openStatModal, stat)
} else {
tabIndex = 1
wordData.words = practiceStore.wrongWords
wordData.index = 0
}
}
function nextWord(word: ArticleWord) {
if (!store.skipWordNamesWithSimpleWords.includes(word.word.toLowerCase()) && !word.isSymbol) {
practiceStore.inputWordNumber++
statisticsStore.inputWordNumber++
}
}

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import {onMounted, onUnmounted, watch} from "vue"
import {useBaseStore} from "@/stores/base.ts"
import {DefaultDisplayStatistics, DictType, ShortcutKey, Sort, Word} from "@/types.ts";
import {DefaultDisplayStatistics, DictType, getDefaultWord, ShortcutKey, Sort, Word} from "@/types.ts";
import {emitter, EventKey} from "@/utils/eventBus.ts"
import {cloneDeep, reverse, shuffle} from "lodash-es"
import {usePracticeStore} from "@/stores/practice.ts"
@@ -21,24 +21,29 @@ import MiniDialog from "@/pages/pc/components/dialog/MiniDialog.vue";
import BaseButton from "@/components/BaseButton.vue";
interface IProps {
words: Word[],
index: number,
data: {
new: any[],
review: any[],
}
}
const props = withDefaults(defineProps<IProps>(), {
words: [],
index: -1
data: {
new: [],
review: [],
}
})
const emit = defineEmits<{
'update:words': [val: Word[]],
sort: [val: Word[]]
sort: [val: Word[]],
complete: [val: any]
}>()
const typingRef: any = $ref()
const store = useBaseStore()
const runtimeStore = useRuntimeStore()
const practiceStore = usePracticeStore()
const statisticsStore = usePracticeStore()
const settingStore = useSettingStore()
const {
@@ -48,100 +53,73 @@ const {
toggleWordSimple
} = useWordOptions()
let data = $ref({
index: props.index,
words: props.words,
let allWrongWords = []
let current = $ref({
index: 0,
words: [],
wrongWords: [],
})
let stat = cloneDeep(DefaultDisplayStatistics)
let showSortOption = $ref(false)
useWindowClick(() => showSortOption = false)
watch(() => props.words, () => {
data.words = props.words
data.index = props.index
data.wrongWords = []
watch(() => props.data, () => {
current.words = props.data.new
current.index = 0
current.wrongWords = []
allWrongWords = []
practiceStore.wrongWords = []
practiceStore.repeatNumber = 0
practiceStore.startDate = Date.now()
practiceStore.correctRate = -1
practiceStore.inputWordNumber = 0
practiceStore.wrongWordNumber = 0
stat = cloneDeep(DefaultDisplayStatistics)
}, {immediate: true})
watch(data, () => {
practiceStore.total = data.words.length
practiceStore.index = data.index
})
statisticsStore.step = 0
statisticsStore.startDate = Date.now()
statisticsStore.correctRate = -1
statisticsStore.inputWordNumber = 0
statisticsStore.wrongWordNumber = 0
statisticsStore.total = props.data.review.concat(props.data.new).length
statisticsStore.newWordNumber = props.data.new.length
statisticsStore.index = 0
}, {immediate: true, deep: true})
const word = $computed(() => {
return data.words[data.index] ?? {
trans: [],
word: '',
usphone: '',
ukphone: '',
}
return current.words[current.index] ?? getDefaultWord()
})
const prevWord: Word = $computed(() => {
return data.words?.[data.index - 1] ?? undefined
return current.words?.[current.index - 1] ?? undefined
})
const nextWord: Word = $computed(() => {
return data.words?.[data.index + 1] ?? undefined
return current.words?.[current.index + 1] ?? undefined
})
function next(isTyping: boolean = true) {
if (data.index === data.words.length - 1) {
//复制当前错词,因为第一遍错词是最多的,后续的练习都是从错词中练习
if (stat.total === -1) {
let now = Date.now()
stat = {
startDate: practiceStore.startDate,
endDate: now,
spend: now - practiceStore.startDate,
total: props.words.length,
correctRate: -1,
inputWordNumber: practiceStore.inputWordNumber,
wrongWordNumber: data.wrongWords.length,
wrongWords: data.wrongWords,
}
stat.correctRate = 100 - Math.trunc(((stat.wrongWordNumber) / (stat.total)) * 100)
}
if (data.wrongWords.length) {
if (current.index === current.words.length - 1) {
if (current.wrongWords.length) {
console.log('当前背完了,但还有错词')
data.words = cloneDeep(data.wrongWords)
practiceStore.total = data.words.length
practiceStore.index = data.index = 0
practiceStore.inputWordNumber = 0
practiceStore.wrongWordNumber = 0
practiceStore.repeatNumber++
data.wrongWords = []
current.words = cloneDeep(current.wrongWords)
current.wrongWords = []
} else {
console.log('这章节完了')
isTyping && practiceStore.inputWordNumber++
let now = Date.now()
stat.endDate = now
stat.spend = now - stat.startDate
emitter.emit(EventKey.openStatModal, stat)
console.log('这章节完了', statisticsStore.total)
isTyping && statisticsStore.inputWordNumber++
statisticsStore.speed = Date.now() - statisticsStore.startDate
if (statisticsStore.step) {
emitter.emit(EventKey.openStatModal, {})
// emit('complete', {})
} else {
if (props.data.review.length) {
settingStore.dictation = true
statisticsStore.step++
current.words = shuffle(props.data.review.concat(props.data.new))
current.index = 0
} else {
emitter.emit(EventKey.openStatModal, {})
// emit('complete', {})
}
}
}
} else {
data.index++
isTyping && practiceStore.inputWordNumber++
current.index++
isTyping && statisticsStore.inputWordNumber++
console.log('这个词完了')
if ([DictType.word].includes(store.currentDict.type)
&& store.skipWordNames.includes(word.word.toLowerCase())) {
next()
}
}
}
@@ -149,9 +127,12 @@ function wordWrong() {
if (!store.wrong2.find((v: Word) => v.word.toLowerCase() === word.word.toLowerCase())) {
store.wrong2.push(word)
}
if (!data.wrongWords.find((v: Word) => v.word.toLowerCase() === word.word.toLowerCase())) {
data.wrongWords.push(word)
practiceStore.wrongWordNumber++
if (!current.wrongWords.find((v: Word) => v.word.toLowerCase() === word.word.toLowerCase())) {
current.wrongWords.push(word)
}
if (!allWrongWords.find((v: Word) => v.word.toLowerCase() === word.word.toLowerCase())) {
allWrongWords.push(word)
statisticsStore.wrongWordNumber++
}
}
@@ -172,10 +153,10 @@ useOnKeyboardEventListener(onKeyDown, onKeyUp)
//TODO 略过忽略的单词上
function prev() {
if (data.index === 0) {
if (current.index === 0) {
ElMessage.warning('已经是第一个了~')
} else {
data.index--
current.index--
}
}
@@ -209,11 +190,11 @@ function play() {
function sort(type: Sort) {
if (type === Sort.reverse) {
ElMessage.success('已翻转排序')
emit('sort', reverse(cloneDeep(data.words)))
emit('sort', reverse(cloneDeep(current.words)))
}
if (type === Sort.random) {
ElMessage.success('已随机排序')
emit('sort', shuffle(data.words))
emit('sort', shuffle(current.words))
}
}
@@ -286,7 +267,7 @@ onUnmounted(() => {
v-loading="!store.load"
>
<div class="list-header">
<div>{{ data.words.length }}个单词</div>
<div>{{ current.words.length }}个单词</div>
<div style="position:relative;"
@click.stop="null">
<BaseIcon
@@ -309,14 +290,14 @@ onUnmounted(() => {
</div>
</div>
<WordList
v-if="data.words.length"
v-if="current.words.length"
:is-active="active"
:static="false"
:show-word="!settingStore.dictation"
:show-translate="settingStore.translate"
:list="data.words"
:activeIndex="data.index"
@click="(val:any) => data.index = val.index"
:list="current.words"
:activeIndex="current.index"
@click="(val:any) => current.index = val.index"
>
<template v-slot:suffix="{item,index}">
<BaseIcon

View File

@@ -10,33 +10,28 @@ import Statistics from "@/pages/pc/practice/Statistics.vue";
import {emitter, EventKey} from "@/utils/eventBus.ts";
import {useSettingStore} from "@/stores/setting.ts";
import {useRuntimeStore} from "@/stores/runtime.ts";
import {MessageBox} from "@/utils/MessageBox.tsx";
import PracticeArticle from "@/pages/pc/practice/practice-article/index.vue";
import PracticeWord from "@/pages/pc/practice/practice-word/index.vue";
import {ShortcutKey, Word} from "@/types.ts";
import DictModal from "@/pages/pc/components/dialog/DictDiglog.vue";
import {useStartKeyboardEventListener} from "@/hooks/event.ts";
import useTheme from "@/hooks/theme.ts";
import Logo from "@/pages/pc/components/Logo.vue";
import {Icon} from "@iconify/vue";
import TypingWord from "@/pages/pc/practice/practice-word/TypingWord.vue";
import {cloneDeep} from "lodash-es";
import {syncMyDictList} from "@/hooks/dict.ts";
import {cloneDeep, shuffle} from "lodash-es";
const practiceStore = usePracticeStore()
const statisticsStore = usePracticeStore()
const store = useBaseStore()
const settingStore = useSettingStore()
const runtimeStore = useRuntimeStore()
const {toggleTheme} = useTheme()
watch(practiceStore, () => {
if (practiceStore.inputWordNumber < 1) {
return practiceStore.correctRate = -1
watch(statisticsStore, () => {
if (statisticsStore.inputWordNumber < 1) {
return statisticsStore.correctRate = -1
}
if (practiceStore.wrongWordNumber > practiceStore.inputWordNumber) {
return practiceStore.correctRate = 0
if (statisticsStore.wrongWordNumber > statisticsStore.inputWordNumber) {
return statisticsStore.correctRate = 0
}
practiceStore.correctRate = 100 - Math.trunc(((practiceStore.wrongWordNumber) / (practiceStore.inputWordNumber)) * 100)
statisticsStore.correctRate = 100 - Math.trunc(((statisticsStore.wrongWordNumber) / (statisticsStore.inputWordNumber)) * 100)
})
function next() {
@@ -133,20 +128,39 @@ onUnmounted(() => {
emitter.off(ShortcutKey.TogglePanel, togglePanel)
})
onMounted(() => {
getCurrentPractice()
emitter.on(EventKey.changeDict, getCurrentPractice)
})
onUnmounted(() => {
emitter.off(EventKey.changeDict, getCurrentPractice)
})
let wordData = $ref({
words: [],
index: -1
})
let data = $ref({
new: [],
review: []
})
function getCurrentPractice() {
let c = store.currentStudy.word
let wordDict = store.currentStudyWordDict;
if (wordDict.words?.length) {
wordData.index = 0
wordData.statistics.map(v=>{
wordData.words = []
statisticsStore.step = 0
for (let i = c.lastLearnIndex; i < wordDict.words.length; i++) {
if (data.new.length >= c.perDayStudyNumber) break
let item = wordDict.words[i]
if (!store.skipWordNames.includes(item.word.toLowerCase())) {
data.new.push(item)
}
}
})
wordData.words = cloneDeep(wordDict.words.slice(c.lastLearnIndex, c.lastLearnIndex + c.perDayStudyNumber))
emitter.emit(EventKey.resetWord)
}
}
@@ -158,15 +172,9 @@ function sort(list: Word[]) {
syncMyDictList(store.currentDict)
}
onMounted(() => {
getCurrentPractice()
emitter.on(EventKey.changeDict, getCurrentPractice)
})
onUnmounted(() => {
emitter.off(EventKey.changeDict, getCurrentPractice)
})
function complete() {
}
useStartKeyboardEventListener()
@@ -177,8 +185,8 @@ useStartKeyboardEventListener()
<div class="flex flex-1">
<TypingWord
@sort="sort"
v-model:words="wordData.words"
:index="wordData.index"/>
@complete="complete"
:data="data"/>
</div>
<Footer/>
</div>

View File

@@ -134,8 +134,8 @@ export const DefaultBaseState = (): BaseState => ({
currentStudy: {
word: {
dictIndex: 0,
perDayStudyNumber: 30,
lastLearnIndex: 10,
perDayStudyNumber: 3,
lastLearnIndex: 0,
},
article: {
dictIndex: 0,

View File

@@ -1,11 +1,9 @@
import {defineStore} from "pinia"
import {Word} from "@/types.ts"
export interface PracticeState {
wrongWords: Word[],
//todo 废弃
repeatNumber: number,
step: number,
startDate: number,
speed: number,
total: number,
index: number,//当前输入的第几个用于和total计算进度
newWordNumber: number,
@@ -17,8 +15,8 @@ export interface PracticeState {
export const usePracticeStore = defineStore('practice', {
state: (): PracticeState => {
return {
wrongWords: [],
repeatNumber: 0,
step: 0,
speed: 0,
startDate: Date.now(),
correctRate: -1,
total: 0,

View File

@@ -32,6 +32,17 @@ export const DefaultWord: Word = {
trans: [],
}
export function getDefaultWord(val?: any) {
return {
id:'',
word: '',
phonetic0: '',
phonetic1: '',
trans: [],
...val
}
}
export type StudyWord = {
type: 'new' | 'repeat' | 'wrong'
word: Word
@@ -122,8 +133,8 @@ export const DefaultArticle: Article = {
}
export interface Statistics {
startIndex:number,
endIndex:number,
startIndex: number,
endIndex: number,
startDate: number,//开始日期
endDate: number//结束日期
spend: number,//花费时间
@@ -173,6 +184,7 @@ export enum ShortcutKey {
NextChapter = 'NextChapter',
PreviousChapter = 'PreviousChapter',
RepeatChapter = 'RepeatChapter',
//todo 废弃
DictationChapter = 'DictationChapter',
PlayWordPronunciation = 'PlayWordPronunciation',
// PlayTranslatePronunciation = 'PlayTranslatePronunciation',

View File

@@ -200,3 +200,38 @@ export function useNav() {
return {nav, back: router.back}
}
export function _dateFormat(val, type?): string {
if (!val) return
if (String(val).length === 10) {
val = val * 1000
}
const d = new Date(Number(val))
const year = d.getFullYear()
const m = d.getMonth() + 1
const mStr = m < 10 ? '0' + m : m
const day = d.getDate()
const dayStr = day < 10 ? '0' + day : day
const h = d.getHours()
const hStr = h < 10 ? '0' + h : h
const min = d.getMinutes()
const minStr = min < 10 ? '0' + min : min
const sec = d.getSeconds()
const secStr = sec < 10 ? '0' + sec : sec
switch (type) {
case 'Y':
return year + ''
case 'M':
return `${year}-${mStr}`
case 'M_D':
return `${mStr}-${dayStr}`
case 'M_CN':
return `${year}${mStr}`
case 'D':
return `${year}-${mStr}-${dayStr}`
case 'm':
return `${year}-${mStr}-${dayStr} ${hStr}:${minStr}`
default:
return `${year}-${mStr}-${dayStr} ${hStr}:${minStr}:${secStr}`
}
}