replace list
This commit is contained in:
@@ -8,7 +8,6 @@ import BaseButton from "@/components/BaseButton.vue";
|
||||
import {Icon} from '@iconify/vue';
|
||||
import {ActivityCalendar} from "vue-activity-calendar";
|
||||
import "vue-activity-calendar/style.css";
|
||||
import ChapterList from "@/components/list/ChapterList.vue";
|
||||
import WordListDialog from "@/components/dialog/WordListDialog.vue";
|
||||
import {isArticle} from "@/hooks/article.ts";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
@@ -23,7 +22,7 @@ import {nanoid} from "nanoid";
|
||||
import DictListPanel from "@/components/DictListPanel.vue";
|
||||
import {useRouter} from "vue-router";
|
||||
import ArticleList4 from "@/components/list2/ArticleList4.vue";
|
||||
import WordChapterList from "@/components/list2/WordChapterList.vue";
|
||||
import BaseList from "@/components/list2/BaseList.vue";
|
||||
|
||||
const store = useBaseStore()
|
||||
const settingStore = useSettingStore()
|
||||
@@ -78,7 +77,7 @@ async function selectDict(val: { dict: DictResource | Dict, index: number }) {
|
||||
}
|
||||
}
|
||||
}
|
||||
chapterList2 = Array.from({length: runtimeStore.editDict.chapterWords.length}).map((v, i) => ({id: i}))
|
||||
chapterList2 = runtimeStore.editDict.chapterWords.map((v, i) => ({id: i}))
|
||||
loading = false
|
||||
}
|
||||
|
||||
@@ -341,18 +340,24 @@ function showWordListModal(val: { item: Word, index: number }) {
|
||||
<Empty v-else/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<WordChapterList
|
||||
<BaseList
|
||||
ref="chapterListRef"
|
||||
v-if="chapterList2.length"
|
||||
:list="chapterList2"
|
||||
:show-border="true"
|
||||
@title="showWordListModal"
|
||||
@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 === index">
|
||||
<template v-slot:prefix="{ item, index }">
|
||||
<input type="radio" :checked="runtimeStore.editDict.chapterIndex === item.id">
|
||||
</template>
|
||||
</WordChapterList>
|
||||
<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>
|
||||
|
||||
@@ -9,12 +9,14 @@ const props = withDefaults(defineProps<{
|
||||
activeId?: string,
|
||||
isActive?: boolean
|
||||
showBorder?: boolean
|
||||
static?: boolean
|
||||
}>(), {
|
||||
list: [],
|
||||
activeIndex: -1,
|
||||
activeId: '',
|
||||
isActive: false,
|
||||
showBorder: false
|
||||
showBorder: false,
|
||||
static: true
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
@@ -25,8 +27,7 @@ const emit = defineEmits<{
|
||||
}>()
|
||||
|
||||
//虚拟列表长度限制
|
||||
const limit = 1
|
||||
|
||||
const limit = 0
|
||||
const settingStore = useSettingStore()
|
||||
const listRef: any = $ref()
|
||||
|
||||
@@ -47,18 +48,21 @@ function scrollViewToCenter(index: number) {
|
||||
}
|
||||
|
||||
watch(() => localActiveIndex, (n: any) => {
|
||||
if (props.static) return
|
||||
if (settingStore.showPanel) {
|
||||
scrollViewToCenter(n)
|
||||
}
|
||||
})
|
||||
|
||||
watch(() => props.isActive, (n: boolean) => {
|
||||
setTimeout(() => {
|
||||
if (n) scrollViewToCenter(localActiveIndex)
|
||||
}, 300)
|
||||
if (props.static) return
|
||||
if (n) {
|
||||
setTimeout(() => scrollViewToCenter(localActiveIndex), 300)
|
||||
}
|
||||
})
|
||||
|
||||
watch(() => props.list, () => {
|
||||
if (props.static) return
|
||||
if (props.list.length > limit) {
|
||||
listRef?.scrollToItem(0)
|
||||
} else {
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import {$ref} from "vue/macros";
|
||||
import {Word} from "@/types.ts";
|
||||
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
|
||||
import BaseList from "@/components/list2/BaseList.vue";
|
||||
import {usePlayWordAudio} from "@/hooks/sound.ts";
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
list: Word[],
|
||||
showTranslate?: boolean
|
||||
showWord?: boolean
|
||||
}>(), {
|
||||
list: [],
|
||||
showTranslate: true,
|
||||
showWord: true
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
click: [val: { item: Word, index: number }],
|
||||
title: [val: { item: Word, index: number }],
|
||||
}>()
|
||||
|
||||
const listRef: any = $ref(null as any)
|
||||
|
||||
function scrollToBottom() {
|
||||
listRef?.scrollToBottom()
|
||||
}
|
||||
|
||||
function scrollToItem(index: number) {
|
||||
listRef?.scrollToItem(index)
|
||||
}
|
||||
defineExpose({scrollToBottom, scrollToItem})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BaseList
|
||||
ref="listRef"
|
||||
@click="(e:any) => emit('click',e)"
|
||||
:list="list"
|
||||
v-bind="$attrs">
|
||||
<template v-slot:prefix="{ item, index }">
|
||||
<slot name="prefix" :item="item" :index="index"></slot>
|
||||
</template>
|
||||
<template v-slot="{ item, index }">
|
||||
<div class="item-title" @click.stop="emit('title',{item,index})">
|
||||
第{{ index + 1 }}章 {{ item.length }}词
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:suffix="{ item, index }">
|
||||
<slot name="suffix" :item="item" :index="index"></slot>
|
||||
</template>
|
||||
</BaseList>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
@@ -47,11 +47,16 @@ function delArticle(index: number) {
|
||||
runtimeStore.editDict.articles.splice(index, 1)
|
||||
|
||||
if (runtimeStore.editDict.articles.length) {
|
||||
if (chapterIndex >= runtimeStore.editDict.articles.length - 1) {
|
||||
chapterIndex = runtimeStore.editDict.articles.length - 1
|
||||
article = runtimeStore.editDict.articles[chapterIndex]
|
||||
}
|
||||
if (chapterIndex === index) {
|
||||
article = runtimeStore.editDict.articles[index]
|
||||
article = runtimeStore.editDict.articles[chapterIndex]
|
||||
}
|
||||
} else {
|
||||
article = cloneDeep(DefaultArticle)
|
||||
chapterIndex = -1
|
||||
}
|
||||
syncMyDictList(runtimeStore.editDict)
|
||||
ElMessage.success('删除成功!')
|
||||
@@ -61,7 +66,10 @@ const emit = defineEmits<{
|
||||
back: []
|
||||
}>()
|
||||
|
||||
async function getDictDetail(val: { dict: DictResource | Dict, index: number }) {
|
||||
async function getDictDetail(val: {
|
||||
dict: DictResource | Dict,
|
||||
index: number
|
||||
}) {
|
||||
let item = val.dict
|
||||
// console.log('word-getDictDetail', item)
|
||||
chapterIndex = -1
|
||||
@@ -189,7 +197,10 @@ function importData(e: any) {
|
||||
reader.readAsBinaryString(file);
|
||||
}
|
||||
|
||||
function exportData(val: { type: string, data?: Article }) {
|
||||
function exportData(val: {
|
||||
type: string,
|
||||
data?: Article
|
||||
}) {
|
||||
const {type, data} = val
|
||||
let list = []
|
||||
let filename = ''
|
||||
@@ -309,7 +320,7 @@ defineExpose({getDictDetail, add, editDict})
|
||||
<template v-slot:prefix="{item,index}">
|
||||
<input type="radio" :checked="chapterIndex === index">
|
||||
</template>
|
||||
<template v-slot="{item,index}">
|
||||
<template v-slot:suffix="{item,index}">
|
||||
<BaseIcon
|
||||
class-name="del"
|
||||
@click="emitter.emit(EventKey.openArticleListModal,item)"
|
||||
|
||||
@@ -10,6 +10,9 @@ import MiniDialog from "@/components/dialog/MiniDialog.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import {useWindowClick} from "@/hooks/event.ts";
|
||||
import {reverse, shuffle} from "lodash-es";
|
||||
import BaseList from "@/components/list2/BaseList.vue";
|
||||
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
|
||||
import {usePlayWordAudio} from "@/hooks/sound.ts";
|
||||
|
||||
const props = defineProps<{
|
||||
title: string,
|
||||
@@ -36,7 +39,7 @@ watch(() => props.list, (n) => {
|
||||
checkStatus()
|
||||
})
|
||||
|
||||
function handleCheckedChange({word: source}: any) {
|
||||
function handleCheckedChange({item: source}: any) {
|
||||
source.checked = !source.checked
|
||||
checkStatus()
|
||||
}
|
||||
@@ -89,6 +92,7 @@ defineExpose({scrollToBottom, scrollToItem})
|
||||
let show = $ref(false)
|
||||
useWindowClick(() => show = false)
|
||||
|
||||
const playWordAudio = usePlayWordAudio()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -140,30 +144,41 @@ useWindowClick(() => show = false)
|
||||
</div>
|
||||
</div>
|
||||
<div class="wrapper">
|
||||
<VirtualWordList2
|
||||
<!-- TODO -->
|
||||
<BaseList
|
||||
ref="listRef"
|
||||
:list="list"
|
||||
v-if="list.length"
|
||||
@click="handleCheckedChange"
|
||||
>
|
||||
<template v-slot:prefix="{word}" v-if="canOperation">
|
||||
<el-checkbox v-model="word.checked"
|
||||
@change="handleCheckedChange({word})"
|
||||
<template v-slot:prefix="{item}" v-if="canOperation">
|
||||
<el-checkbox v-model="item.checked"
|
||||
@change="handleCheckedChange({item})"
|
||||
size="large"/>
|
||||
</template>
|
||||
<template v-slot="{word,index}" v-if="canOperation">
|
||||
<template v-slot="{item,index}">
|
||||
<div class="item-title">
|
||||
<span class="word">{{ item.name }}</span>
|
||||
<span class="phonetic">{{ item.usphone }}</span>
|
||||
<VolumeIcon class="volume" @click="playWordAudio(item.name)"></VolumeIcon>
|
||||
</div>
|
||||
<div class="item-sub-title" v-if="item.trans.length">
|
||||
<div v-for="tran in item.trans">{{ tran }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:suffix="{item,index}" v-if="canOperation">
|
||||
<BaseIcon
|
||||
class-name="del"
|
||||
@click="emit('edit',{word,index})"
|
||||
@click="emit('edit',{item,index})"
|
||||
title="编辑"
|
||||
icon="tabler:edit"/>
|
||||
<BaseIcon
|
||||
class-name="del"
|
||||
@click="del({word,index})"
|
||||
@click="del({item,index})"
|
||||
title="删除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
</template>
|
||||
</VirtualWordList2>
|
||||
</BaseList>
|
||||
<Empty :text="emptyTitle" v-else/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -200,6 +215,7 @@ useWindowClick(() => show = false)
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import Empty from "@/components/Empty.vue";
|
||||
import ChapterWordList from "@/pages/dict/components/ChapterWordList.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import {$computed, $ref} from "vue/macros";
|
||||
@@ -23,6 +22,7 @@ import EditDict from "@/pages/dict/components/EditDict.vue";
|
||||
import {syncMyDictList} from "@/hooks/dict.ts";
|
||||
import MiniDialog from "@/components/dialog/MiniDialog.vue";
|
||||
import {useWindowClick} from "@/hooks/event.ts";
|
||||
import BaseList from "@/components/list2/BaseList.vue";
|
||||
|
||||
const emit = defineEmits<{
|
||||
back: []
|
||||
@@ -61,7 +61,10 @@ let chapterWordList: Word[] = $computed({
|
||||
}
|
||||
})
|
||||
|
||||
async function getDictDetail(val: { dict: DictResource | Dict, index: number }) {
|
||||
async function getDictDetail(val: {
|
||||
dict: DictResource | Dict,
|
||||
index: number
|
||||
}) {
|
||||
let item = val.dict
|
||||
// console.log('word-getDictDetail', item)
|
||||
chapterList2 = []
|
||||
@@ -101,13 +104,13 @@ async function getDictDetail(val: { dict: DictResource | Dict, index: number })
|
||||
}
|
||||
}
|
||||
}
|
||||
chapterList2 = Array.from({length: runtimeStore.editDict.chapterWords.length}).map((v, i) => ({id: i}))
|
||||
chapterList2 = runtimeStore.editDict.chapterWords.map((v, i) => ({id: i}))
|
||||
loading = false
|
||||
}
|
||||
|
||||
function addNewChapter() {
|
||||
runtimeStore.editDict.chapterWords.push([])
|
||||
chapterList2 = Array.from({length: runtimeStore.editDict.chapterWords.length}).map((v, i) => ({id: i}))
|
||||
chapterList2 = runtimeStore.editDict.chapterWords.map((v, i) => ({id: i}))
|
||||
ElMessage.success('新增章节成功')
|
||||
setTimeout(() => chapterListRef?.scrollToItem(chapterList2.length - 1), 100)
|
||||
}
|
||||
@@ -117,8 +120,17 @@ function delWordChapter(index: number) {
|
||||
list.map(v => v.checked = false)
|
||||
residueWordList = residueWordList.concat(list)
|
||||
runtimeStore.editDict.chapterWords.splice(index, 1)
|
||||
chapterList2 = Array.from({length: runtimeStore.editDict.chapterWords.length}).map((v, i) => ({id: i}))
|
||||
chapterList2 = runtimeStore.editDict.chapterWords.map((v, i) => ({id: i}))
|
||||
|
||||
// if (runtimeStore.editDict.chapterWords.length) {
|
||||
// if (chapterIndex >= runtimeStore.editDict.chapterWords.length - 1) {
|
||||
// chapterIndex = runtimeStore.editDict.chapterWords.length - 1
|
||||
// }
|
||||
// } else {
|
||||
// chapterIndex = -1
|
||||
// }
|
||||
|
||||
//这里采用删除后跳到上一张的做法,因为章节名是index,如果保持删除后的index不变,看起来就像未删除一样,但是实际删除了
|
||||
if (chapterIndex >= index) chapterIndex--
|
||||
if (chapterIndex < 0) chapterIndex = 0
|
||||
|
||||
@@ -133,9 +145,11 @@ let residueWordListCheckedTotal = $computed(() => {
|
||||
return residueWordList.filter(v => v.checked).length
|
||||
})
|
||||
|
||||
function handleChangeCurrentChapter(index: number) {
|
||||
function handleChangeCurrentChapter(val: {
|
||||
index: number
|
||||
}) {
|
||||
chapterWordList.map(v => v.checked = false)
|
||||
chapterIndex = index
|
||||
chapterIndex = val.index
|
||||
closeWordForm()
|
||||
}
|
||||
|
||||
@@ -324,17 +338,19 @@ async function onSubmitWord() {
|
||||
})
|
||||
}
|
||||
|
||||
function delWord(val: { word: Word }) {
|
||||
let rIndex = runtimeStore.editDict.originWords.findIndex(v => v.id === val.word.id)
|
||||
function delWord(val: {
|
||||
item: Word
|
||||
}) {
|
||||
let rIndex = runtimeStore.editDict.originWords.findIndex(v => v.id === val.item.id)
|
||||
if (rIndex > -1) {
|
||||
runtimeStore.editDict.originWords.splice(rIndex, 1)
|
||||
}
|
||||
let rIndex2 = runtimeStore.editDict.words.findIndex(v => v.id === val.word.id)
|
||||
let rIndex2 = runtimeStore.editDict.words.findIndex(v => v.id === val.item.id)
|
||||
if (rIndex2 > -1) {
|
||||
runtimeStore.editDict.words.splice(rIndex2, 1)
|
||||
}
|
||||
|
||||
if (wordFormData.type === FormMode.Edit && wordForm.name === val.word.name) {
|
||||
if (wordFormData.type === FormMode.Edit && wordForm.name === val.item.name) {
|
||||
closeWordForm()
|
||||
}
|
||||
syncEditDict2MyDictList()
|
||||
@@ -388,7 +404,7 @@ function resetChapterList(num?: number) {
|
||||
runtimeStore.editDict.words.map(v => v.checked = false)
|
||||
runtimeStore.editDict.chapterWords = chunk(runtimeStore.editDict.words, runtimeStore.editDict.chapterWordNumber)
|
||||
runtimeStore.editDict.length = runtimeStore.editDict.words.length + runtimeStore.editDict.residueWords.length
|
||||
chapterList2 = Array.from({length: runtimeStore.editDict.chapterWords.length}).map((v, i) => ({id: i}))
|
||||
chapterList2 = runtimeStore.editDict.chapterWords.map((v, i) => ({id: i}))
|
||||
}
|
||||
|
||||
async function resetDict() {
|
||||
@@ -566,44 +582,34 @@ defineExpose({getDictDetail, add: addWord, editDict})
|
||||
</div>
|
||||
</div>
|
||||
<div class="select">
|
||||
<BaseButton v-if="isCanOperation" size="small" @click="showAllocationChapterDialog = true">智能分配</BaseButton>
|
||||
<BaseButton v-if="isCanOperation" size="small" @click="showAllocationChapterDialog = true">智能分配
|
||||
</BaseButton>
|
||||
<span>{{ runtimeStore.editDict.chapterWords.length }}章</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wrapper">
|
||||
<RecycleScroller
|
||||
v-if="chapterList2.length"
|
||||
<BaseList
|
||||
ref="chapterListRef"
|
||||
style="height: 100%;"
|
||||
:items="chapterList2"
|
||||
:item-size="63"
|
||||
key-field="id"
|
||||
v-slot="{ item,index }"
|
||||
>
|
||||
<div style="padding: 0 15rem;">
|
||||
<div class="common-list-item"
|
||||
:class="chapterIndex === item.id && 'active'"
|
||||
@click="handleChangeCurrentChapter(item.id)">
|
||||
<div class="flex gap10 flex1 ">
|
||||
<input type="radio" :checked="chapterIndex === item.id">
|
||||
<div class="item-title flex flex1 space-between">
|
||||
<span>第{{ item.id + 1 }}章</span>
|
||||
<span>{{ runtimeStore.editDict.chapterWords[item.id]?.length }}词</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right"
|
||||
v-if="isCanOperation"
|
||||
>
|
||||
<BaseIcon
|
||||
class-name="del"
|
||||
@click="delWordChapter(item.id)"
|
||||
title="移除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
</div>
|
||||
:list="chapterList2"
|
||||
@click="handleChangeCurrentChapter"
|
||||
:active-index="chapterIndex">
|
||||
<template v-slot:prefix="{ item, index }">
|
||||
<input type="radio" :checked="chapterIndex === item.id">
|
||||
</template>
|
||||
<template v-slot="{ item, index }">
|
||||
<div class="item-title">
|
||||
<span>第{{ item.id + 1 }}章</span>
|
||||
<span>{{ runtimeStore.editDict.chapterWords[item.id]?.length }}词</span>
|
||||
</div>
|
||||
</div>
|
||||
</RecycleScroller>
|
||||
<Empty v-else/>
|
||||
</template>
|
||||
<template v-slot:suffix="{ item, index }" v-if="isCanOperation">
|
||||
<BaseIcon
|
||||
class-name="del"
|
||||
@click="delWordChapter(item.id)"
|
||||
title="移除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
</template>
|
||||
</BaseList>
|
||||
</div>
|
||||
</div>
|
||||
<ChapterWordList
|
||||
@@ -614,7 +620,7 @@ defineExpose({getDictDetail, add: addWord, editDict})
|
||||
@add="addWord('chapter')"
|
||||
@del="delWord"
|
||||
:empty-title="chapterIndex === -1?'请选择章节':null"
|
||||
@edit="val => editWord(val.word,val.index,'chapter')"
|
||||
@edit="val => editWord(val.item,val.index,'chapter')"
|
||||
v-model:list="chapterWordList"/>
|
||||
<div class="options-column" v-if="isCanOperation">
|
||||
<BaseButton @click="toChapterWordList"
|
||||
@@ -635,7 +641,7 @@ defineExpose({getDictDetail, add: addWord, editDict})
|
||||
:show-add="true"
|
||||
@add="addWord('residue')"
|
||||
@del="delWord"
|
||||
@edit="val => editWord(val.word,val.index,'residue')"
|
||||
@edit="val => editWord(val.item,val.index,'residue')"
|
||||
v-model:list="residueWordList"/>
|
||||
<div class="right-column">
|
||||
<div class="add" v-if="wordFormData.type">
|
||||
@@ -814,6 +820,7 @@ defineExpose({getDictDetail, add: addWord, editDict})
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import ArticleList2 from "@/components/list/ArticleList2.vue";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import {useArticleOptions} from "@/hooks/dict.ts";
|
||||
import ArticleList4 from "@/components/list2/ArticleList4.vue";
|
||||
import WordList from "@/components/list2/WordList.vue";
|
||||
|
||||
const store = useBaseStore()
|
||||
const practiceStore = usePracticeStore()
|
||||
@@ -208,7 +209,10 @@ function nextWord(word: ArticleWord) {
|
||||
}
|
||||
}
|
||||
|
||||
function changePracticeArticle(val: { item: Article, index: number }) {
|
||||
function changePracticeArticle(val: {
|
||||
item: Article,
|
||||
index: number
|
||||
}) {
|
||||
let rIndex = store.currentDict.articles.findIndex(v => v.id === val.item.id)
|
||||
if (rIndex > -1) {
|
||||
store.currentDict.chapterIndex = rIndex
|
||||
@@ -278,6 +282,7 @@ const {
|
||||
|
||||
<ArticleList4
|
||||
:isActive="active"
|
||||
:static="false"
|
||||
:show-translate="settingStore.translate"
|
||||
@click="changePracticeArticle"
|
||||
:active-id="articleData.article.id"
|
||||
|
||||
@@ -291,6 +291,7 @@ onUnmounted(() => {
|
||||
<WordList
|
||||
v-if="data.words.length"
|
||||
:is-active="active"
|
||||
:static="false"
|
||||
:show-word="!settingStore.dictation"
|
||||
:show-translate="settingStore.translate"
|
||||
:list="data.words"
|
||||
|
||||
Reference in New Issue
Block a user