This commit is contained in:
zyronon
2023-10-23 18:58:33 +08:00
parent 5922475b33
commit 9c6151f5b7
15 changed files with 478 additions and 503 deletions

View File

@@ -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>

View File

@@ -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())) {

View File

@@ -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;

View File

@@ -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"
>

View File

@@ -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]"

View File

@@ -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;
}
}
}