save
This commit is contained in:
2
Note.md
2
Note.md
@@ -45,4 +45,6 @@ A cold welcome 有bug
|
||||
|
||||
单词发音,点击第二遍时减速
|
||||
|
||||
http://enpuz.com/ 语法分析工具
|
||||
|
||||
键盘音效应该多放几遍
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,14 +24,14 @@ provide('tabIndex', computed(() => tabIndex))
|
||||
watch(() => settingStore.showPanel, n => {
|
||||
if (n) {
|
||||
switch (store.current.dictType) {
|
||||
case DictType.newWordDict:
|
||||
case DictType.new:
|
||||
return tabIndex = 1;
|
||||
case DictType.skipWordDict:
|
||||
case DictType.skip:
|
||||
return tabIndex = 3;
|
||||
case DictType.wrongWordDict:
|
||||
case DictType.wrong:
|
||||
return tabIndex = 2;
|
||||
case DictType.publicDict:
|
||||
case DictType.customDict:
|
||||
case DictType.word:
|
||||
case DictType.customWord:
|
||||
return tabIndex = 0;
|
||||
}
|
||||
}
|
||||
@@ -46,23 +46,23 @@ const currentData = $computed(() => {
|
||||
else return props
|
||||
})
|
||||
|
||||
const newWordDictData = $computed(() => {
|
||||
if (store.current.dictType !== DictType.newWordDict) return {list: store.newWordDict.words ?? [], index: -1}
|
||||
const newData = $computed(() => {
|
||||
if (store.current.dictType !== DictType.new) return {list: store.new.words ?? [], index: -1}
|
||||
else return props
|
||||
})
|
||||
|
||||
const wrongWordDictData = $computed(() => {
|
||||
if (store.current.dictType !== DictType.wrongWordDict) return {list: store.wrongWordDict.words ?? [], index: -1}
|
||||
const wrongData = $computed(() => {
|
||||
if (store.current.dictType !== DictType.wrong) return {list: store.wrong.words ?? [], index: -1}
|
||||
else return props
|
||||
})
|
||||
|
||||
const skipWordDictData = $computed(() => {
|
||||
if (store.current.dictType !== DictType.skipWordDict) return {list: store.skipWordDict.words ?? [], index: -1}
|
||||
const skipData = $computed(() => {
|
||||
if (store.current.dictType !== DictType.skip) return {list: store.skip.words ?? [], index: -1}
|
||||
else return props
|
||||
})
|
||||
|
||||
function changeIndex(i: number, dict: Dict) {
|
||||
dict.chapterWordIndex = i
|
||||
dict.wordIndex = i
|
||||
console.log('i', i, dict.type)
|
||||
if (store.current.dictType === dict.type) {
|
||||
emit('update:index', i)
|
||||
@@ -80,11 +80,11 @@ function changeIndex(i: number, dict: Dict) {
|
||||
<div class="tab" :class="tabIndex === 0 && 'active'" @click="tabIndex = 0">
|
||||
{{ currentDict.name + ` 第${currentDict.chapterIndex + 1}章` }}
|
||||
</div>
|
||||
<div class="tab" :class="tabIndex === 1 && 'active'" @click="tabIndex = 1">{{ store.newWordDict.name }}</div>
|
||||
<div class="tab" :class="tabIndex === 1 && 'active'" @click="tabIndex = 1">{{ store.new.name }}</div>
|
||||
<div class="tab" :class="tabIndex === 2 && 'active'" @click="tabIndex = 2">
|
||||
{{ store.wrongWordDict.name }}
|
||||
{{ store.wrong.name }}
|
||||
</div>
|
||||
<div class="tab" :class="tabIndex === 3 && 'active'" @click="tabIndex = 3">{{ store.skipWordDict.name }}</div>
|
||||
<div class="tab" :class="tabIndex === 3 && 'active'" @click="tabIndex = 3">{{ store.skip.name }}</div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="slide">
|
||||
@@ -101,7 +101,7 @@ function changeIndex(i: number, dict: Dict) {
|
||||
:list="currentData.list"
|
||||
:activeIndex="currentData.index"/>
|
||||
</div>
|
||||
<footer v-if="![DictType.customDict,DictType.publicDict].includes(store.current.dictType)">
|
||||
<footer v-if="![DictType.customWord,DictType.word].includes(store.current.dictType)">
|
||||
<PopConfirm
|
||||
:title="`确认切换?`"
|
||||
@confirm="changeIndex(0,currentDict)"
|
||||
@@ -112,20 +112,20 @@ function changeIndex(i: number, dict: Dict) {
|
||||
</div>
|
||||
<div class="slide-item">
|
||||
<header>
|
||||
<div class="dict-name">总词数:{{ newWordDictData.list.length }}</div>
|
||||
<div class="dict-name">总词数:{{ newData.list.length }}</div>
|
||||
</header>
|
||||
<div class="content">
|
||||
<WordList
|
||||
class="word-list"
|
||||
@change="(i:number) => changeIndex(i,store.newWordDict)"
|
||||
@change="(i:number) => changeIndex(i,store.new)"
|
||||
:isActive="settingStore.showPanel && tabIndex === 1"
|
||||
:list="newWordDictData.list"
|
||||
:activeIndex="newWordDictData.index"/>
|
||||
:list="newData.list"
|
||||
:activeIndex="newData.index"/>
|
||||
</div>
|
||||
<footer v-if="store.current.dictType !== DictType.newWordDict && newWordDictData.list.length">
|
||||
<footer v-if="store.current.dictType !== DictType.new && newData.list.length">
|
||||
<PopConfirm
|
||||
:title="`确认切换?`"
|
||||
@confirm="changeIndex(0,store.newWordDict)"
|
||||
@confirm="changeIndex(0,store.new)"
|
||||
>
|
||||
<BaseButton>切换</BaseButton>
|
||||
</PopConfirm>
|
||||
@@ -134,21 +134,21 @@ function changeIndex(i: number, dict: Dict) {
|
||||
<div class="slide-item">
|
||||
<header>
|
||||
<a href="" target="_blank"></a>
|
||||
<div class="dict-name">总词数:{{ wrongWordDictData.list.length }}</div>
|
||||
<div class="dict-name">总词数:{{ wrongData.list.length }}</div>
|
||||
</header>
|
||||
<div class="content">
|
||||
<WordList
|
||||
class="word-list"
|
||||
@change="(i:number) => changeIndex(i,store.wrongWordDict)"
|
||||
@change="(i:number) => changeIndex(i,store.wrong)"
|
||||
:isActive="settingStore.showPanel && tabIndex === 2"
|
||||
:list="wrongWordDictData.list"
|
||||
:activeIndex="wrongWordDictData.index"/>
|
||||
:list="wrongData.list"
|
||||
:activeIndex="wrongData.index"/>
|
||||
</div>
|
||||
<footer
|
||||
v-if="store.current.dictType !== DictType.wrongWordDict && wrongWordDictData.list.length">
|
||||
v-if="store.current.dictType !== DictType.wrong && wrongData.list.length">
|
||||
<PopConfirm
|
||||
:title="`确认切换?`"
|
||||
@confirm="changeIndex(0,store.wrongWordDict)"
|
||||
@confirm="changeIndex(0,store.wrong)"
|
||||
>
|
||||
<BaseButton>切换</BaseButton>
|
||||
</PopConfirm>
|
||||
@@ -156,20 +156,20 @@ function changeIndex(i: number, dict: Dict) {
|
||||
</div>
|
||||
<div class="slide-item">
|
||||
<header>
|
||||
<div class="dict-name">总词数:{{ skipWordDictData.list.length }}</div>
|
||||
<div class="dict-name">总词数:{{ skipData.list.length }}</div>
|
||||
</header>
|
||||
<div class="content">
|
||||
<WordList
|
||||
class="word-list"
|
||||
@change="(i:number) => changeIndex(i,store.skipWordDict)"
|
||||
@change="(i:number) => changeIndex(i,store.skip)"
|
||||
:isActive="settingStore.showPanel && tabIndex === 3"
|
||||
:list="skipWordDictData.list"
|
||||
:activeIndex="skipWordDictData.index"/>
|
||||
:list="skipData.list"
|
||||
:activeIndex="skipData.index"/>
|
||||
</div>
|
||||
<footer v-if="store.current.dictType !== DictType.skipWordDict && skipWordDictData.list.length">
|
||||
<footer v-if="store.current.dictType !== DictType.skip && skipData.list.length">
|
||||
<PopConfirm
|
||||
:title="`确认切换?`"
|
||||
@confirm="changeIndex(0,store.skipWordDict)"
|
||||
@confirm="changeIndex(0,store.skip)"
|
||||
>
|
||||
<BaseButton>切换</BaseButton>
|
||||
</PopConfirm>
|
||||
|
||||
@@ -281,10 +281,10 @@ function onKeyDown(e: KeyboardEvent) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!store.wrongWordDict.originWords.find((v: Word) => v.name.toLowerCase() === currentWord.name.toLowerCase())) {
|
||||
store.wrongWordDict.originWords.push(currentWord)
|
||||
store.wrongWordDict.words.push(currentWord)
|
||||
store.wrongWordDict.chapterWords = [store.wrongWordDict.words]
|
||||
if (!store.wrong.originWords.find((v: Word) => v.name.toLowerCase() === currentWord.name.toLowerCase())) {
|
||||
store.wrong.originWords.push(currentWord)
|
||||
store.wrong.words.push(currentWord)
|
||||
store.wrong.chapterWords = [store.wrong.words]
|
||||
}
|
||||
|
||||
if (!store.skipWordNamesWithSimpleWords.includes(currentWord.name.toLowerCase())) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import {Icon} from "@iconify/vue";
|
||||
import VolumeIcon from "@/components/VolumeIcon.vue";
|
||||
import Tooltip from "@/components/Tooltip.vue";
|
||||
import Panel from "@/components/Practice/Panel.vue";
|
||||
import IconWrapper from "@/components/IconWrapper.vue";
|
||||
|
||||
interface IProps {
|
||||
words: Word[],
|
||||
@@ -75,19 +76,7 @@ watch(() => data.index, (n) => {
|
||||
}
|
||||
})
|
||||
|
||||
let allList = $ref([])
|
||||
|
||||
|
||||
const word = $computed(() => {
|
||||
// let w = data.words[data.index]
|
||||
// let s = allList.find(s => s.name === w.name)
|
||||
// if (s) return s
|
||||
// else return w ?? {
|
||||
// trans: [],
|
||||
// name: '',
|
||||
// usphone: '',
|
||||
// ukphone: '',
|
||||
// }
|
||||
return data.words[data.index] ?? {
|
||||
trans: [],
|
||||
name: '',
|
||||
@@ -151,7 +140,7 @@ function next(isTyping: boolean = true) {
|
||||
data.index++
|
||||
isTyping && practiceStore.inputWordNumber++
|
||||
console.log('这个词完了')
|
||||
if ([DictType.customDict, DictType.publicDict].includes(store.current.dictType)
|
||||
if ([DictType.customWord, DictType.word].includes(store.current.dictType)
|
||||
&& store.skipWordNames.includes(word.name.toLowerCase())) {
|
||||
next()
|
||||
}
|
||||
@@ -171,10 +160,10 @@ function ignore() {
|
||||
}
|
||||
|
||||
function collect() {
|
||||
if (!store.newWordDict.originWords.find((v: Word) => v.name.toLowerCase() === word.name.toLowerCase())) {
|
||||
store.newWordDict.originWords.push(word)
|
||||
store.newWordDict.words.push(word)
|
||||
store.newWordDict.chapterWords = [store.newWordDict.words]
|
||||
if (!store.new.originWords.find((v: Word) => v.name.toLowerCase() === word.name.toLowerCase())) {
|
||||
store.new.originWords.push(word)
|
||||
store.new.words.push(word)
|
||||
store.new.chapterWords = [store.new.words]
|
||||
}
|
||||
activeBtnIndex = 1
|
||||
setTimeout(() => {
|
||||
@@ -184,9 +173,9 @@ function collect() {
|
||||
|
||||
function remove() {
|
||||
if (!store.skipWordNames.includes(word.name.toLowerCase())) {
|
||||
store.skipWordDict.originWords.push(word)
|
||||
store.skipWordDict.words.push(word)
|
||||
store.skipWordDict.chapterWords = [store.skipWordDict.words]
|
||||
store.skip.originWords.push(word)
|
||||
store.skip.words.push(word)
|
||||
store.skip.chapterWords = [store.skip.words]
|
||||
}
|
||||
activeBtnIndex = 0
|
||||
next(false)
|
||||
@@ -225,10 +214,10 @@ async function onKeyDown(e: KeyboardEvent) {
|
||||
isWrong = (input + letter) !== word.name.slice(0, input.length + 1)
|
||||
}
|
||||
if (isWrong) {
|
||||
if (!store.wrongWordDict.originWords.find((v: Word) => v.name.toLowerCase() === word.name.toLowerCase())) {
|
||||
store.wrongWordDict.originWords.push(word)
|
||||
store.wrongWordDict.words.push(word)
|
||||
store.wrongWordDict.chapterWords = [store.wrongWordDict.words]
|
||||
if (!store.wrong.originWords.find((v: Word) => v.name.toLowerCase() === word.name.toLowerCase())) {
|
||||
store.wrong.originWords.push(word)
|
||||
store.wrong.words.push(word)
|
||||
store.wrong.chapterWords = [store.wrong.words]
|
||||
}
|
||||
if (!data.wrongWords.find((v: Word) => v.name.toLowerCase() === word.name.toLowerCase())) {
|
||||
data.wrongWords.push(word)
|
||||
@@ -305,21 +294,15 @@ useOnKeyboardEventListener(onKeyDown, onKeyUp)
|
||||
<div class="prev"
|
||||
@click="prev"
|
||||
v-if="prevWord">
|
||||
<Icon icon="bi:arrow-left" width="22"/>
|
||||
<div class="word">
|
||||
<div>{{ prevWord.name }}</div>
|
||||
<div v-show="settingStore.translate">{{ prevWord.trans.join(';') }}</div>
|
||||
</div>
|
||||
<Icon class="arrow" icon="bi:arrow-left" width="22"/>
|
||||
<div class="word">{{ prevWord.name }}</div>
|
||||
</div>
|
||||
<Tooltip title="快捷键:Tab">
|
||||
<div class="next"
|
||||
@click="next(false)"
|
||||
v-if="nextWord">
|
||||
<div class="word">
|
||||
<div :class="settingStore.dictation && 'shadow'">{{ nextWord.name }}</div>
|
||||
<div v-show="settingStore.translate">{{ nextWord.trans.join(';') }}</div>
|
||||
</div>
|
||||
<Icon icon="bi:arrow-right" width="22"/>
|
||||
<div class="word" :class="settingStore.dictation && 'shadow'">{{ nextWord.name }}</div>
|
||||
<Icon class="arrow" icon="bi:arrow-right" width="22"/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
@@ -329,7 +312,7 @@ useOnKeyboardEventListener(onKeyDown, onKeyUp)
|
||||
opacity: settingStore.translate ? 1 : 0
|
||||
}"
|
||||
>
|
||||
<div v-for="i in word.trans">{{i}}</div>
|
||||
<div v-for="i in word.trans">{{ i }}</div>
|
||||
</div>
|
||||
<div class="word-wrapper">
|
||||
<div class="word"
|
||||
@@ -351,21 +334,27 @@ useOnKeyboardEventListener(onKeyDown, onKeyUp)
|
||||
</div>
|
||||
<div class="phonetic">{{ settingStore.wordSoundType === 'us' ? word.usphone : word.ukphone }}</div>
|
||||
<div class="options">
|
||||
<BaseButton keyboard="`"
|
||||
@click="remove"
|
||||
:active="activeBtnIndex === 0">
|
||||
忽略
|
||||
</BaseButton>
|
||||
<BaseButton keyboard="Enter"
|
||||
@click="collect"
|
||||
:active="activeBtnIndex === 1">
|
||||
收藏
|
||||
</BaseButton>
|
||||
<BaseButton keyboard="Tab"
|
||||
@click="ignore"
|
||||
:active="activeBtnIndex === 2">
|
||||
跳过
|
||||
</BaseButton>
|
||||
<Tooltip title="忽略(快捷键:`)">
|
||||
<IconWrapper>
|
||||
<Icon icon="fluent:delete-20-regular" class="menu"
|
||||
:active="activeBtnIndex === 0"
|
||||
@click="remove"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<Tooltip title="收藏(快捷键:Enter)">
|
||||
<IconWrapper>
|
||||
<Icon icon="ph:star" class="menu"
|
||||
@click="collect"
|
||||
:active="activeBtnIndex === 1"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<Tooltip title="跳过(快捷键:Tab)">
|
||||
<IconWrapper>
|
||||
<Icon icon="icon-park-outline:go-ahead" class="menu"
|
||||
@click="ignore"
|
||||
:active="activeBtnIndex === 2"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Panel :list="data.words" v-model:index="data.index"/>
|
||||
</div>
|
||||
@@ -392,35 +381,35 @@ useOnKeyboardEventListener(onKeyDown, onKeyUp)
|
||||
top: 0;
|
||||
width: 100%;
|
||||
|
||||
.word {
|
||||
div {
|
||||
font-size: 24rem;
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
& > div {
|
||||
width: 45%;
|
||||
align-items: center;
|
||||
|
||||
div:last-child {
|
||||
font-size: 14rem;
|
||||
.arrow {
|
||||
min-width: 22rem;
|
||||
min-height: 22rem;
|
||||
}
|
||||
}
|
||||
|
||||
.word {
|
||||
font-size: 24rem;
|
||||
margin-bottom: 4rem;
|
||||
}
|
||||
|
||||
|
||||
.prev {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
float: left;
|
||||
align-items: center;
|
||||
gap: 10rem;
|
||||
}
|
||||
|
||||
.next {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 10rem;
|
||||
float: right;
|
||||
|
||||
.word {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.shadow {
|
||||
@@ -437,7 +426,7 @@ useOnKeyboardEventListener(onKeyDown, onKeyUp)
|
||||
font-size: 18rem;
|
||||
}
|
||||
|
||||
.phonetic, .translate {
|
||||
.phonetic, .translate, .options {
|
||||
font-size: 20rem;
|
||||
margin-left: -30rem;
|
||||
transition: all .3s;
|
||||
|
||||
@@ -36,7 +36,7 @@ watch(() => props.groupByTag, () => {
|
||||
</div>
|
||||
<div class="dict-list">
|
||||
<div class="dict-item anim"
|
||||
:class="selectDictName === i.name && 'active'"
|
||||
:class="selectDictName === i.id && 'active'"
|
||||
@click="emit('selectDict',i)"
|
||||
v-for="i in list"
|
||||
>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import {dictionaryResources} from '@/assets/dictionary.ts'
|
||||
import {useBaseStore} from "@/stores/base.ts"
|
||||
import {watch} from "vue"
|
||||
import {Dict, DictResource, DictType, languageCategoryOptions, Sort, Word} from "@/types.ts"
|
||||
import {DefaultDict, Dict, DictResource, DictType, languageCategoryOptions, Sort, Word} from "@/types.ts"
|
||||
import {chunk, cloneDeep, groupBy} from "lodash-es";
|
||||
import {$computed, $ref} from "vue/macros";
|
||||
import Modal from "@/components/Modal/Modal.vue";
|
||||
@@ -56,48 +56,34 @@ watch(() => props.modelValue, (n: boolean) => {
|
||||
})
|
||||
|
||||
async function selectDict(item: DictResource) {
|
||||
console.log('item',item)
|
||||
console.log('item', item)
|
||||
step = 1
|
||||
let find = base.myDicts.find((v: Dict) => v.name === item.name)
|
||||
if (find) {
|
||||
runtimeStore.editDict = cloneDeep(find)
|
||||
} else {
|
||||
let data = {
|
||||
sort: Sort.normal,
|
||||
type: DictType.publicDict,
|
||||
originWords: [],
|
||||
words: [],
|
||||
chapterWordNumber: 30,
|
||||
chapterWords: [],
|
||||
chapterIndex: 0,
|
||||
chapterWordIndex: 0,
|
||||
statistics: [],
|
||||
articles: [],
|
||||
let data: Dict = {
|
||||
...DefaultDict,
|
||||
...item,
|
||||
}
|
||||
|
||||
if (item.resourceType === 'article') {
|
||||
data.type = DictType.publicArticle
|
||||
let r = await fetch(`/dicts/${item.language}/${item.resourceType}/${item.translateLanguage}/${item.url}`)
|
||||
r.json().then(v => {
|
||||
console.log('v', v)
|
||||
data.articles = cloneDeep(v.map(v => {
|
||||
v.id = uuidv4()
|
||||
return v
|
||||
let r = await fetch(`./dicts/${data.language}/${data.type}/${data.translateLanguage}/${item.url}`)
|
||||
r.json().then(v => {
|
||||
console.log('v', v)
|
||||
if (data.type === DictType.article) {
|
||||
data.articles = cloneDeep(v.map(s => {
|
||||
s.id = uuidv4()
|
||||
return s
|
||||
}))
|
||||
runtimeStore.editDict = cloneDeep(data)
|
||||
})
|
||||
} else {
|
||||
data.type = DictType.publicDict
|
||||
let r = await fetch(`/dicts/${item.language}/${item.resourceType}/${item.translateLanguage}/${item.url}`)
|
||||
r.json().then(v => {
|
||||
} else {
|
||||
data.originWords = v
|
||||
data.words = v
|
||||
data.chapterWords = chunk(v, data.chapterWordNumber)
|
||||
runtimeStore.editDict = cloneDeep(data)
|
||||
console.log(' runtimeStore.editDict', runtimeStore.editDict)
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +116,7 @@ function groupByDictTags(dictList: DictResource[]) {
|
||||
const groupByTranslateLanguage = $computed(() => {
|
||||
let data: any
|
||||
if (currentLanguage === 'article') {
|
||||
let articleList = dictionaryResources.filter(v => v.resourceType === 'article')
|
||||
let articleList = dictionaryResources.filter(v => v.type === 'article')
|
||||
data = groupBy(articleList, 'translateLanguage')
|
||||
} else {
|
||||
data = groupBy(groupByLanguage[currentLanguage], 'translateLanguage')
|
||||
@@ -191,12 +177,12 @@ const dictIsArticle = $computed(() => {
|
||||
<div class="translate">
|
||||
<span>翻译:</span>
|
||||
<el-radio-group v-model="currentTranslateLanguage">
|
||||
<el-radio v-for="i in translateLanguageList" :label="i">{{ i }}</el-radio>
|
||||
<el-radio border v-for="i in translateLanguageList" :label="i">{{ i }}</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<DictGroup
|
||||
v-for="item in groupedByCategoryAndTag"
|
||||
:select-dict-name="runtimeStore.editDict.name"
|
||||
:select-dict-name="runtimeStore.editDict.resourceId"
|
||||
@selectDict="selectDict"
|
||||
@detail="step = 1"
|
||||
:groupByTag="item[1]"
|
||||
|
||||
@@ -47,44 +47,54 @@ watch(() => settingStore.showToolbar, n => {
|
||||
{{ store.dictTitle }} {{ practiceStore.repeatNumber ? ' 复习错词' : '' }}
|
||||
</div>
|
||||
<div class="options">
|
||||
<Tooltip title="开关默写模式">
|
||||
<Tooltip title="收起图标">
|
||||
<IconWrapper>
|
||||
<Icon icon="majesticons:eye-off-line"
|
||||
v-if="settingStore.dictation"
|
||||
@click="settingStore.dictation = false"/>
|
||||
<Icon icon="mdi:eye-outline"
|
||||
v-else
|
||||
@click="settingStore.dictation = true"/>
|
||||
<Icon :icon="`system-uicons:window-collapse-${settingStore.collapse?'left':'right'}`"
|
||||
@click="settingStore.collapse = !settingStore.collapse"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
|
||||
<TranslateSetting/>
|
||||
<div class="more" v-if="!settingStore.collapse">
|
||||
<Tooltip title="开关默写模式">
|
||||
<IconWrapper>
|
||||
<Icon icon="majesticons:eye-off-line"
|
||||
v-if="settingStore.dictation"
|
||||
@click="settingStore.dictation = false"/>
|
||||
<Icon icon="mdi:eye-outline"
|
||||
v-else
|
||||
@click="settingStore.dictation = true"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
|
||||
<VolumeSetting/>
|
||||
<TranslateSetting/>
|
||||
|
||||
<RepeatSetting/>
|
||||
<VolumeSetting/>
|
||||
|
||||
<Add/>
|
||||
<RepeatSetting/>
|
||||
|
||||
<Add/>
|
||||
|
||||
<Tooltip title="反馈">
|
||||
<IconWrapper>
|
||||
<Icon icon="octicon:bug-24" @click="showFeedbackModal = true"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="切换主题">
|
||||
<IconWrapper>
|
||||
<Icon icon="ep:moon" v-if="settingStore.theme === 'dark'"
|
||||
@click="toggle"/>
|
||||
<Icon icon="tabler:sun" v-else @click="toggle"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<Tooltip title="反馈">
|
||||
<IconWrapper>
|
||||
<Icon icon="octicon:bug-24" @click="showFeedbackModal = true"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<Tooltip title="设置">
|
||||
<IconWrapper>
|
||||
<Icon icon="uil:setting" @click="showSettingModal = true"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<!-- <div class="base-button" @click="emitter.emit(EventKey.openStatModal)">ok</div>-->
|
||||
|
||||
<Tooltip title="切换主题">
|
||||
<IconWrapper>
|
||||
<Icon icon="ep:moon" v-if="settingStore.theme === 'dark'"
|
||||
@click="toggle"/>
|
||||
<Icon icon="tabler:sun" v-else @click="toggle"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<!-- <div class="base-button" @click="emitter.emit(EventKey.openStatModal)">ok</div>-->
|
||||
|
||||
<Tooltip title="单词本">
|
||||
<IconWrapper>
|
||||
@@ -152,6 +162,14 @@ header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rem;
|
||||
|
||||
.more {
|
||||
display: flex;
|
||||
gap: 10rem;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
transition: all .3s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@ export function getSplitTranslateText(article: string) {
|
||||
|
||||
export function isArticle(type: DictType): boolean {
|
||||
return [
|
||||
DictType.publicArticle,
|
||||
DictType.article,
|
||||
DictType.customArticle
|
||||
].includes(type)
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
import {defineStore} from 'pinia'
|
||||
import {Dict, DictType, DisplayStatistics, SaveDictKey, Sort, Statistics, Word} from "../types.ts"
|
||||
import {DefaultDict, Dict, DictType, DisplayStatistics, SaveDictKey, Sort, Statistics, Word} from "../types.ts"
|
||||
import {chunk, cloneDeep} from "lodash-es";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts"
|
||||
import {v4 as uuidv4} from 'uuid';
|
||||
|
||||
export interface State {
|
||||
newWordDict: Dict,
|
||||
skipWordDict: Dict,
|
||||
wrongWordDict: Dict,
|
||||
new: Dict,
|
||||
skip: Dict,
|
||||
wrong: Dict,
|
||||
myDicts: Dict[],
|
||||
current: {
|
||||
dictType: DictType,
|
||||
@@ -22,131 +22,87 @@ export interface State {
|
||||
export const useBaseStore = defineStore('base', {
|
||||
state: (): State => {
|
||||
return {
|
||||
newWordDict: {
|
||||
id: 'newWordDict',
|
||||
new: {
|
||||
...DefaultDict,
|
||||
id: 'new',
|
||||
name: '生词本',
|
||||
sort: Sort.normal,
|
||||
type: DictType.newWordDict,
|
||||
originWords: [],
|
||||
articles: [],
|
||||
words: [],
|
||||
chapterWordNumber: 15,
|
||||
chapterWords: [],
|
||||
chapterIndex: 0,
|
||||
chapterWordIndex: 0,
|
||||
statistics: [],
|
||||
url: '',
|
||||
type: DictType.new,
|
||||
},
|
||||
skipWordDict: {
|
||||
id: 'skipWordDict',
|
||||
skip: {
|
||||
...DefaultDict,
|
||||
id: 'skip',
|
||||
name: '简单词',
|
||||
sort: Sort.normal,
|
||||
type: DictType.skipWordDict,
|
||||
originWords: [],
|
||||
articles: [],
|
||||
words: [],
|
||||
chapterWordNumber: 15,
|
||||
chapterWords: [],
|
||||
chapterIndex: 0,
|
||||
chapterWordIndex: 0,
|
||||
statistics: [],
|
||||
url: '',
|
||||
type: DictType.skip,
|
||||
},
|
||||
wrongWordDict: {
|
||||
id: 'wrongWordDict',
|
||||
wrong: {
|
||||
...DefaultDict,
|
||||
id: 'wrong',
|
||||
name: '错词本',
|
||||
sort: Sort.normal,
|
||||
type: DictType.wrongWordDict,
|
||||
originWords: [],
|
||||
articles: [],
|
||||
words: [],
|
||||
chapterWordNumber: 15,
|
||||
chapterWords: [],
|
||||
chapterIndex: 0,
|
||||
chapterWordIndex: 0,
|
||||
statistics: [],
|
||||
url: '',
|
||||
type: DictType.wrong,
|
||||
},
|
||||
myDicts: [
|
||||
{
|
||||
...DefaultDict,
|
||||
id: '新概念英语2-课文',
|
||||
name: '新概念英语2-课文',
|
||||
sort: Sort.normal,
|
||||
type: DictType.publicArticle,
|
||||
originWords: [],
|
||||
articles: [],
|
||||
words: [],
|
||||
chapterWordNumber: 15,
|
||||
chapterWords: [],
|
||||
chapterIndex: 0,
|
||||
chapterWordIndex: 0,
|
||||
statistics: [],
|
||||
type: DictType.article,
|
||||
url: 'NCE_2.json',
|
||||
translateLanguage: 'common',
|
||||
language: 'en',
|
||||
resourceType: "article"
|
||||
},
|
||||
{
|
||||
...DefaultDict,
|
||||
id: '新概念英语2',
|
||||
name: '新概念英语2',
|
||||
sort: Sort.normal,
|
||||
type: DictType.publicDict,
|
||||
originWords: [],
|
||||
articles: [],
|
||||
words: [],
|
||||
chapterWordNumber: 15,
|
||||
chapterWords: [],
|
||||
chapterIndex: 0,
|
||||
chapterWordIndex: 0,
|
||||
statistics: [],
|
||||
type: DictType.word,
|
||||
url: 'nce-new-2.json',
|
||||
resourceId: 'nce-new-2',
|
||||
translateLanguage: 'common',
|
||||
language: 'en',
|
||||
resourceType: "word"
|
||||
}
|
||||
],
|
||||
current: {
|
||||
dictType: DictType.publicDict,
|
||||
dictType: DictType.word,
|
||||
// dictType: DictType.publicArticle,
|
||||
index: 1,
|
||||
editIndex: 0,
|
||||
repeatNumber: 0,
|
||||
},
|
||||
simpleWords: [
|
||||
'a', 'an', 'of', 'and',
|
||||
'i', 'my', 'you', 'your',
|
||||
'me', 'am', 'is', 'do', 'are',
|
||||
'a', 'an',
|
||||
'i', 'my', 'you', 'your', 'me', 'it',
|
||||
'am', 'is', 'do', 'are', 'did', 'were',
|
||||
'what', 'who', 'where', 'how', 'no', 'yes',
|
||||
'not', 'did', 'were', 'can', 'could', 'it',
|
||||
'the', 'to'
|
||||
'not', 'can', 'could',
|
||||
'the', 'to', 'of', 'for', 'and', 'that', 'this','be'
|
||||
],
|
||||
load: false
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
skipWordNames: (state: State) => {
|
||||
return state.skipWordDict.originWords.map(v => v.name.toLowerCase())
|
||||
return state.skip.originWords.map(v => v.name.toLowerCase())
|
||||
},
|
||||
skipWordNamesWithSimpleWords: (state: State) => {
|
||||
return state.skipWordDict.originWords.map(v => v.name.toLowerCase()).concat(state.simpleWords)
|
||||
return state.skip.originWords.map(v => v.name.toLowerCase()).concat(state.simpleWords)
|
||||
},
|
||||
isArticle(state: State): boolean {
|
||||
return [
|
||||
DictType.publicArticle,
|
||||
DictType.article,
|
||||
DictType.customArticle
|
||||
].includes(state.current.dictType)
|
||||
},
|
||||
currentDict(state: State): Dict {
|
||||
switch (state.current.dictType) {
|
||||
case DictType.newWordDict:
|
||||
return state.newWordDict
|
||||
case DictType.skipWordDict:
|
||||
return state.skipWordDict
|
||||
case DictType.wrongWordDict:
|
||||
return state.wrongWordDict
|
||||
case DictType.publicDict:
|
||||
case DictType.publicArticle:
|
||||
case DictType.customDict:
|
||||
case DictType.new:
|
||||
return state.new
|
||||
case DictType.skip:
|
||||
return state.skip
|
||||
case DictType.wrong:
|
||||
return state.wrong
|
||||
case DictType.word:
|
||||
case DictType.article:
|
||||
case DictType.customWord:
|
||||
case DictType.customArticle:
|
||||
return this.myDicts[this.current.index]
|
||||
}
|
||||
@@ -166,7 +122,7 @@ export const useBaseStore = defineStore('base', {
|
||||
},
|
||||
dictTitle(state: State) {
|
||||
let title = this.currentDict.name
|
||||
if ([DictType.publicDict, DictType.customDict].includes(this.current.dictType)) {
|
||||
if ([DictType.word, DictType.customWord].includes(this.current.dictType)) {
|
||||
title += ` 第${this.currentDict.chapterIndex + 1}章`
|
||||
}
|
||||
return title
|
||||
@@ -187,52 +143,54 @@ export const useBaseStore = defineStore('base', {
|
||||
}
|
||||
|
||||
if ([
|
||||
DictType.newWordDict,
|
||||
DictType.wrongWordDict,
|
||||
DictType.skipWordDict,
|
||||
DictType.new,
|
||||
DictType.wrong,
|
||||
DictType.skip,
|
||||
].includes(this.current.dictType)) {
|
||||
|
||||
} else {
|
||||
if ([
|
||||
DictType.publicDict,
|
||||
DictType.customDict,
|
||||
DictType.word,
|
||||
DictType.customWord,
|
||||
].includes(this.current.dictType)) {
|
||||
if (!this.currentDict.originWords.length) {
|
||||
let r = await fetch(`./dicts/${this.currentDict.language}/${this.currentDict.resourceType}/${this.currentDict.translateLanguage}/${this.currentDict.url}`)
|
||||
// let r = await fetch(`.${this.currentDict.url}`)
|
||||
let r = await fetch(`./dicts/${this.currentDict.language}/${this.currentDict.type}/${this.currentDict.translateLanguage}/${this.currentDict.url}`)
|
||||
// let r = await fetch(`.${this.currentDict.url}`)0
|
||||
r.json().then(v => {
|
||||
fetch('./translate/en2zh_CN.json').then(r => {
|
||||
r.json().then((list: Word[]) => {
|
||||
console.log('list', list)
|
||||
console.time()
|
||||
if (this.currentDict.translateLanguage === 'common'){
|
||||
fetch('./translate/en2zh_CN.json').then(r => {
|
||||
r.json().then((list: Word[]) => {
|
||||
console.time()
|
||||
|
||||
v.map((w: Word) => {
|
||||
let res = list.find(a => a.name === w.name)
|
||||
if (res) {
|
||||
w = Object.assign(w, res)
|
||||
}
|
||||
return w
|
||||
v.map((w: Word) => {
|
||||
let res = list.find(a => a.name === w.name)
|
||||
if (res) w = Object.assign(w, res)
|
||||
})
|
||||
|
||||
this.currentDict.originWords = cloneDeep(v)
|
||||
this.currentDict.words = cloneDeep(v)
|
||||
this.currentDict.chapterWords = chunk(this.currentDict.words, this.currentDict.chapterWordNumber)
|
||||
this.load = true
|
||||
|
||||
console.timeEnd()
|
||||
})
|
||||
console.log('v', v)
|
||||
|
||||
this.currentDict.originWords = cloneDeep(v)
|
||||
this.currentDict.words = cloneDeep(v)
|
||||
this.currentDict.chapterWords = chunk(this.currentDict.words, this.currentDict.chapterWordNumber)
|
||||
this.load = true
|
||||
|
||||
console.timeEnd()
|
||||
})
|
||||
})
|
||||
}else{
|
||||
this.currentDict.originWords = cloneDeep(v)
|
||||
this.currentDict.words = cloneDeep(v)
|
||||
this.currentDict.chapterWords = chunk(this.currentDict.words, this.currentDict.chapterWordNumber)
|
||||
this.load = true
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if ([
|
||||
DictType.publicArticle,
|
||||
DictType.article,
|
||||
DictType.customArticle,
|
||||
].includes(this.current.dictType)) {
|
||||
if (!this.currentDict.articles.length) {
|
||||
let r = await fetch(`./dicts/${this.currentDict.language}/${this.currentDict.resourceType}/${this.currentDict.translateLanguage}/${this.currentDict.url}`)
|
||||
let r = await fetch(`./dicts/${this.currentDict.language}/${this.currentDict.type}/${this.currentDict.translateLanguage}/${this.currentDict.url}`)
|
||||
r.json().then((v: any[]) => {
|
||||
this.currentDict.articles = cloneDeep(v.map(v => {
|
||||
v.id = uuidv4()
|
||||
@@ -255,9 +213,9 @@ export const useBaseStore = defineStore('base', {
|
||||
// this.saveStatistics()
|
||||
console.log('changeDict', cloneDeep(dict), chapterIndex, chapterWordIndex)
|
||||
this.current.dictType = dict.type
|
||||
if ([DictType.newWordDict,
|
||||
DictType.skipWordDict,
|
||||
DictType.wrongWordDict].includes(dict.type)) {
|
||||
if ([DictType.new,
|
||||
DictType.skip,
|
||||
DictType.wrong].includes(dict.type)) {
|
||||
this[dict.type].chapterIndex = chapterIndex
|
||||
this[dict.type].chapterWordIndex = chapterWordIndex
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {defineStore} from "pinia"
|
||||
import {Dict, DictType, Sort} from "@/types.ts";
|
||||
import {DefaultDict, Dict, DictType, Sort} from "@/types.ts";
|
||||
|
||||
export interface RuntimeState {
|
||||
disableEventListener: boolean,
|
||||
@@ -12,20 +12,7 @@ export const useRuntimeStore = defineStore('runtime', {
|
||||
return {
|
||||
disableEventListener: false,
|
||||
modalList: [],
|
||||
editDict: {
|
||||
name: '',
|
||||
sort: Sort.normal,
|
||||
type: DictType.publicArticle,
|
||||
originWords: [],
|
||||
articles: [],
|
||||
words: [],
|
||||
chapterWordNumber: 15,
|
||||
chapterWords: [],
|
||||
chapterIndex: 0,
|
||||
chapterWordIndex: 0,
|
||||
statistics: [],
|
||||
url: '',
|
||||
},
|
||||
editDict: {...DefaultDict},
|
||||
}
|
||||
},
|
||||
})
|
||||
@@ -32,6 +32,7 @@ export interface SettingState {
|
||||
},
|
||||
showPanel: boolean,
|
||||
theme: string,
|
||||
collapse: boolean,
|
||||
}
|
||||
|
||||
export const useSettingStore = defineStore('setting', {
|
||||
@@ -70,6 +71,7 @@ export const useSettingStore = defineStore('setting', {
|
||||
waitTimeForChangeWord: 300,
|
||||
|
||||
theme: 'auto',
|
||||
collapse:false,
|
||||
}
|
||||
},
|
||||
})
|
||||
46
src/types.ts
46
src/types.ts
@@ -1,7 +1,7 @@
|
||||
import bookFlag from "@/assets/img/flags/book.png";
|
||||
import enFlag from "@/assets/img/flags/en.png";
|
||||
import jpFlag from "@/assets/img/flags/ja.png";
|
||||
import deFlag from "@/assets/img/flags/de.png";
|
||||
import deFlag from "./assets/img/flags/de.png";
|
||||
import codeFlag from "@/assets/img/flags/code.png";
|
||||
|
||||
export type Word = {
|
||||
@@ -25,7 +25,6 @@ export const PronunciationApi = 'https://dict.youdao.com/dictvoice?audio='
|
||||
|
||||
export type TranslateLanguageType = 'en' | 'zh-CN' | 'ja' | 'de' | 'common' | ''
|
||||
export type LanguageType = 'en' | 'ja' | 'de' | 'code'
|
||||
export type ResourceType = 'word' | 'article'
|
||||
|
||||
export type DictResource = {
|
||||
id: string
|
||||
@@ -36,7 +35,7 @@ export type DictResource = {
|
||||
url: string
|
||||
length: number
|
||||
translateLanguage: TranslateLanguageType
|
||||
resourceType: ResourceType
|
||||
type: DictType
|
||||
language: LanguageType
|
||||
}
|
||||
|
||||
@@ -44,25 +43,29 @@ export interface Dict {
|
||||
id: string,
|
||||
name: string,
|
||||
sort: Sort,
|
||||
type: DictType,
|
||||
originWords: Word[],//原始单词
|
||||
words: Word[],
|
||||
chapterWordNumber: number,//章节单词数量
|
||||
chapterWords: Word[][],
|
||||
chapterIndex: number,//章节下标
|
||||
wordIndex: number,//单词下标
|
||||
articles: Article[],
|
||||
chapterIndex: number,
|
||||
chapterWordIndex: number,
|
||||
statistics: Statistics[],
|
||||
resourceId: string,
|
||||
type: DictType,
|
||||
translateLanguage: TranslateLanguageType
|
||||
language: LanguageType
|
||||
url: string,
|
||||
}
|
||||
|
||||
|
||||
export enum DictType {
|
||||
newWordDict = 'newWordDict',
|
||||
skipWordDict = 'skipWordDict',
|
||||
wrongWordDict = 'wrongWordDict',
|
||||
publicDict = 'publicDict',
|
||||
customDict = 'customDict',
|
||||
publicArticle = 'publicArticle',
|
||||
new = 'new',
|
||||
skip = 'skip',
|
||||
wrong = 'wrong',
|
||||
word = 'word',
|
||||
customWord = 'customWord',
|
||||
article = 'article',
|
||||
customArticle = 'customArticle'
|
||||
}
|
||||
|
||||
@@ -172,3 +175,22 @@ export const languageCategoryOptions = [
|
||||
{id: 'de', name: '德语', flag: deFlag},
|
||||
{id: 'code', name: 'Code', flag: codeFlag},
|
||||
]
|
||||
|
||||
export const DefaultDict: Dict = {
|
||||
id: '',
|
||||
name: '',
|
||||
sort: Sort.normal,
|
||||
originWords: [],//原始单词
|
||||
words: [],
|
||||
chapterWordNumber: 30,//章节单词数量
|
||||
chapterWords: [],
|
||||
chapterIndex: 0,//章节下标
|
||||
wordIndex: 0,//单词下标
|
||||
articles: [],
|
||||
statistics: [],
|
||||
resourceId: '',
|
||||
type: DictType.word,
|
||||
translateLanguage: 'common',
|
||||
language: 'en',
|
||||
url: '',
|
||||
}
|
||||
23
src/vite-env.d.ts
vendored
23
src/vite-env.d.ts
vendored
@@ -1,11 +1,11 @@
|
||||
import {ElMessageBox} from "element-plus";
|
||||
|
||||
/// <reference types="vite/client" />
|
||||
/// <reference types="vue/macros-global" />
|
||||
|
||||
// declare module '*.json' {
|
||||
// const src: string
|
||||
// export default src
|
||||
// }
|
||||
|
||||
declare const LATEST_COMMIT_HASH: string
|
||||
|
||||
declare module '*.mp3' {
|
||||
@@ -17,10 +17,16 @@ declare module '*.wav' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
declare module '*.png' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module "*.png";
|
||||
declare module "*.svg";
|
||||
declare module "*.jpeg";
|
||||
declare module "*.jpg";
|
||||
|
||||
// declare module '*.png' {
|
||||
// const src: string;
|
||||
// export default src;
|
||||
// }
|
||||
|
||||
declare module "*.vue" {
|
||||
import type {DefineComponent} from 'vue'
|
||||
@@ -33,7 +39,7 @@ declare module "*.vue" {
|
||||
// export default Vue
|
||||
// }
|
||||
|
||||
declare module '*.ts';
|
||||
// declare module '*.ts';
|
||||
|
||||
// declare global {
|
||||
// interface Window {
|
||||
@@ -42,3 +48,6 @@ declare module '*.ts';
|
||||
// }
|
||||
|
||||
declare var ElMessageBox: ElMessageBox;
|
||||
|
||||
/// <reference types="vite/client" />
|
||||
/// <reference types="vue/macros-global" />
|
||||
@@ -28,6 +28,7 @@
|
||||
],
|
||||
"types": [
|
||||
"vue/ref-macros",
|
||||
"vite/client",
|
||||
"element-plus/global"
|
||||
],
|
||||
"baseUrl": "src",
|
||||
@@ -41,9 +42,10 @@
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"src",
|
||||
"src/**/*.ts",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.vue",
|
||||
"auto-imports.d.ts",
|
||||
"src/vite-env.d.ts"
|
||||
|
||||
Reference in New Issue
Block a user