This commit is contained in:
zyronon
2023-11-09 18:57:34 +08:00
parent 3c60cf521b
commit a4b466eaff
8 changed files with 115 additions and 89 deletions

3
components.d.ts vendored
View File

@@ -24,6 +24,9 @@ declare module 'vue' {
EditArticle: typeof import('./src/components/Article/EditArticle.vue')['default']
EditBatchArticleModal: typeof import('./src/components/Article/EditBatchArticleModal.vue')['default']
EditSingleArticleModal: typeof import('./src/components/Article/EditSingleArticleModal.vue')['default']
ElButton: typeof import('element-plus/es')['ElButton']
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElOption: typeof import('element-plus/es')['ElOption']

View File

@@ -38,7 +38,7 @@ watch(store.wrong.originWords, (n) => {
store.wrong.chapterWords = [store.wrong.words]
})
useStartKeyboardEventListener()
// useStartKeyboardEventListener()
async function init() {
console.time()

View File

@@ -9,7 +9,7 @@ import {useBaseStore} from "@/stores/base.ts";
import {useSettingStore} from "@/stores/setting.ts";
import {useRuntimeStore} from "@/stores/runtime.ts";
import {useDisableEventListener} from "@/hooks/event.ts";
import {Dict, DictType, languageCategoryOptions, Sort, Word} from "@/types.ts";
import {DefaultDict, Dict, DictType, languageCategoryOptions, Sort, Word} from "@/types.ts";
import {onMounted, reactive, watch} from "vue";
import {FormInstance, FormRules} from "element-plus";
import {dictionaryResources} from "@/assets/dictionary.ts";
@@ -39,12 +39,11 @@ let step = $ref(1)
let isAddDict = $ref(false)
let list = $computed(() => {
return store.myDicts.filter(v => v.type === DictType.customArticle)
.concat([
store.simple,
store.wrong,
store.collect
])
return [
store.collect,
store.simple,
store.wrong
].concat(store.myDicts.filter(v => v.type === DictType.customArticle))
.concat([{name: '',} as any])
})
@@ -99,9 +98,11 @@ onMounted(() => {
console.log('tagList', tagList)
})
function selectDict(dict: Dict) {
// runtimeStore.editDict = cloneDeep(dict)
runtimeStore.editDict = dict
function selectDict(val: {
dict: Dict,
index: number
}) {
store.current.editIndex = val.index
isAddDict = false
step = 1
}
@@ -109,31 +110,20 @@ function selectDict(dict: Dict) {
async function onSubmit() {
await dictFormRef.validate((valid, fields) => {
if (valid) {
let data = {
sort: Sort.normal,
type: DictType.customArticle,
originWords: [],
words: [],
chapterWordNumber: 30,
chapterWords: [],
chapterIndex: 0,
chapterWordIndex: 0,
statistics: [],
articles: [],
url: '',
let data: Dict = {
...DefaultDict,
...dictForm,
}
if (dictForm.id) {
let rIndex = store.myDicts.findIndex(v => v.id === dictForm.id)
runtimeStore.editDict = data
store.myDicts[rIndex] = cloneDeep(data)
isAddDict = false
} else {
if (store.myDicts.find(v => v.name === dictForm.name)) {
return ElMessage.warning('已有相同名称词典!')
} else {
runtimeStore.editDict = data
store.myDicts.push(cloneDeep(data))
store.current.editIndex = store.myDicts.length - 1
isAddDict = false
console.log('submit!', data)
}
@@ -145,8 +135,8 @@ async function onSubmit() {
}
function editDict() {
dictForm.name = runtimeStore.editDict.name
dictForm.description = runtimeStore.editDict.description
dictForm.name = store.editDict.name
dictForm.description = store.editDict.description
wordFormMode = FormMode.None;
isAddDict = true
}
@@ -171,23 +161,30 @@ const wordRules = reactive<FormRules>({
{max: 30, message: '名称不能超过30个字符', trigger: 'blur'},
],
})
let wordListRef: any = $ref()
async function onSubmitWord() {
await wordFormRef.validate((valid, fields) => {
if (valid) {
if (wordFormMode === FormMode.Add) {
if (runtimeStore.editDict.originWords.find(v => v.name === wordForm.name)) {
if (store.editDict.originWords.find(v => v.name === wordForm.name)) {
return ElMessage.warning('已有相同名称单词!')
} else {
// let list = cloneDeep(store.editDict.originWords)
let data: any = cloneDeep(wordForm)
if (data.trans) {
data.trans = data.trans.split('\n');
} else {
data.trans = []
}
runtimeStore.editDict.originWords.push(data)
store.editDict.originWords.push(data)
console.log('wordListRef',wordListRef)
wordListRef?.reset()
// store.editDict.originWords = list
//因为虚拟列表,必须重新赋值才能检测到更新
// store.editDict.originWords = cloneDeep(store.editDict.originWords)
}
console.log('runtimeStore.editDict', runtimeStore.editDict)
console.log('store.editDict', store.editDict)
}
} else {
ElMessage.warning('请填写完整')
@@ -245,10 +242,10 @@ const {
<div class="detail" v-if="!isAddDict">
<div class="dict">
<div class="info">
<div class="name">{{ runtimeStore.editDict.name }}</div>
<div class="desc">{{ runtimeStore.editDict.description }}</div>
<div class="name">{{ store.editDict.name }}</div>
<div class="desc">{{ store.editDict.description }}</div>
<div class="more-info">
<div class="item">词汇量{{ runtimeStore.editDict.originWords.length }}</div>
<div class="item">词汇量{{ store.editDict.originWords.length }}</div>
<div class="item">创建日期-</div>
<div class="item">花费时间-</div>
<div class="item">累积错误-</div>
@@ -293,25 +290,19 @@ const {
<div class="list-header">
<div class="name">单词列表</div>
<div class="flex-center gap10">
<div class="name">{{ store.currentDict.originWords.length }}个单词</div>
<div class="name">{{ store.editDict.originWords.length }}个单词</div>
<BaseIcon icon="mi:add"
@click='wordFormMode = FormMode.Add'
/>
</div>
</div>
<!-- <WordList-->
<!-- v-if="runtimeStore.editDict.originWords.length"-->
<!-- class="word-list"-->
<!-- :is-active="true"-->
<!-- @change="(i:number) => data.index = i"-->
<!-- :list="runtimeStore.editDict.originWords"-->
<!-- :activeIndex="data.index"/>-->
<WordList2
v-if="store.currentDict.words.length"
ref="wordListRef"
v-if="store.editDict.originWords.length"
class="word-list"
:is-active="true"
@change="(i:number) => data.index = i"
:list="store.currentDict.words"
:list="store.editDict.originWords"
:activeIndex="data.index">
<template v-slot="{word}">
<BaseIcon

View File

@@ -158,7 +158,7 @@ onUnmounted(() => {
<PracticeWord ref="practiceRef" v-else/>
<Footer/>
</div>
<!-- <AddWordDialog></AddWordDialog>-->
<AddWordDialog></AddWordDialog>
<DictModal :model-value="runtimeStore.showDictModal" @close="runtimeStore.showDictModal = false"/>
<SettingModal v-if="runtimeStore.showSettingModal" @close="runtimeStore.showSettingModal = false"/>
<Statistics/>

View File

@@ -8,7 +8,7 @@ const props = defineProps<{
}>()
const emit = defineEmits<{
selectDict: [val: Dict]
selectDict: [val: { dict: Dict, index: number }]
detail: [],
add: []
}>()
@@ -17,17 +17,17 @@ const emit = defineEmits<{
<template>
<div class="dict-list">
<template v-for="i in list">
<template v-for="(dict,index) in list">
<div class="dict-item anim"
:class="selectDictName === i.name && 'active'"
@click="emit('selectDict',i)"
v-if="i.name"
:class="selectDictName === dict.name && 'active'"
@click="emit('selectDict',{dict,index})"
v-if="dict.name"
>
<div class="name">{{ i.name }}</div>
<div class="desc">{{ i.description }}</div>
<div class="num">{{ i.length }}</div>
<div class="name">{{ dict.name }}</div>
<div class="desc">{{ dict.description }}</div>
<div class="num">{{ dict.length }}</div>
<Icon icon="octicon:arrow-right-24" v-if="selectDictName === i.name"
<Icon icon="octicon:arrow-right-24" v-if="selectDictName === dict.name"
@click.stop="emit('detail')"
class="go" width="20" color="#929596"/>
</div>

View File

@@ -6,27 +6,15 @@ import {usePlayWordAudio} from "@/hooks/sound.ts";
import {useWordOptions} from "@/hooks/dict.ts";
const props = withDefaults(defineProps<{
list?: Word[],
activeIndex?: number,
showDel?: boolean,
isActive?: boolean
active?: boolean
showTranslate?: boolean
showWord?: boolean
word: Word
}>(), {
activeIndex: -1,
isActive: false,
showDel: false,
showTranslate: true,
showWord: true
})
const emit = defineEmits<{
del: [val: Word],
change: [i: number]
}>()
const playWordAudio = usePlayWordAudio()
const {
isWordCollect,

View File

@@ -2,6 +2,9 @@
import {Word} from "../../types.ts";
import {useSettingStore} from "@/stores/setting.ts";
import WordItem from "@/components/list/WordItem.vue";
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
import {usePlayWordAudio} from "@/hooks/sound.ts";
import {watch} from 'vue'
const props = withDefaults(defineProps<{
list: Word[],
@@ -24,30 +27,38 @@ const emit = defineEmits<{
}>()
const settingStore = useSettingStore()
//
// const listRef: HTMLElement = $ref(null as any)
//
// function scrollViewToCenter(index: number) {
// if (index === -1) return
// listRef.children[index]?.scrollIntoView({block: 'center', behavior: 'smooth'})
// }
//
// watch(() => props.activeIndex, (n: any) => {
// if (settingStore.showPanel) {
// scrollViewToCenter(n)
// }
// })
//
// watch(() => props.isActive, (n: boolean) => {
// setTimeout(() => {
// if (n) scrollViewToCenter(props.activeIndex)
// }, 300)
// })
//
const listRef: any = $ref()
function scrollViewToCenter(index: number) {
if (index === -1) return
listRef.scrollToIndex(index)
// listRef.children[index]?.scrollIntoView({block: 'center', behavior: 'smooth'})
}
watch(() => props.activeIndex, (n: any) => {
if (settingStore.showPanel) {
scrollViewToCenter(n)
}
})
watch(() => props.isActive, (n: boolean) => {
setTimeout(() => {
if (n) scrollViewToCenter(props.activeIndex)
}, 300)
})
// watch(() => props.list, () => {
// listRef.scrollTo(0, 0)
// })
const playWordAudio = usePlayWordAudio()
function reset() {
listRef.reset()
}
defineExpose({reset})
</script>
<template>
@@ -56,12 +67,28 @@ const settingStore = useSettingStore()
data-key="name"
:data-sources="list"
:estimate-size="85"
ref="listRef"
item-class="dict-virtual-item"
>
<template #={source}>
<WordItem :word="source">
<slot :word="source"></slot>
</WordItem>
<template #={source,index}>
<div class="common-list-item"
:class="{active:activeIndex === index}"
@click="emit('change',index)"
>
<div class="left">
<div class="item-title">
<span class="word" :class="!showWord && 'text-shadow'">{{ source.name }}</span>
<span class="phonetic">{{ source.usphone }}</span>
<VolumeIcon class="volume" @click="playWordAudio(source.name)"></VolumeIcon>
</div>
<div class="item-sub-title" v-if="source.trans.length && showTranslate">
<div v-for="item in source.trans">{{ item }}</div>
</div>
</div>
<div class="right">
<slot :word="source"></slot>
</div>
</div>
</template>
</virtual-list>
</template>

View File

@@ -13,6 +13,7 @@ export interface State {
current: {
dictType: DictType,
index: number,
editIndex: number,
practiceType: DictType,//练习类型目前仅词典为collect时判断是练单词还是文章使用
},
simpleWords: string[],
@@ -109,6 +110,7 @@ export const useBaseStore = defineStore('base', {
current: {
dictType: DictType.word,
index: 1,
editIndex: 0,
// dictType: DictType.article,
// index: 0,
practiceType: DictType.word,
@@ -141,6 +143,21 @@ export const useBaseStore = defineStore('base', {
DictType.customArticle
].includes(state.current.dictType)
},
editDict(state: State) {
if (state.current.editIndex === -1) {
return cloneDeep(DefaultDict)
}
switch (state.current.editIndex) {
case 0:
return state.collect
case 1:
return state.simple
case 2:
return state.wrong
default:
return state.myDicts[state.current.editIndex]
}
},
currentDict(state: State): Dict {
switch (state.current.dictType) {
case DictType.collect: