debug
This commit is contained in:
@@ -89,7 +89,7 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- <Backgorund/>-->
|
||||
<Backgorund/>
|
||||
<router-view/>
|
||||
<ArticleContentDialog/>
|
||||
<SettingDialog v-if="runtimeStore.showSettingModal" @close="runtimeStore.showSettingModal = false"/>
|
||||
|
||||
@@ -39,8 +39,12 @@
|
||||
--color-input-bg: white;
|
||||
--color-input-icon: #d3d4d7;
|
||||
|
||||
--color-textarea-bg: white;
|
||||
|
||||
--font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
|
||||
--word-font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace;
|
||||
|
||||
|
||||
}
|
||||
|
||||
html.dark {
|
||||
@@ -72,6 +76,9 @@ html.dark {
|
||||
|
||||
--color-input-bg: rgba(14, 18, 23, 1);
|
||||
--color-input-icon: #383737;
|
||||
|
||||
--color-textarea-bg: rgb(43, 45, 48);
|
||||
|
||||
}
|
||||
|
||||
@media (max-width: 1680px) {
|
||||
@@ -174,7 +181,7 @@ a {
|
||||
min-height: 20rem;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background: var(--color-item-bg);
|
||||
background: var(--color-textarea-bg);
|
||||
|
||||
&:focus {
|
||||
border: 1px solid var(--color-main-active);
|
||||
@@ -429,5 +436,4 @@ footer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-bottom: 10rem;
|
||||
}
|
||||
@@ -2,7 +2,8 @@
|
||||
import {$ref} from "vue/macros";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import Close from "@/components/icon/Close.vue";
|
||||
import {useWindowClick} from "@/hooks/event.ts";
|
||||
import {useDisableEventListener, useWindowClick} from "@/hooks/event.ts";
|
||||
import {watch} from "vue";
|
||||
|
||||
defineProps<{
|
||||
modelValue: string
|
||||
@@ -17,6 +18,8 @@ useWindowClick((e: PointerEvent) => {
|
||||
focus = inputEl.contains(e.target as any);
|
||||
})
|
||||
|
||||
useDisableEventListener(() => focus)
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -30,7 +33,9 @@ useWindowClick((e: PointerEvent) => {
|
||||
:value="modelValue"
|
||||
@input="e=>$emit('update:modelValue',e.target.value)"
|
||||
>
|
||||
<Close @click="$emit('update:modelValue','')"/>
|
||||
<transition name="fade">
|
||||
<Close v-if="modelValue" @click="$emit('update:modelValue','')"/>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -448,7 +448,7 @@ defineExpose({save, getEditArticle: () => cloneDeep(editArticle)})
|
||||
border-radius: 8rem;
|
||||
|
||||
.section {
|
||||
background: var(--color-item-bg);
|
||||
background: var(--color-textarea-bg);
|
||||
margin-bottom: 20rem;
|
||||
padding: var(--space);
|
||||
border-radius: 8rem;
|
||||
|
||||
@@ -4,6 +4,7 @@ import {Article, DefaultArticle} from "@/types.ts";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import Dialog from "@/components/dialog/Dialog.vue";
|
||||
import EditArticle from "@/components/article/EditArticle.vue";
|
||||
import {useDisableEventListener} from "@/hooks/event.ts";
|
||||
|
||||
interface IProps {
|
||||
article?: Article
|
||||
@@ -16,14 +17,18 @@ const props = withDefaults(defineProps<IProps>(), {
|
||||
})
|
||||
const emit = defineEmits<{
|
||||
save: [val: Article]
|
||||
'update:modelValue': [val: boolean]
|
||||
}>()
|
||||
|
||||
useDisableEventListener(() => props.modelValue)
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog
|
||||
:header="false"
|
||||
:model-value="props.modelValue"
|
||||
@close="emit('update:modelValue',false)"
|
||||
:full-screen="true"
|
||||
>
|
||||
<div class="wrapper">
|
||||
|
||||
@@ -65,7 +65,7 @@ onUnmounted(() => {
|
||||
display: flex;
|
||||
gap: var(--space);
|
||||
padding: var(--space);
|
||||
|
||||
color: var(--color-font-1);
|
||||
|
||||
.article-content {
|
||||
flex: 1;
|
||||
|
||||
@@ -108,10 +108,6 @@ function changeDict() {
|
||||
close()
|
||||
}
|
||||
|
||||
function clickEvent(e) {
|
||||
console.log('e', e)
|
||||
}
|
||||
|
||||
const dictIsArticle = $computed(() => {
|
||||
return isArticle(runtimeStore.editDict.type)
|
||||
})
|
||||
@@ -128,7 +124,7 @@ function showAllWordModal() {
|
||||
})
|
||||
}
|
||||
|
||||
function resetChapterList(v) {
|
||||
function resetChapterList(v:number) {
|
||||
const temp = () => {
|
||||
runtimeStore.editDict.chapterWordNumber = v
|
||||
runtimeStore.editDict.chapterWords = chunk(runtimeStore.editDict.words, runtimeStore.editDict.chapterWordNumber)
|
||||
@@ -158,7 +154,7 @@ function changeSort(v, notice: boolean = true) {
|
||||
} else {
|
||||
runtimeStore.editDict.words = reverse(cloneDeep(runtimeStore.editDict.originWords))
|
||||
}
|
||||
resetChapterList()
|
||||
resetChapterList(runtimeStore.editDict.chapterWordNumber)
|
||||
notice && ElMessage.success('已重新排序')
|
||||
}
|
||||
if (runtimeStore.editDict.isCustom) {
|
||||
@@ -280,14 +276,16 @@ function handleChangeArticleChapterIndex(val) {
|
||||
:title="`添加${dictIsArticle?'文章':'单词'}`"
|
||||
/>
|
||||
</div>
|
||||
<div class="text">开始日期:-</div>
|
||||
<div class="text">花费时间:-</div>
|
||||
<div class="text">累积错误:-</div>
|
||||
<div class="text">进度:
|
||||
<el-progress :percentage="0"
|
||||
:stroke-width="8"
|
||||
:show-text="false"/>
|
||||
</div>
|
||||
<template v-if="false">
|
||||
<div class="text">开始日期:-</div>
|
||||
<div class="text">花费时间:-</div>
|
||||
<div class="text">累积错误:-</div>
|
||||
<div class="text">进度:
|
||||
<el-progress :percentage="0"
|
||||
:stroke-width="8"
|
||||
:show-text="false"/>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="center-column">
|
||||
<div class="common-title">学习设置</div>
|
||||
@@ -385,63 +383,52 @@ function handleChangeArticleChapterIndex(val) {
|
||||
:title="`管理${dictIsArticle?'文章':'章节'}`"
|
||||
/>
|
||||
</div>
|
||||
<template v-if="dictIsArticle">
|
||||
<ArticleList
|
||||
v-if="runtimeStore.editDict.articles.length"
|
||||
:isActive="false"
|
||||
v-loading="loading"
|
||||
:show-border="true"
|
||||
@title="(val:any) => emitter.emit(EventKey.openArticleContentModal,val.item)"
|
||||
@click="handleChangeArticleChapterIndex"
|
||||
:active-id="activeId"
|
||||
:list="runtimeStore.editDict.articles">
|
||||
<template v-slot:prefix="{item,index}">
|
||||
<input type="radio" :checked="activeId === item.id">
|
||||
</template>
|
||||
</ArticleList>
|
||||
<Empty v-else/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<BaseList
|
||||
ref="chapterListRef"
|
||||
v-if="chapterList2.length"
|
||||
:list="chapterList2"
|
||||
:show-border="true"
|
||||
@click="(val:any) => runtimeStore.editDict.chapterIndex = val.index"
|
||||
:active-index="runtimeStore.editDict.chapterIndex"
|
||||
>
|
||||
<template v-slot:prefix="{ item, index }">
|
||||
<input type="radio" :checked="runtimeStore.editDict.chapterIndex === item.id">
|
||||
</template>
|
||||
<template v-slot="{ item, index }">
|
||||
<div class="item-title" @click.stop="showWordListModal({item,index})">
|
||||
<span>第{{ item.id + 1 }}章</span>
|
||||
<span>{{ runtimeStore.editDict.chapterWords[item.id]?.length }}词</span>
|
||||
</div>
|
||||
</template>
|
||||
</BaseList>
|
||||
<Empty v-else/>
|
||||
</template>
|
||||
<div class="list-content">
|
||||
<template v-if="dictIsArticle">
|
||||
<ArticleList
|
||||
v-if="runtimeStore.editDict.articles.length"
|
||||
:isActive="false"
|
||||
v-loading="loading"
|
||||
:show-border="true"
|
||||
@title="(val:any) => emitter.emit(EventKey.openArticleContentModal,val.item)"
|
||||
@click="handleChangeArticleChapterIndex"
|
||||
:active-id="activeId"
|
||||
:list="runtimeStore.editDict.articles">
|
||||
<template v-slot:prefix="{item,index}">
|
||||
<input type="radio" :checked="activeId === item.id">
|
||||
</template>
|
||||
</ArticleList>
|
||||
<Empty v-else/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<BaseList
|
||||
ref="chapterListRef"
|
||||
v-if="chapterList2.length"
|
||||
:list="chapterList2"
|
||||
:show-border="true"
|
||||
@click="(val:any) => runtimeStore.editDict.chapterIndex = val.index"
|
||||
:active-index="runtimeStore.editDict.chapterIndex"
|
||||
>
|
||||
<template v-slot:prefix="{ item, index }">
|
||||
<input type="radio" :checked="runtimeStore.editDict.chapterIndex === item.id">
|
||||
</template>
|
||||
<template v-slot="{ item, index }">
|
||||
<div class="item-title" @click.stop="showWordListModal({item,index})">
|
||||
<span>第{{ item.id + 1 }}章</span>
|
||||
<span>{{ runtimeStore.editDict.chapterWords[item.id]?.length }}词</span>
|
||||
</div>
|
||||
</template>
|
||||
</BaseList>
|
||||
<Empty v-else/>
|
||||
</template>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<!-- <BaseButton @click="step = 0">导出</BaseButton>-->
|
||||
<BaseButton @click="close">关闭</BaseButton>
|
||||
<BaseButton @click="changeDict">切换</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="false" class="activity">
|
||||
<ActivityCalendar
|
||||
:data="[{ date: '2023-05-22', count: 5 }]"
|
||||
:width="40"
|
||||
:height="7"
|
||||
:cellLength="16"
|
||||
:cellInterval="8"
|
||||
:fontSize="12"
|
||||
:showLevelFlag="false"
|
||||
:showWeekDayFlag="false"
|
||||
:clickEvent="clickEvent"
|
||||
/>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<!-- <BaseButton @click="step = 0">导出</BaseButton>-->
|
||||
<BaseButton @click="close">关闭</BaseButton>
|
||||
<BaseButton @click="changeDict">切换</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Slide>
|
||||
@@ -505,17 +492,21 @@ $header-height: 60rem;
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
.left-column {
|
||||
overflow: auto;
|
||||
flex: 6;
|
||||
.column {
|
||||
background: var(--color-second-bg);
|
||||
color: var(--color-font-1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.left-column {
|
||||
flex: 5;
|
||||
gap: 10rem;
|
||||
min-height: 100rem;
|
||||
position: relative;
|
||||
color: var(--color-font-1);
|
||||
font-size: 14rem;
|
||||
padding-right: var(--space);
|
||||
@extend .column;
|
||||
|
||||
|
||||
.name {
|
||||
font-size: 24rem;
|
||||
@@ -542,10 +533,7 @@ $header-height: 60rem;
|
||||
.center-column {
|
||||
overflow: auto;
|
||||
flex: 7;
|
||||
background: white;
|
||||
border-radius: 10rem;
|
||||
background: var(--color-second-bg);
|
||||
color: var(--color-font-1);
|
||||
@extend .column;
|
||||
|
||||
.setting {
|
||||
.row {
|
||||
@@ -575,58 +563,20 @@ $header-height: 60rem;
|
||||
font-size: 13rem;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.right-column {
|
||||
flex: 7;
|
||||
border-radius: 10rem;
|
||||
background: var(--color-second-bg);
|
||||
color: var(--color-font-1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@extend .column;
|
||||
|
||||
.tabs {
|
||||
.list-content {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
margin-bottom: 10rem;
|
||||
|
||||
.tab {
|
||||
font-size: 20rem;
|
||||
color: var(--color-font-3);
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
cursor: pointer;
|
||||
border-bottom: 3px solid transparent;
|
||||
padding-bottom: 10rem;
|
||||
transition: all .3s;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: var(--color-font-1);
|
||||
|
||||
span {
|
||||
border-bottom: 3px solid var(--color-main-active);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.scroll {
|
||||
height: calc(100% - 45rem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.activity {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.footer {
|
||||
box-sizing: content-box;
|
||||
display: flex;
|
||||
@@ -634,7 +584,7 @@ $header-height: 60rem;
|
||||
justify-content: flex-end;
|
||||
gap: var(--space);
|
||||
padding-right: var(--space);
|
||||
margin-bottom: 20rem;
|
||||
margin: var(--space) 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,15 +109,15 @@ const emit = defineEmits<{
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 50rem;
|
||||
width: 50rem;
|
||||
height: 55rem;
|
||||
width: 55rem;
|
||||
color: white; background-color: skyblue;
|
||||
clip-path: polygon(0 10%, 0% 100%, 100% 100%);
|
||||
font-size: 12rem;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-end;
|
||||
padding: 5rem;
|
||||
padding: 3rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ export function useWordOptions() {
|
||||
if (rIndex > -1) {
|
||||
store.wrong.originWords.splice(rIndex, 1)
|
||||
}
|
||||
store.wrong.length = store.wrong.originWords.length
|
||||
}
|
||||
|
||||
function delSimpleWord(val: Word) {
|
||||
@@ -60,6 +61,7 @@ export function useWordOptions() {
|
||||
if (rIndex > -1) {
|
||||
store.simple.originWords.splice(rIndex, 1)
|
||||
}
|
||||
store.simple.length = store.simple.originWords.length
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -303,7 +303,7 @@ $header-height: 50rem;
|
||||
font-size: 16rem;
|
||||
|
||||
&.active {
|
||||
color: rgb(36, 127, 255);
|
||||
color: var(--color-main-active);
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,18 +82,6 @@ watch(() => settingStore.dictation, () => {
|
||||
calcTranslateLocation()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
emitter.on(EventKey.resetWord, () => {
|
||||
wrong = input = ''
|
||||
})
|
||||
emitter.on(EventKey.onTyping, onTyping)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
emitter.off(EventKey.resetWord,)
|
||||
emitter.off(EventKey.onTyping, onTyping)
|
||||
})
|
||||
|
||||
function nextSentence() {
|
||||
// wordData.words = [
|
||||
// {"name": "pharmacy", "trans": ["药房;配药学,药剂学;制药业;一批备用药品"], "usphone": "'fɑrməsi", "ukphone": "'fɑːməsɪ"},
|
||||
@@ -218,7 +206,6 @@ function onTyping(e: KeyboardEvent) {
|
||||
playKeyboardAudio()
|
||||
}
|
||||
e.preventDefault()
|
||||
|
||||
}
|
||||
|
||||
function calcTranslateLocation() {
|
||||
@@ -247,7 +234,9 @@ function calcTranslateLocation() {
|
||||
}
|
||||
|
||||
function play() {
|
||||
return playWordAudio('article1')
|
||||
let currentSection = props.article.sections[sectionIndex]
|
||||
|
||||
return playWordAudio(currentSection[sentenceIndex].text)
|
||||
if (isPlay) {
|
||||
isPlay = false
|
||||
return window.speechSynthesis.pause();
|
||||
@@ -262,55 +251,14 @@ function play() {
|
||||
window.speechSynthesis.speak(msg);
|
||||
}
|
||||
|
||||
function onKeyDown(e: KeyboardEvent) {
|
||||
if (!props.active) return
|
||||
switch (e.key) {
|
||||
case 'Backspace':
|
||||
if (wrong) {
|
||||
wrong = ''
|
||||
} else {
|
||||
input = input.slice(0, -1)
|
||||
}
|
||||
break
|
||||
case ShortcutKeyMap.Collect:
|
||||
|
||||
break
|
||||
case ShortcutKeyMap.Remove:
|
||||
break
|
||||
case ShortcutKeyMap.Ignore:
|
||||
nextSentence()
|
||||
break
|
||||
case ShortcutKeyMap.Show:
|
||||
if (settingStore.allowWordTip) {
|
||||
hoverIndex = {
|
||||
sectionIndex: sectionIndex,
|
||||
sentenceIndex: sentenceIndex,
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// console.log(
|
||||
// 'sectionIndex', sectionIndex,
|
||||
// 'sentenceIndex', sentenceIndex,
|
||||
// 'wordIndex', wordIndex,
|
||||
// 'stringIndex', stringIndex,
|
||||
// )
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
function onKeyUp() {
|
||||
hoverIndex = {
|
||||
sectionIndex: -1,
|
||||
sentenceIndex: -1,
|
||||
function del() {
|
||||
if (wrong) {
|
||||
wrong = ''
|
||||
} else {
|
||||
input = input.slice(0, -1)
|
||||
}
|
||||
}
|
||||
|
||||
useOnKeyboardEventListener(onKeyDown, onKeyUp)
|
||||
|
||||
// useEventListener('keydown', onKeyDown)
|
||||
// useEventListener('keyup', onKeyUp)
|
||||
|
||||
function playWord(word: ArticleWord) {
|
||||
playWordAudio(word.name)
|
||||
}
|
||||
@@ -366,6 +314,30 @@ const {
|
||||
toggleArticleCollect
|
||||
} = useArticleOptions()
|
||||
|
||||
|
||||
function showSentence(i1: number = sectionIndex, i2: number = sentenceIndex) {
|
||||
hoverIndex = {sectionIndex: i1, sentenceIndex: i2}
|
||||
}
|
||||
|
||||
function hideSentence() {
|
||||
hoverIndex = {sectionIndex: -1, sentenceIndex: -1}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
emitter.on(EventKey.resetWord, () => {
|
||||
wrong = input = ''
|
||||
})
|
||||
emitter.on(EventKey.onTyping, onTyping)
|
||||
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
emitter.off(EventKey.resetWord,)
|
||||
emitter.off(EventKey.onTyping, onTyping)
|
||||
})
|
||||
|
||||
defineExpose({showSentence, play, del,hideSentence,nextSentence})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -408,8 +380,8 @@ const {
|
||||
sectionIndex === indexI && sentenceIndex === indexJ && settingStore.dictation
|
||||
?'dictation':''
|
||||
]"
|
||||
@mouseenter="settingStore.allowWordTip && (hoverIndex = {sectionIndex : indexI,sentenceIndex :indexJ})"
|
||||
@mouseleave="hoverIndex = {sectionIndex : -1,sentenceIndex :-1}"
|
||||
@mouseenter="settingStore.allowWordTip && showSentence(indexI,indexJ)"
|
||||
@mouseleave="hideSentence"
|
||||
@click="playWordAudio(sentence.text)"
|
||||
v-for="(sentence,indexJ) in section">
|
||||
<span
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import {$ref} from "vue/macros";
|
||||
import {$computed, $ref} from "vue/macros";
|
||||
import TypingArticle from "./TypingArticle.vue";
|
||||
import {
|
||||
Article,
|
||||
@@ -29,6 +29,7 @@ import {useSettingStore} from "@/stores/setting.ts";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import {syncMyDictList, useArticleOptions} from "@/hooks/dict.ts";
|
||||
import ArticleList from "@/components/list/ArticleList.vue";
|
||||
import {useOnKeyboardEventListener} from "@/hooks/event.ts";
|
||||
|
||||
const store = useBaseStore()
|
||||
const practiceStore = usePracticeStore()
|
||||
@@ -48,9 +49,12 @@ let articleData = $ref({
|
||||
stringIndex: 0,
|
||||
})
|
||||
let showEditArticle = $ref(false)
|
||||
let typingArticleRef = $ref<any>()
|
||||
let editArticle = $ref<Article>(cloneDeep(DefaultArticle))
|
||||
let articleIsActive = $computed(() => tabIndex === 0)
|
||||
|
||||
function next() {
|
||||
if (!articleIsActive) return
|
||||
if (store.currentDict.chapterIndex >= articleData.articles.length - 1) {
|
||||
store.currentDict.chapterIndex = 0
|
||||
} else store.currentDict.chapterIndex++
|
||||
@@ -59,19 +63,6 @@ function next() {
|
||||
getCurrentPractice()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
init()
|
||||
emitter.on(EventKey.changeDict, init)
|
||||
emitter.on(EventKey.next, next)
|
||||
emitter.on(ShortcutKey.NextChapter, next)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
emitter.off(EventKey.changeDict, init)
|
||||
emitter.off(EventKey.next, next)
|
||||
emitter.off(ShortcutKey.NextChapter, next)
|
||||
})
|
||||
|
||||
function init() {
|
||||
if (!store.currentDict.articles.length) return
|
||||
articleData.articles = cloneDeep(store.currentDict.articles)
|
||||
@@ -180,7 +171,8 @@ function saveArticle(val: Article) {
|
||||
setArticle(val)
|
||||
}
|
||||
|
||||
function edit(val: Article) {
|
||||
function edit(val: Article = articleData.article) {
|
||||
if (!articleIsActive)return
|
||||
// tabIndex = 1
|
||||
// wordData.words = [
|
||||
// {
|
||||
@@ -256,6 +248,71 @@ function sort(list: Word[]) {
|
||||
wordData.index = 0
|
||||
}
|
||||
|
||||
function play() {
|
||||
if (!articleIsActive) return
|
||||
typingArticleRef?.play()
|
||||
}
|
||||
|
||||
function show() {
|
||||
if (!articleIsActive) return
|
||||
typingArticleRef?.showSentence()
|
||||
}
|
||||
|
||||
|
||||
function onKeyUp(e: KeyboardEvent) {
|
||||
typingArticleRef.hideSentence()
|
||||
}
|
||||
|
||||
async function onKeyDown(e: KeyboardEvent) {
|
||||
// console.log('e', e)
|
||||
switch (e.key) {
|
||||
case 'Backspace':
|
||||
typingArticleRef.del()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
useOnKeyboardEventListener(onKeyDown, onKeyUp)
|
||||
|
||||
function skip() {
|
||||
if (!articleIsActive) return
|
||||
typingArticleRef?.nextSentence()
|
||||
}
|
||||
|
||||
function collect(e: KeyboardEvent) {
|
||||
if (!articleIsActive) return
|
||||
toggleArticleCollect(articleData.article)
|
||||
}
|
||||
|
||||
//包装一遍,因为快捷建的默认参数是Event
|
||||
function shortcutKeyEdit(){
|
||||
edit()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
init()
|
||||
emitter.on(EventKey.changeDict, init)
|
||||
emitter.on(EventKey.next, next)
|
||||
|
||||
emitter.on(ShortcutKey.NextChapter, next)
|
||||
emitter.on(ShortcutKey.PlayWordPronunciation, play)
|
||||
emitter.on(ShortcutKey.ShowWord, show)
|
||||
emitter.on(ShortcutKey.Next, skip)
|
||||
emitter.on(ShortcutKey.ToggleCollect, collect)
|
||||
emitter.on(ShortcutKey.EditArticle, shortcutKeyEdit)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
emitter.off(EventKey.changeDict, init)
|
||||
emitter.off(EventKey.next, next)
|
||||
emitter.off(ShortcutKey.NextChapter, next)
|
||||
emitter.off(ShortcutKey.PlayWordPronunciation, play)
|
||||
emitter.off(ShortcutKey.ShowWord, show)
|
||||
emitter.off(ShortcutKey.Next, skip)
|
||||
emitter.off(ShortcutKey.ToggleCollect, collect)
|
||||
emitter.off(ShortcutKey.EditArticle, shortcutKeyEdit)
|
||||
})
|
||||
|
||||
defineExpose({getCurrentPractice})
|
||||
|
||||
</script>
|
||||
@@ -266,10 +323,11 @@ defineExpose({getCurrentPractice})
|
||||
<div class="swiper-list" :class="`step${tabIndex}`">
|
||||
<div class="swiper-item">
|
||||
<TypingArticle
|
||||
ref="typingArticleRef"
|
||||
:active="tabIndex === 0"
|
||||
@edit="edit"
|
||||
@wrong="wrong"
|
||||
@over="over"
|
||||
@over="skip"
|
||||
@nextWord="nextWord"
|
||||
:article="articleData.article"
|
||||
/>
|
||||
|
||||
@@ -147,10 +147,6 @@ function next(isTyping: boolean = true) {
|
||||
}
|
||||
}
|
||||
|
||||
function onKeyUp(e: KeyboardEvent) {
|
||||
typingRef.hideWord()
|
||||
}
|
||||
|
||||
function wordWrong() {
|
||||
if (!store.wrong.originWords.find((v: Word) => v.name.toLowerCase() === word.name.toLowerCase())) {
|
||||
store.wrong.originWords.push(word)
|
||||
@@ -161,6 +157,10 @@ function wordWrong() {
|
||||
}
|
||||
}
|
||||
|
||||
function onKeyUp(e: KeyboardEvent) {
|
||||
typingRef.hideWord()
|
||||
}
|
||||
|
||||
async function onKeyDown(e: KeyboardEvent) {
|
||||
// console.log('e', e)
|
||||
switch (e.key) {
|
||||
|
||||
@@ -8,13 +8,13 @@ import {nanoid} from "nanoid";
|
||||
import {state} from "vue-tsc/out/shared";
|
||||
|
||||
export interface BaseState {
|
||||
myDictList: Dict[],
|
||||
current: {
|
||||
index: number,
|
||||
practiceType: DictType,//练习类型,目前仅词典为collect时判断是练单词还是文章使用
|
||||
},
|
||||
simpleWords: string[],
|
||||
load: boolean
|
||||
myDictList: Dict[],
|
||||
current: {
|
||||
index: number,
|
||||
practiceType: DictType,//练习类型,目前仅词典为collect时判断是练单词还是文章使用
|
||||
},
|
||||
simpleWords: string[],
|
||||
load: boolean
|
||||
}
|
||||
|
||||
// words: [
|
||||
@@ -63,241 +63,267 @@ export interface BaseState {
|
||||
// ],
|
||||
|
||||
export const useBaseStore = defineStore('base', {
|
||||
state: (): BaseState => {
|
||||
return {
|
||||
myDictList: [
|
||||
{
|
||||
...cloneDeep(DefaultDict),
|
||||
id: 'collect',
|
||||
name: '收藏',
|
||||
type: DictType.collect,
|
||||
category: '自带字典',
|
||||
tags: ['自带'],
|
||||
},
|
||||
{
|
||||
...cloneDeep(DefaultDict),
|
||||
id: 'skip',
|
||||
name: '简单词',
|
||||
type: DictType.simple,
|
||||
category: '自带字典'
|
||||
},
|
||||
{
|
||||
...cloneDeep(DefaultDict),
|
||||
id: 'wrong',
|
||||
name: '错词本',
|
||||
type: DictType.wrong,
|
||||
category: '自带字典'
|
||||
},
|
||||
{
|
||||
...cloneDeep(DefaultDict),
|
||||
id: 'article_nce2',
|
||||
name: "新概念英语2-课文",
|
||||
description: '新概念英语2-课文',
|
||||
category: '英语学习',
|
||||
tags: ['新概念英语'],
|
||||
url: 'NCE_2.json',
|
||||
translateLanguage: 'common',
|
||||
language: 'en',
|
||||
type: DictType.article,
|
||||
resourceId: 'article_nce2',
|
||||
},
|
||||
{
|
||||
...cloneDeep(DefaultDict),
|
||||
id: 'nce-new-2',
|
||||
name: '新概念英语(新版)-2',
|
||||
description: '新概念英语新版第二册',
|
||||
category: '青少年英语',
|
||||
tags: ['新概念英语'],
|
||||
url: 'nce-new-2.json',
|
||||
translateLanguage: 'common',
|
||||
language: 'en',
|
||||
type: DictType.word,
|
||||
resourceId: 'nce-new-2',
|
||||
},
|
||||
],
|
||||
current: {
|
||||
index: 4,
|
||||
// dictType: DictType.article,
|
||||
// index: 0,
|
||||
practiceType: DictType.word,
|
||||
},
|
||||
simpleWords: [
|
||||
'a', 'an',
|
||||
'i', 'my', 'you', 'your', 'me', 'it',
|
||||
'am', 'is', 'do', 'are', 'did', 'were',
|
||||
'what', 'who', 'where', 'how', 'no', 'yes',
|
||||
'not', 'can', 'could',
|
||||
'the', 'to', 'of', 'for', 'and', 'that', 'this', 'be'
|
||||
],
|
||||
load: false
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
collect() {
|
||||
return this.myDictList[0] ?? {}
|
||||
},
|
||||
simple(): Dict {
|
||||
return this.myDictList[1]
|
||||
},
|
||||
wrong() {
|
||||
return this.myDictList[2]
|
||||
},
|
||||
skipWordNames() {
|
||||
return this.simple.originWords.map(v => v.name.toLowerCase())
|
||||
},
|
||||
skipWordNamesWithSimpleWords() {
|
||||
return this.simple.originWords.map(v => v.name.toLowerCase()).concat(this.simpleWords)
|
||||
},
|
||||
isArticle(state: BaseState): boolean {
|
||||
//如果是收藏时,特殊判断
|
||||
if (this.currentDict.type === DictType.collect) {
|
||||
return state.current.practiceType === DictType.article
|
||||
}
|
||||
return [
|
||||
DictType.article,
|
||||
].includes(this.currentDict.type)
|
||||
},
|
||||
currentDict(): Dict {
|
||||
return this.myDictList[this.current.index]
|
||||
},
|
||||
chapter(state: BaseState): Word[] {
|
||||
return this.currentDict.chapterWords[this.currentDict.chapterIndex] ?? []
|
||||
},
|
||||
chapterName(state: BaseState) {
|
||||
let title = ''
|
||||
switch (this.currentDict.type) {
|
||||
case DictType.collect:
|
||||
if (state.current.practiceType === DictType.article) {
|
||||
return `第${this.currentDict.chapterIndex + 1}章`
|
||||
}
|
||||
case DictType.wrong:
|
||||
case DictType.simple:
|
||||
return this.currentDict.name
|
||||
case DictType.word:
|
||||
return `第${this.currentDict.chapterIndex + 1}章`
|
||||
}
|
||||
return title
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
setState(obj: any) {
|
||||
//这样不会丢失watch的值的引用
|
||||
merge(this, obj)
|
||||
},
|
||||
async init() {
|
||||
return new Promise(async resolve => {
|
||||
try {
|
||||
let configStr: string = await localforage.getItem(SaveDict.key)
|
||||
// console.log(configStr)
|
||||
// console.log('s', new Blob([configStr]).size)
|
||||
configStr = ''
|
||||
if (configStr) {
|
||||
let data = JSON.parse(configStr)
|
||||
let state: BaseState = data.val
|
||||
let version = Number(data.version)
|
||||
// console.log('state', state)
|
||||
state.load = false
|
||||
|
||||
if (version === SaveDict.version) {
|
||||
this.setState(state)
|
||||
} else {
|
||||
if (version === 2) {
|
||||
|
||||
}
|
||||
// this.setState(state)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('读取本地dict数据失败', e)
|
||||
state: (): BaseState => {
|
||||
return {
|
||||
myDictList: [
|
||||
{
|
||||
...cloneDeep(DefaultDict),
|
||||
id: 'collect',
|
||||
name: '收藏',
|
||||
type: DictType.collect,
|
||||
category: '自带字典',
|
||||
tags: ['自带'],
|
||||
},
|
||||
{
|
||||
...cloneDeep(DefaultDict),
|
||||
id: 'skip',
|
||||
name: '简单词',
|
||||
type: DictType.simple,
|
||||
category: '自带字典'
|
||||
},
|
||||
{
|
||||
...cloneDeep(DefaultDict),
|
||||
id: 'wrong',
|
||||
name: '错词本',
|
||||
type: DictType.wrong,
|
||||
category: '自带字典'
|
||||
},
|
||||
{
|
||||
...cloneDeep(DefaultDict),
|
||||
id: 'cet4',
|
||||
name: 'CET-4',
|
||||
description: '大学英语四级词库',
|
||||
category: '中国考试',
|
||||
tags: ['大学英语'],
|
||||
url: 'CET4_T.json',
|
||||
length: 2607,
|
||||
translateLanguage: 'common',
|
||||
language: 'en',
|
||||
type: DictType.word
|
||||
},
|
||||
{
|
||||
...cloneDeep(DefaultDict),
|
||||
id: 'article_nce2',
|
||||
name: "新概念英语2-课文",
|
||||
description: '新概念英语2-课文',
|
||||
category: '英语学习',
|
||||
tags: ['新概念英语'],
|
||||
url: 'NCE_2.json',
|
||||
translateLanguage: 'common',
|
||||
language: 'en',
|
||||
type: DictType.article,
|
||||
resourceId: 'article_nce2',
|
||||
length: 10
|
||||
},
|
||||
{
|
||||
...cloneDeep(DefaultDict),
|
||||
id: 'nce-new-2',
|
||||
name: '新概念英语(新版)-2',
|
||||
description: '新概念英语新版第二册',
|
||||
category: '青少年英语',
|
||||
tags: ['新概念英语'],
|
||||
url: 'nce-new-2.json',
|
||||
translateLanguage: 'common',
|
||||
language: 'en',
|
||||
type: DictType.word,
|
||||
resourceId: 'nce-new-2',
|
||||
length: 862
|
||||
},
|
||||
],
|
||||
current: {
|
||||
index: 3,
|
||||
// dictType: DictType.article,
|
||||
// index: 0,
|
||||
practiceType: DictType.word,
|
||||
},
|
||||
simpleWords: [
|
||||
'a', 'an',
|
||||
'i', 'my', 'you', 'your', 'me', 'it',
|
||||
'am', 'is', 'do', 'are', 'did', 'were',
|
||||
'what', 'who', 'where', 'how', 'no', 'yes',
|
||||
'not', 'can', 'could',
|
||||
'the', 'to', 'of', 'for', 'and', 'that', 'this', 'be'
|
||||
],
|
||||
load: false
|
||||
}
|
||||
},
|
||||
getters: {
|
||||
collect() {
|
||||
return this.myDictList[0] ?? {}
|
||||
},
|
||||
simple(): Dict {
|
||||
return this.myDictList[1]
|
||||
},
|
||||
wrong() {
|
||||
return this.myDictList[2]
|
||||
},
|
||||
skipWordNames() {
|
||||
return this.simple.originWords.map(v => v.name.toLowerCase())
|
||||
},
|
||||
skipWordNamesWithSimpleWords() {
|
||||
return this.simple.originWords.map(v => v.name.toLowerCase()).concat(this.simpleWords)
|
||||
},
|
||||
isArticle(state: BaseState): boolean {
|
||||
//如果是收藏时,特殊判断
|
||||
if (this.currentDict.type === DictType.collect) {
|
||||
return state.current.practiceType === DictType.article
|
||||
}
|
||||
return [
|
||||
DictType.article,
|
||||
].includes(this.currentDict.type)
|
||||
},
|
||||
currentDict(): Dict {
|
||||
return this.myDictList[this.current.index]
|
||||
},
|
||||
chapter(state: BaseState): Word[] {
|
||||
return this.currentDict.chapterWords[this.currentDict.chapterIndex] ?? []
|
||||
},
|
||||
chapterName(state: BaseState) {
|
||||
let title = ''
|
||||
switch (this.currentDict.type) {
|
||||
case DictType.collect:
|
||||
if (state.current.practiceType === DictType.article) {
|
||||
return `第${this.currentDict.chapterIndex + 1}章`
|
||||
}
|
||||
case DictType.wrong:
|
||||
case DictType.simple:
|
||||
return this.currentDict.name
|
||||
case DictType.word:
|
||||
return `第${this.currentDict.chapterIndex + 1}章`
|
||||
}
|
||||
return title
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
setState(obj: any) {
|
||||
//这样不会丢失watch的值的引用
|
||||
merge(this, obj)
|
||||
},
|
||||
async init() {
|
||||
return new Promise(async resolve => {
|
||||
try {
|
||||
let configStr: string = await localforage.getItem(SaveDict.key)
|
||||
// console.log(configStr)
|
||||
// console.log('s', new Blob([configStr]).size)
|
||||
configStr = ''
|
||||
if (configStr) {
|
||||
let data = JSON.parse(configStr)
|
||||
let state: BaseState = data.val
|
||||
let version = Number(data.version)
|
||||
// console.log('state', state)
|
||||
state.load = false
|
||||
|
||||
if (this.current.index < 3) {
|
||||
if (version === SaveDict.version) {
|
||||
this.setState(state)
|
||||
} else {
|
||||
if (version === 2) {
|
||||
|
||||
} else {
|
||||
let dictResourceUrl = `./dicts/${this.currentDict.language}/${this.currentDict.type}/${this.currentDict.translateLanguage}/${this.currentDict.url}`;
|
||||
if ([DictType.word].includes(this.currentDict.type)) {
|
||||
if (!this.currentDict.originWords.length) {
|
||||
let r = await fetch(dictResourceUrl)
|
||||
// let r = await fetch(`.${this.currentDict.url}`)
|
||||
let v = await r.json()
|
||||
v.map(s => {
|
||||
s.id = nanoid(6)
|
||||
})
|
||||
if (this.currentDict.translateLanguage === 'common') {
|
||||
const runtimeStore = useRuntimeStore()
|
||||
let r2 = await fetch('./translate/en2zh_CN-min.json')
|
||||
// fetch('http://sc.ttentau.top/en2zh_CN-min.json').then(r2 => {
|
||||
let list: Word[] = await r2.json()
|
||||
if (list && list.length) {
|
||||
runtimeStore.translateWordList = list
|
||||
}
|
||||
// this.setState(state)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('读取本地dict数据失败', e)
|
||||
}
|
||||
}
|
||||
this.currentDict.originWords = cloneDeep(v)
|
||||
this.currentDict.words = cloneDeep(v)
|
||||
this.currentDict.chapterWords = chunk(this.currentDict.words, this.currentDict.chapterWordNumber)
|
||||
const runtimeStore = useRuntimeStore()
|
||||
|
||||
if (this.current.index < 3) {
|
||||
|
||||
} else {
|
||||
let dictResourceUrl = `./dicts/${this.currentDict.language}/${this.currentDict.type}/${this.currentDict.translateLanguage}/${this.currentDict.url}`;
|
||||
if ([DictType.word].includes(this.currentDict.type)) {
|
||||
if (!this.currentDict.originWords.length) {
|
||||
let r = await fetch(dictResourceUrl)
|
||||
// let r = await fetch(`.${this.currentDict.url}`)
|
||||
let v = await r.json()
|
||||
v.map(s => {
|
||||
s.id = nanoid(6)
|
||||
})
|
||||
if (this.currentDict.translateLanguage === 'common') {
|
||||
let r2 = await fetch('./translate/en2zh_CN-min.json')
|
||||
// fetch('http://sc.ttentau.top/en2zh_CN-min.json').then(r2 => {
|
||||
let list: Word[] = await r2.json()
|
||||
if (list && list.length) {
|
||||
runtimeStore.translateWordList = list
|
||||
}
|
||||
}
|
||||
this.currentDict.originWords = cloneDeep(v)
|
||||
this.currentDict.words = cloneDeep(v)
|
||||
this.currentDict.chapterWords = chunk(this.currentDict.words, this.currentDict.chapterWordNumber)
|
||||
}
|
||||
}
|
||||
|
||||
if ([DictType.article].includes(this.currentDict.type)) {
|
||||
if (!this.currentDict.articles.length) {
|
||||
let r = await fetch(dictResourceUrl)
|
||||
let s: any[] = await r.json()
|
||||
this.currentDict.articles = cloneDeep(s.map(v => {
|
||||
v.id = nanoid(6)
|
||||
return v
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO 先这样,默认加载
|
||||
if (!runtimeStore.translateWordList.length) {
|
||||
setTimeout(async () => {
|
||||
let r2 = await fetch('./translate/en2zh_CN-min.json')
|
||||
// fetch('http://sc.ttentau.top/en2zh_CN-min.json').then(r2 => {
|
||||
let list: Word[] = await r2.json()
|
||||
if (list && list.length) {
|
||||
runtimeStore.translateWordList = list
|
||||
}
|
||||
})
|
||||
}
|
||||
emitter.emit(EventKey.changeDict)
|
||||
resolve(true)
|
||||
})
|
||||
},
|
||||
saveStatistics(statistics: DisplayStatistics) {
|
||||
if (statistics.spend > 1000 * 10) {
|
||||
delete statistics.wrongWords
|
||||
this.currentDict.statistics.push(statistics)
|
||||
}
|
||||
}
|
||||
|
||||
if ([DictType.article].includes(this.currentDict.type)) {
|
||||
if (!this.currentDict.articles.length) {
|
||||
let r = await fetch(dictResourceUrl)
|
||||
let s: any[] = await r.json()
|
||||
this.currentDict.articles = cloneDeep(s.map(v => {
|
||||
v.id = nanoid(6)
|
||||
return v
|
||||
}))
|
||||
},
|
||||
async changeDict(dict: Dict, practiceType?: DictType, chapterIndex?: number, wordIndex?: number) {
|
||||
//TODO 保存统计
|
||||
// this.saveStatistics()
|
||||
console.log('changeDict', cloneDeep(dict), chapterIndex, wordIndex)
|
||||
if (chapterIndex === undefined) chapterIndex = dict.chapterIndex
|
||||
if (wordIndex === undefined) wordIndex = dict.wordIndex
|
||||
if (practiceType === undefined) this.current.practiceType = practiceType
|
||||
if ([DictType.collect,
|
||||
DictType.simple,
|
||||
DictType.wrong].includes(dict.type)) {
|
||||
dict.chapterIndex = 0
|
||||
dict.wordIndex = wordIndex
|
||||
dict.chapterWordNumber = dict.words.length
|
||||
dict.chapterWords = [dict.words]
|
||||
} else {
|
||||
if (dict.type === DictType.article) {
|
||||
if (chapterIndex > dict.articles.length) {
|
||||
dict.chapterIndex = 0
|
||||
dict.wordIndex = 0
|
||||
}
|
||||
} else {
|
||||
if (chapterIndex > dict.chapterWords.length) {
|
||||
dict.chapterIndex = 0
|
||||
dict.wordIndex = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
// await checkDictHasTranslate(dict)
|
||||
let rIndex = this.myDictList.findIndex((v: Dict) => v.id === dict.id)
|
||||
if (rIndex > -1) {
|
||||
this.myDictList[rIndex] = dict
|
||||
this.current.index = rIndex
|
||||
} else {
|
||||
this.myDictList.push(cloneDeep(dict))
|
||||
this.current.index = this.myDictList.length - 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emitter.emit(EventKey.changeDict)
|
||||
resolve(true)
|
||||
})
|
||||
},
|
||||
saveStatistics(statistics: DisplayStatistics) {
|
||||
if (statistics.spend > 1000 * 10) {
|
||||
delete statistics.wrongWords
|
||||
this.currentDict.statistics.push(statistics)
|
||||
}
|
||||
},
|
||||
async changeDict(dict: Dict, practiceType?: DictType, chapterIndex?: number, wordIndex?: number) {
|
||||
//TODO 保存统计
|
||||
// this.saveStatistics()
|
||||
console.log('changeDict', cloneDeep(dict), chapterIndex, wordIndex)
|
||||
if (chapterIndex === undefined) chapterIndex = dict.chapterIndex
|
||||
if (wordIndex === undefined) wordIndex = dict.wordIndex
|
||||
if (practiceType === undefined) this.current.practiceType = practiceType
|
||||
if ([DictType.collect,
|
||||
DictType.simple,
|
||||
DictType.wrong].includes(dict.type)) {
|
||||
dict.chapterIndex = 0
|
||||
dict.wordIndex = wordIndex
|
||||
dict.chapterWordNumber = dict.words.length
|
||||
dict.chapterWords = [dict.words]
|
||||
} else {
|
||||
if (dict.type === DictType.article) {
|
||||
if (chapterIndex > dict.articles.length) {
|
||||
dict.chapterIndex = 0
|
||||
dict.wordIndex = 0
|
||||
}
|
||||
} else {
|
||||
if (chapterIndex > dict.chapterWords.length) {
|
||||
dict.chapterIndex = 0
|
||||
dict.wordIndex = 0
|
||||
}
|
||||
emitter.emit(EventKey.changeDict)
|
||||
}
|
||||
}
|
||||
// await checkDictHasTranslate(dict)
|
||||
let rIndex = this.myDictList.findIndex((v: Dict) => v.id === dict.id)
|
||||
if (rIndex > -1) {
|
||||
this.myDictList[rIndex] = dict
|
||||
this.current.index = rIndex
|
||||
} else {
|
||||
this.myDictList.push(cloneDeep(dict))
|
||||
this.current.index = this.myDictList.length - 1
|
||||
}
|
||||
|
||||
emitter.emit(EventKey.changeDict)
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
Reference in New Issue
Block a user