Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import {DefaultWord, ShortcutKey, Word} from "@/types.ts";
|
||||
import {getDefaultWord, ShortcutKey, Word} from "@/types.ts";
|
||||
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import {usePlayBeep, usePlayCorrect, usePlayKeyboardAudio, usePlayWordAudio, useTTsPlayAudio} from "@/hooks/sound.ts";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import {nextTick, onMounted, onUnmounted, watch} from "vue";
|
||||
import Tooltip from "@/pages/pc/components/Tooltip.vue";
|
||||
|
||||
@@ -13,7 +12,7 @@ interface IProps {
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
word: () => cloneDeep(DefaultWord),
|
||||
word: () => getDefaultWord(),
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import {onMounted, onUnmounted, watch} from "vue"
|
||||
import {useBaseStore} from "@/stores/base.ts"
|
||||
import {DefaultDisplayStatistics, DefaultWord, DictType, ShortcutKey, Sort, Word} from "@/types.ts";
|
||||
import {DefaultDisplayStatistics, DictType, getDefaultWord, ShortcutKey, Sort, Word} from "@/types.ts";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts"
|
||||
import {cloneDeep, reverse, shuffle} from "lodash-es"
|
||||
import {usePracticeStore} from "@/stores/practice.ts"
|
||||
@@ -80,7 +80,7 @@ watch(data, () => {
|
||||
})
|
||||
|
||||
const word: Word = $computed(() => {
|
||||
return data.words[data.index] ?? DefaultWord
|
||||
return data.words[data.index] ?? getDefaultWord()
|
||||
})
|
||||
|
||||
function next(isTyping: boolean = true) {
|
||||
|
||||
@@ -225,7 +225,7 @@ defineRender(
|
||||
pageSize={pageSize}
|
||||
onUpdate:page-size={(e) => pageSize = e}
|
||||
pageSizes={[20, 50, 100, 200]}
|
||||
layout="sizes, prev, pager, next"
|
||||
layout="prev, pager, next"
|
||||
total={list.value.length}/>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -1,207 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import {nextTick} from "vue";
|
||||
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
|
||||
import {Sort} from "@/types.ts";
|
||||
import MiniDialog from "@/pages/pc/components/dialog/MiniDialog.vue";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import {cloneDeep, reverse, shuffle} from "lodash-es";
|
||||
import Input from "@/pages/pc/components/Input.vue";
|
||||
|
||||
let list = defineModel('list')
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
activeIndex?: number,
|
||||
activeId?: string,
|
||||
isActive?: boolean
|
||||
showBorder?: boolean
|
||||
}>(), {
|
||||
activeIndex: -1,
|
||||
activeId: '',
|
||||
isActive: false,
|
||||
showBorder: false,
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
click: [val: {
|
||||
item: any,
|
||||
index: number
|
||||
}],
|
||||
}>()
|
||||
|
||||
const settingStore = useSettingStore()
|
||||
const listRef: any = $ref()
|
||||
|
||||
function scrollToBottom() {
|
||||
nextTick(() => {
|
||||
listRef?.scrollTo(0, listRef.scrollHeight)
|
||||
})
|
||||
}
|
||||
|
||||
function scrollToItem(index: number) {
|
||||
nextTick(() => {
|
||||
listRef?.children[index]?.scrollIntoView({block: 'center', behavior: 'smooth'})
|
||||
})
|
||||
}
|
||||
|
||||
function itemIsActive(item: any, index: number) {
|
||||
return props.activeId ?
|
||||
props.activeId === item.id
|
||||
: props.activeIndex === index
|
||||
}
|
||||
|
||||
defineExpose({scrollToBottom, scrollToItem})
|
||||
|
||||
let pageNo = $ref(1)
|
||||
let pageSize = $ref(50)
|
||||
let currentList = $computed({
|
||||
get() {
|
||||
if (searchKey) {
|
||||
return list.value.filter(v => v.word.includes(searchKey))
|
||||
}
|
||||
return list.value.slice((pageNo - 1) * pageSize, (pageNo - 1) * pageSize + pageSize)
|
||||
},
|
||||
set(v) {
|
||||
list.value = v
|
||||
}
|
||||
})
|
||||
|
||||
let selectIds = $ref([])
|
||||
let selectAll = $computed(()=>{
|
||||
return !!selectIds.length
|
||||
})
|
||||
|
||||
function toggleSelect(item) {
|
||||
let rIndex = selectIds.findIndex(v => v === item.id)
|
||||
if (rIndex > -1) {
|
||||
selectIds.splice(rIndex, 1)
|
||||
} else {
|
||||
selectIds.push(item.id)
|
||||
}
|
||||
}
|
||||
|
||||
function toggleSelectAll() {
|
||||
if (selectAll) {
|
||||
selectIds = []
|
||||
} else {
|
||||
selectIds = currentList.map(v => v.id)
|
||||
}
|
||||
}
|
||||
|
||||
let searchKey = $ref('')
|
||||
let showSortDialog = $ref(false)
|
||||
let showSearchInput = $ref(false)
|
||||
|
||||
function sort(type: Sort) {
|
||||
if (type === Sort.reverse) {
|
||||
ElMessage.success('已翻转排序')
|
||||
list.value = reverse(cloneDeep(list.value))
|
||||
}
|
||||
if (type === Sort.random) {
|
||||
ElMessage.success('已随机排序')
|
||||
list.value = shuffle(cloneDeep(list.value))
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="">
|
||||
<div
|
||||
v-if="showSearchInput"
|
||||
class="flex gap-2"
|
||||
>
|
||||
<Input v-model="searchKey"
|
||||
class="flex-1"/>
|
||||
<BaseButton @click="showSearchInput = false">取消</BaseButton>
|
||||
</div>
|
||||
<div class="flex justify-between " v-else>
|
||||
<el-checkbox
|
||||
@click="toggleSelectAll"
|
||||
:model-value="selectAll"
|
||||
size="large"/>
|
||||
<div class="flex gap-2 relative">
|
||||
<BaseIcon
|
||||
v-if="selectIds.length"
|
||||
@click="emit('del')"
|
||||
class="del"
|
||||
title="删除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
<BaseIcon
|
||||
@click="emit('add')"
|
||||
icon="fluent:add-20-filled"
|
||||
title="添加单词"/>
|
||||
<BaseIcon
|
||||
title="改变顺序"
|
||||
icon="icon-park-outline:sort-two"
|
||||
@click="showSortDialog = !showSortDialog"
|
||||
/>
|
||||
<BaseIcon
|
||||
@click="showSearchInput = !showSearchInput"
|
||||
title="搜索"
|
||||
icon="fluent:search-24-regular"/>
|
||||
<MiniDialog
|
||||
v-model="showSortDialog"
|
||||
style="width: 8rem;"
|
||||
>
|
||||
<div class="mini-row-title">
|
||||
列表顺序设置
|
||||
</div>
|
||||
<div class="mini-row">
|
||||
<BaseButton size="small" @click="sort(Sort.reverse)">翻转</BaseButton>
|
||||
<BaseButton size="small" @click="sort(Sort.random)">随机</BaseButton>
|
||||
</div>
|
||||
</MiniDialog>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex-1 overflow-auto"
|
||||
ref="listRef">
|
||||
<div class="list-item-wrapper"
|
||||
v-for="(item,index) in currentList"
|
||||
:key="item.id"
|
||||
>
|
||||
<div class="common-list-item"
|
||||
:class="{
|
||||
active:itemIsActive(item,index),
|
||||
border:showBorder
|
||||
}"
|
||||
@click="emit('click',{item,index})"
|
||||
>
|
||||
<div class="left">
|
||||
<el-checkbox
|
||||
:model-value="selectIds.includes(item.id)"
|
||||
@change="toggleSelect(item)"
|
||||
size="large"/>
|
||||
<div class="title-wrapper">
|
||||
<div class="item-title">
|
||||
<span class="word">{{ item.word }}</span>
|
||||
<span class="phonetic">{{ item.phonetic0 }}</span>
|
||||
<VolumeIcon class="volume"></VolumeIcon>
|
||||
</div>
|
||||
<div class="item-sub-title">
|
||||
<div v-for="v in item.trans">{{ (v.pos ? v.pos + '.' : '') + (v.cn || v.en) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<slot name="suffix" :item="item" :index="index"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<el-pagination background
|
||||
v-model:current-page="pageNo"
|
||||
v-model:page-size="pageSize"
|
||||
layout="prev, pager, next" :total="list.length"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
@@ -1,10 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import {DefaultWord, ShortcutKey, Word} from "@/types.ts";
|
||||
import {getDefaultWord, ShortcutKey, Word} from "@/types.ts";
|
||||
import VolumeIcon from "@/components/icon/VolumeIcon.vue";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import {usePlayBeep, usePlayCorrect, usePlayKeyboardAudio, usePlayWordAudio, useTTsPlayAudio} from "@/hooks/sound.ts";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import {onMounted, onUnmounted, watch} from "vue";
|
||||
import Tooltip from "@/pages/pc/components/Tooltip.vue";
|
||||
|
||||
@@ -13,7 +12,7 @@ interface IProps {
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
word: () => cloneDeep(DefaultWord),
|
||||
word: () => getDefaultWord(),
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import {onMounted} from "vue";
|
||||
import {useRoute} from "vue-router";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import {_checkDictWords} from "@/utils";
|
||||
import WordList from "@/pages/pc/components/list/WordList.vue";
|
||||
import {getDefaultDict} from "@/types.ts";
|
||||
import BasePage from "@/pages/pc/components/BasePage.vue";
|
||||
|
||||
const runtimeStore = useRuntimeStore()
|
||||
const route = useRoute()
|
||||
let dict = $ref(getDefaultDict())
|
||||
|
||||
onMounted(() => {
|
||||
switch (Number(route.query.type)) {
|
||||
case -1:
|
||||
if (runtimeStore.routeData) {
|
||||
dict = cloneDeep(runtimeStore.routeData)
|
||||
_checkDictWords(dict)
|
||||
}
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasePage>
|
||||
<div class="h-100 flex ">
|
||||
<WordList
|
||||
ref="listRef"
|
||||
:list="dict.words"
|
||||
>
|
||||
</WordList>
|
||||
</div>
|
||||
</BasePage>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
@@ -140,7 +140,7 @@ function editWord(word: Word,) {
|
||||
wordForm.word = word.word
|
||||
wordForm.phonetic1 = word.phonetic1
|
||||
wordForm.phonetic0 = word.phonetic0
|
||||
wordForm.trans = word.trans.join('\n')
|
||||
wordForm.trans = word.trans.map(v => JSON.stringify(v)).join('\n')
|
||||
}
|
||||
|
||||
function addWord() {
|
||||
|
||||
@@ -1,229 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import BasePage from "@/pages/pc/components/BasePage.vue";
|
||||
import {onMounted, reactive} from "vue";
|
||||
import {useRoute} from "vue-router";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import {assign, cloneDeep} from "lodash-es";
|
||||
import {Word} from "@/types.ts";
|
||||
import {nanoid} from "nanoid";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import {_checkDictWords, useNav} from "@/utils";
|
||||
import {FormInstance, FormRules} from "element-plus";
|
||||
import BaseTable from "@/pages/pc/components/BaseTable.vue";
|
||||
|
||||
const runtimeStore = useRuntimeStore()
|
||||
const store = useBaseStore()
|
||||
const route = useRoute()
|
||||
|
||||
let list = $computed({
|
||||
get() {
|
||||
return runtimeStore.editDict.words
|
||||
},
|
||||
set(v) {
|
||||
runtimeStore.editDict.words = v
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
switch (Number(route.query.type)) {
|
||||
case -1:
|
||||
runtimeStore.editDict = cloneDeep(runtimeStore.routeData)
|
||||
_checkDictWords(runtimeStore.editDict)
|
||||
break
|
||||
case 0:
|
||||
runtimeStore.editDict = cloneDeep(store.collectWord)
|
||||
break
|
||||
case 1:
|
||||
runtimeStore.editDict = cloneDeep(store.wrong)
|
||||
break
|
||||
case 2:
|
||||
runtimeStore.editDict = cloneDeep(store.simple)
|
||||
break
|
||||
case 3:
|
||||
runtimeStore.editDict = cloneDeep(store.master)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
const {back} = useNav()
|
||||
|
||||
let wordFormData = $ref({
|
||||
where: '',
|
||||
type: '',
|
||||
id: '',
|
||||
index: 0
|
||||
})
|
||||
|
||||
enum FormMode {
|
||||
None = '',
|
||||
Add = 'Add',
|
||||
Edit = 'Edit',
|
||||
}
|
||||
|
||||
const DefaultFormWord = {
|
||||
word: '',
|
||||
phonetic0: '',
|
||||
phonetic1: '',
|
||||
trans: '',
|
||||
}
|
||||
let wordForm = $ref(cloneDeep(DefaultFormWord))
|
||||
const wordFormRef = $ref<FormInstance>()
|
||||
const wordRules = reactive<FormRules>({
|
||||
name: [
|
||||
{required: true, message: '请输入单词', trigger: 'blur'},
|
||||
{max: 30, message: '名称不能超过30个字符', trigger: 'blur'},
|
||||
],
|
||||
})
|
||||
|
||||
//TODO trans结构变了,
|
||||
async function onSubmitWord() {
|
||||
await wordFormRef.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
let data: any = cloneDeep(wordForm)
|
||||
if (data.trans) {
|
||||
data.trans = data.trans.split('\n');
|
||||
} else {
|
||||
data.trans = []
|
||||
}
|
||||
if (wordFormData.type === FormMode.Add) {
|
||||
data.id = nanoid(6)
|
||||
data.checked = false
|
||||
let r = list.find(v => v.word === wordForm.word)
|
||||
// if (r) return ElMessage.warning('已有相同名称单词!')
|
||||
// else list.push(data)
|
||||
list.push(data)
|
||||
ElMessage.success('添加成功')
|
||||
wordForm = cloneDeep(DefaultFormWord)
|
||||
// setTimeout(wordListRef?.scrollToBottom, 100)
|
||||
} else {
|
||||
let r = list.find(v => v.id === wordFormData.id)
|
||||
if (r) assign(r, data)
|
||||
r = list.find(v => v.id === wordFormData.id)
|
||||
if (r) assign(r, data)
|
||||
ElMessage.success('修改成功')
|
||||
}
|
||||
} else {
|
||||
ElMessage.warning('请填写完整')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function delWord(val: {
|
||||
item: Word
|
||||
}) {
|
||||
let rIndex2 = list.findIndex(v => v.id === val.item.id)
|
||||
if (rIndex2 > -1) {
|
||||
list.splice(rIndex2, 1)
|
||||
}
|
||||
if (wordFormData.type === FormMode.Edit && wordForm.word === val.item.word) {
|
||||
closeWordForm()
|
||||
}
|
||||
}
|
||||
|
||||
function batchDelWord() {
|
||||
console.log('multipleSelection', multipleSelection)
|
||||
multipleSelection.map(v => delWord({item: v}))
|
||||
}
|
||||
|
||||
function editWord(word: Word,) {
|
||||
wordFormData.type = FormMode.Edit
|
||||
wordFormData.id = word.id
|
||||
wordForm.word = word.word
|
||||
wordForm.phonetic1 = word.phonetic1
|
||||
wordForm.phonetic0 = word.phonetic0
|
||||
wordForm.trans = word.trans.join('\n')
|
||||
}
|
||||
|
||||
function addWord() {
|
||||
// setTimeout(wordListRef?.scrollToBottom, 100)
|
||||
wordFormData.type = FormMode.Add
|
||||
wordForm = cloneDeep(DefaultFormWord)
|
||||
}
|
||||
|
||||
function closeWordForm() {
|
||||
wordFormData.type = FormMode.None
|
||||
wordForm = cloneDeep(DefaultFormWord)
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasePage>
|
||||
<header class="flex gap-4 mb-2 items-center">
|
||||
<BaseIcon @click="back" icon="octicon:arrow-left-24" width="20"/>
|
||||
<div class="left">
|
||||
<div class="top">
|
||||
<div class="text-xl">
|
||||
{{ runtimeStore.editDict.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="desc" v-if="runtimeStore.editDict.description">{{ runtimeStore.editDict.description }}</div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="flex h-140">
|
||||
<div class="w-1/2">
|
||||
<BaseTable
|
||||
class="h-full"
|
||||
ref="listRef"
|
||||
v-model:list="list">
|
||||
<template v-slot="{item}">
|
||||
<span>123</span>
|
||||
<span>{{item}}</span>
|
||||
</template>
|
||||
<template v-slot:suffix="{ item, index }">
|
||||
<span>1</span>
|
||||
<BaseIcon
|
||||
class="del"
|
||||
@click="editWord(item)"
|
||||
title="编辑"
|
||||
icon="tabler:edit"/>
|
||||
<BaseIcon
|
||||
class="del"
|
||||
@click="del({item,index})"
|
||||
title="删除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
</template>
|
||||
</BaseTable>
|
||||
</div>
|
||||
<div class="add w-1/2" v-if="wordFormData.type">
|
||||
<div class="common-title">
|
||||
{{ wordFormData.type === FormMode.Add ? '添加' : '修改' }}单词
|
||||
</div>
|
||||
<el-form
|
||||
class="form"
|
||||
ref="wordFormRef"
|
||||
:rules="wordRules"
|
||||
:model="wordForm"
|
||||
label-width="6rem">
|
||||
<el-form-item label="单词" prop="word">
|
||||
<el-input v-model="wordForm.word"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="翻译">
|
||||
<el-input v-model="wordForm.trans"
|
||||
placeholder="多个翻译请换行"
|
||||
:autosize="{ minRows: 2, maxRows: 6 }"
|
||||
type="textarea"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="音标/发音①">
|
||||
<el-input v-model="wordForm.phonetic0"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="音标/发音②">
|
||||
<el-input v-model="wordForm.phonetic1"/>
|
||||
</el-form-item>
|
||||
<div class="flex-center">
|
||||
<el-button @click="closeWordForm">关闭</el-button>
|
||||
<el-button type="primary" @click="onSubmitWord">保存</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</BasePage>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
@@ -1,282 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import BasePage from "@/pages/pc/components/BasePage.vue";
|
||||
import {onMounted, reactive} from "vue";
|
||||
import {useRoute} from "vue-router";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import {assign, cloneDeep, reverse, shuffle} from "lodash-es";
|
||||
import {Sort, Word} from "@/types.ts";
|
||||
import {nanoid} from "nanoid";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import {useNav} from "@/utils";
|
||||
import {FormInstance, FormRules} from "element-plus";
|
||||
import MiniDialog from "@/pages/pc/components/dialog/MiniDialog.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
|
||||
const runtimeStore = useRuntimeStore()
|
||||
const store = useBaseStore()
|
||||
const route = useRoute()
|
||||
|
||||
let show = $ref(false)
|
||||
let searchKey = $ref('')
|
||||
let list = $computed({
|
||||
get() {
|
||||
if (searchKey) {
|
||||
return runtimeStore.editDict.words.filter(v => v.word.includes(searchKey))
|
||||
}
|
||||
return runtimeStore.editDict.words
|
||||
},
|
||||
set(v) {
|
||||
runtimeStore.editDict.words = v
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
switch (Number(route.query.type)) {
|
||||
case 0:
|
||||
runtimeStore.editDict = cloneDeep(store.collectWord)
|
||||
break
|
||||
case 1:
|
||||
runtimeStore.editDict = cloneDeep(store.wrong)
|
||||
break
|
||||
case 2:
|
||||
runtimeStore.editDict = cloneDeep(store.simple)
|
||||
break
|
||||
case 3:
|
||||
runtimeStore.editDict = cloneDeep(store.master)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
const {back} = useNav()
|
||||
|
||||
|
||||
let wordFormData = $ref({
|
||||
where: '',
|
||||
type: '',
|
||||
id: '',
|
||||
index: 0
|
||||
})
|
||||
|
||||
enum FormMode {
|
||||
None = '',
|
||||
Add = 'Add',
|
||||
Edit = 'Edit',
|
||||
}
|
||||
|
||||
const DefaultFormWord = {
|
||||
word: '',
|
||||
phonetic0: '',
|
||||
phonetic1: '',
|
||||
trans: '',
|
||||
}
|
||||
let wordForm = $ref(cloneDeep(DefaultFormWord))
|
||||
const wordFormRef = $ref<FormInstance>()
|
||||
const wordRules = reactive<FormRules>({
|
||||
name: [
|
||||
{required: true, message: '请输入单词', trigger: 'blur'},
|
||||
{max: 30, message: '名称不能超过30个字符', trigger: 'blur'},
|
||||
],
|
||||
})
|
||||
|
||||
//TODO trans结构变了,
|
||||
async function onSubmitWord() {
|
||||
await wordFormRef.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
let data: any = cloneDeep(wordForm)
|
||||
if (data.trans) {
|
||||
data.trans = data.trans.split('\n');
|
||||
} else {
|
||||
data.trans = []
|
||||
}
|
||||
if (wordFormData.type === FormMode.Add) {
|
||||
data.id = nanoid(6)
|
||||
data.checked = false
|
||||
let r = list.find(v => v.word === wordForm.word)
|
||||
// if (r) return ElMessage.warning('已有相同名称单词!')
|
||||
// else list.push(data)
|
||||
list.push(data)
|
||||
ElMessage.success('添加成功')
|
||||
wordForm = cloneDeep(DefaultFormWord)
|
||||
// setTimeout(wordListRef?.scrollToBottom, 100)
|
||||
} else {
|
||||
let r = list.find(v => v.id === wordFormData.id)
|
||||
if (r) assign(r, data)
|
||||
r = list.find(v => v.id === wordFormData.id)
|
||||
if (r) assign(r, data)
|
||||
ElMessage.success('修改成功')
|
||||
}
|
||||
} else {
|
||||
ElMessage.warning('请填写完整')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function delWord(val: {
|
||||
item: Word
|
||||
}) {
|
||||
let rIndex2 = list.findIndex(v => v.id === val.item.id)
|
||||
if (rIndex2 > -1) {
|
||||
list.splice(rIndex2, 1)
|
||||
}
|
||||
if (wordFormData.type === FormMode.Edit && wordForm.word === val.item.word) {
|
||||
closeWordForm()
|
||||
}
|
||||
}
|
||||
|
||||
function batchDelWord() {
|
||||
console.log('multipleSelection', multipleSelection)
|
||||
multipleSelection.map(v => delWord({item: v}))
|
||||
}
|
||||
|
||||
function editWord(word: Word,) {
|
||||
wordFormData.type = FormMode.Edit
|
||||
wordFormData.id = word.id
|
||||
wordForm.word = word.word
|
||||
wordForm.phonetic1 = word.phonetic1
|
||||
wordForm.phonetic0 = word.phonetic0
|
||||
wordForm.trans = word.trans.join('\n')
|
||||
}
|
||||
|
||||
function addWord() {
|
||||
// setTimeout(wordListRef?.scrollToBottom, 100)
|
||||
wordFormData.type = FormMode.Add
|
||||
wordForm = cloneDeep(DefaultFormWord)
|
||||
}
|
||||
|
||||
function closeWordForm() {
|
||||
wordFormData.type = FormMode.None
|
||||
wordForm = cloneDeep(DefaultFormWord)
|
||||
}
|
||||
|
||||
|
||||
let multipleSelection = $ref<any[]>([])
|
||||
const handleSelectionChange = (val: any[]) => {
|
||||
multipleSelection = val
|
||||
}
|
||||
|
||||
function sort(type: Sort) {
|
||||
if (type === Sort.reverse) {
|
||||
ElMessage.success('已翻转排序')
|
||||
list = reverse(cloneDeep(list))
|
||||
}
|
||||
if (type === Sort.random) {
|
||||
ElMessage.success('已随机排序')
|
||||
list = shuffle(cloneDeep(list))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasePage>
|
||||
<header class="flex gap-4 items-center">
|
||||
<BaseIcon @click="back" icon="octicon:arrow-left-24" width="20"/>
|
||||
<div class="left">
|
||||
<div class="top">
|
||||
<div class="text-xl">
|
||||
{{ runtimeStore.editDict.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="desc" v-if="runtimeStore.editDict.description">{{ runtimeStore.editDict.description }}</div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="flex">
|
||||
<div class="w-1/2">
|
||||
<div class="flex justify-end py-5 gap-2 relative">
|
||||
<el-input v-model="searchKey"/>
|
||||
<BaseIcon
|
||||
v-if="multipleSelection.length"
|
||||
@click="batchDelWord"
|
||||
class="del"
|
||||
title="删除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
<BaseIcon
|
||||
@click="addWord"
|
||||
icon="fluent:add-20-filled"
|
||||
title="添加单词"/>
|
||||
<BaseIcon
|
||||
title="改变顺序"
|
||||
icon="icon-park-outline:sort-two"
|
||||
@click="show = !show"
|
||||
/>
|
||||
<MiniDialog
|
||||
v-model="show"
|
||||
style="width: 8rem;"
|
||||
>
|
||||
<div class="mini-row-title">
|
||||
列表循环设置
|
||||
</div>
|
||||
<div class="mini-row">
|
||||
<BaseButton size="small" @click="sort(Sort.reverse)">翻转</BaseButton>
|
||||
<BaseButton size="small" @click="sort(Sort.random)">随机</BaseButton>
|
||||
</div>
|
||||
</MiniDialog>
|
||||
</div>
|
||||
<el-table :data="list"
|
||||
@selection-change="handleSelectionChange"
|
||||
max-height="80vh">
|
||||
<el-table-column type="selection" width="55"/>
|
||||
<el-table-column prop="word" label="单词" width="120"/>
|
||||
<el-table-column prop="trans" label="翻译" width="180">
|
||||
<template #default="scope">
|
||||
{{ scope.row.trans.map(v => v.cn) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作">
|
||||
<template #default="scope">
|
||||
<el-button size="small" @click="editWord( scope.row)">
|
||||
Edit
|
||||
</el-button>
|
||||
<el-button
|
||||
size="small"
|
||||
type="danger"
|
||||
@click="delWord({item: scope.row})"
|
||||
>
|
||||
Delete
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="add w-1/2" v-if="wordFormData.type">
|
||||
<div class="common-title">
|
||||
{{ wordFormData.type === FormMode.Add ? '添加' : '修改' }}单词
|
||||
</div>
|
||||
<el-form
|
||||
class="form"
|
||||
ref="wordFormRef"
|
||||
:rules="wordRules"
|
||||
:model="wordForm"
|
||||
label-width="6rem">
|
||||
<el-form-item label="单词" prop="word">
|
||||
<el-input v-model="wordForm.word"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="翻译">
|
||||
<el-input v-model="wordForm.trans"
|
||||
placeholder="多个翻译请换行"
|
||||
:autosize="{ minRows: 2, maxRows: 6 }"
|
||||
type="textarea"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="音标/发音①">
|
||||
<el-input v-model="wordForm.phonetic0"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="音标/发音②">
|
||||
<el-input v-model="wordForm.phonetic1"/>
|
||||
</el-form-item>
|
||||
<div class="flex-center">
|
||||
<el-button @click="closeWordForm">关闭</el-button>
|
||||
<el-button type="primary" @click="onSubmitWord">保存</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</BasePage>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
@@ -1,349 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import BasePage from "@/pages/pc/components/BasePage.vue";
|
||||
import {nextTick, onMounted, reactive} from "vue";
|
||||
import {useRoute} from "vue-router";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import {assign, cloneDeep, reverse, shuffle} from "lodash-es";
|
||||
import {Sort, Word} from "@/types.ts";
|
||||
import {nanoid} from "nanoid";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import {_checkDictWords, useNav} from "@/utils";
|
||||
import {FormInstance, FormRules} from "element-plus";
|
||||
import MiniDialog from "@/pages/pc/components/dialog/MiniDialog.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import WordList from "@/pages/pc/components/list/WordList.vue";
|
||||
import Empty from "@/components/Empty.vue";
|
||||
import {useWindowClick} from "@/hooks/event.ts";
|
||||
|
||||
const runtimeStore = useRuntimeStore()
|
||||
const store = useBaseStore()
|
||||
const route = useRoute()
|
||||
|
||||
let show = $ref(false)
|
||||
let searchKey = $ref('')
|
||||
let list = $computed({
|
||||
get() {
|
||||
if (searchKey) {
|
||||
return runtimeStore.editDict.words.filter(v => v.word.includes(searchKey))
|
||||
}
|
||||
return runtimeStore.editDict.words
|
||||
},
|
||||
set(v) {
|
||||
runtimeStore.editDict.words = v
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
switch (Number(route.query.type)) {
|
||||
case -1:
|
||||
runtimeStore.editDict = cloneDeep(runtimeStore.routeData)
|
||||
_checkDictWords(runtimeStore.editDict)
|
||||
break
|
||||
case 0:
|
||||
runtimeStore.editDict = cloneDeep(store.collectWord)
|
||||
break
|
||||
case 1:
|
||||
runtimeStore.editDict = cloneDeep(store.wrong)
|
||||
break
|
||||
case 2:
|
||||
runtimeStore.editDict = cloneDeep(store.simple)
|
||||
break
|
||||
case 3:
|
||||
runtimeStore.editDict = cloneDeep(store.master)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
const {back} = useNav()
|
||||
|
||||
|
||||
let wordFormData = $ref({
|
||||
where: '',
|
||||
type: '',
|
||||
id: '',
|
||||
index: 0
|
||||
})
|
||||
|
||||
enum FormMode {
|
||||
None = '',
|
||||
Add = 'Add',
|
||||
Edit = 'Edit',
|
||||
}
|
||||
|
||||
const DefaultFormWord = {
|
||||
word: '',
|
||||
phonetic0: '',
|
||||
phonetic1: '',
|
||||
trans: '',
|
||||
}
|
||||
let wordForm = $ref(cloneDeep(DefaultFormWord))
|
||||
const wordFormRef = $ref<FormInstance>()
|
||||
const wordRules = reactive<FormRules>({
|
||||
name: [
|
||||
{required: true, message: '请输入单词', trigger: 'blur'},
|
||||
{max: 30, message: '名称不能超过30个字符', trigger: 'blur'},
|
||||
],
|
||||
})
|
||||
|
||||
//TODO trans结构变了,
|
||||
async function onSubmitWord() {
|
||||
await wordFormRef.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
let data: any = cloneDeep(wordForm)
|
||||
if (data.trans) {
|
||||
data.trans = data.trans.split('\n');
|
||||
} else {
|
||||
data.trans = []
|
||||
}
|
||||
if (wordFormData.type === FormMode.Add) {
|
||||
data.id = nanoid(6)
|
||||
data.checked = false
|
||||
let r = list.find(v => v.word === wordForm.word)
|
||||
// if (r) return ElMessage.warning('已有相同名称单词!')
|
||||
// else list.push(data)
|
||||
list.push(data)
|
||||
ElMessage.success('添加成功')
|
||||
wordForm = cloneDeep(DefaultFormWord)
|
||||
// setTimeout(wordListRef?.scrollToBottom, 100)
|
||||
} else {
|
||||
let r = list.find(v => v.id === wordFormData.id)
|
||||
if (r) assign(r, data)
|
||||
r = list.find(v => v.id === wordFormData.id)
|
||||
if (r) assign(r, data)
|
||||
ElMessage.success('修改成功')
|
||||
}
|
||||
} else {
|
||||
ElMessage.warning('请填写完整')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function delWord(val: {
|
||||
item: Word
|
||||
}) {
|
||||
let rIndex2 = list.findIndex(v => v.id === val.item.id)
|
||||
if (rIndex2 > -1) {
|
||||
list.splice(rIndex2, 1)
|
||||
}
|
||||
if (wordFormData.type === FormMode.Edit && wordForm.word === val.item.word) {
|
||||
closeWordForm()
|
||||
}
|
||||
}
|
||||
|
||||
function batchDelWord() {
|
||||
console.log('multipleSelection', multipleSelection)
|
||||
multipleSelection.map(v => delWord({item: v}))
|
||||
}
|
||||
|
||||
function editWord(word: Word,) {
|
||||
wordFormData.type = FormMode.Edit
|
||||
wordFormData.id = word.id
|
||||
wordForm.word = word.word
|
||||
wordForm.phonetic1 = word.phonetic1
|
||||
wordForm.phonetic0 = word.phonetic0
|
||||
wordForm.trans = word.trans.join('\n')
|
||||
}
|
||||
|
||||
function addWord() {
|
||||
// setTimeout(wordListRef?.scrollToBottom, 100)
|
||||
wordFormData.type = FormMode.Add
|
||||
wordForm = cloneDeep(DefaultFormWord)
|
||||
}
|
||||
|
||||
function closeWordForm() {
|
||||
wordFormData.type = FormMode.None
|
||||
wordForm = cloneDeep(DefaultFormWord)
|
||||
}
|
||||
|
||||
|
||||
let multipleSelection = $ref<any[]>([])
|
||||
const handleSelectionChange = (val: any[]) => {
|
||||
multipleSelection = val
|
||||
}
|
||||
|
||||
function sort(type: Sort) {
|
||||
if (type === Sort.reverse) {
|
||||
ElMessage.success('已翻转排序')
|
||||
list = reverse(cloneDeep(list))
|
||||
}
|
||||
if (type === Sort.random) {
|
||||
ElMessage.success('已随机排序')
|
||||
list = shuffle(cloneDeep(list))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let checkedAll = $ref(false)
|
||||
let isIndeterminate = $ref(false)
|
||||
|
||||
|
||||
function handleCheckedAll() {
|
||||
list.map(v => v.checked = checkedAll)
|
||||
}
|
||||
|
||||
let checkedTotal = $computed(() => {
|
||||
return list.filter(v => v.checked).length
|
||||
})
|
||||
|
||||
function handleCheckedChange({item: source}: any) {
|
||||
source.checked = !source.checked
|
||||
checkStatus()
|
||||
}
|
||||
|
||||
function checkStatus() {
|
||||
checkedAll = list.every(v => v.checked)
|
||||
if (checkedAll) {
|
||||
isIndeterminate = false
|
||||
} else {
|
||||
isIndeterminate = list.some(v => v.checked)
|
||||
}
|
||||
}
|
||||
|
||||
function del(val: { item: Word, index: number }) {
|
||||
list.splice(val.index, 1)
|
||||
}
|
||||
|
||||
let listRef: any = $ref()
|
||||
|
||||
function scrollToBottom() {
|
||||
listRef.scrollToBottom()
|
||||
}
|
||||
|
||||
function scrollToItem(index: number) {
|
||||
nextTick(() => listRef.scrollToItem(index))
|
||||
}
|
||||
|
||||
defineExpose({scrollToBottom, scrollToItem})
|
||||
|
||||
useWindowClick(() => show = false)
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasePage>
|
||||
<header class="flex gap-4 items-center">
|
||||
<BaseIcon @click="back" icon="octicon:arrow-left-24" width="20"/>
|
||||
<div class="left">
|
||||
<div class="top">
|
||||
<div class="text-xl">
|
||||
{{ runtimeStore.editDict.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="desc" v-if="runtimeStore.editDict.description">{{ runtimeStore.editDict.description }}</div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="flex">
|
||||
<div class="w-1/2">
|
||||
<div class="flex justify-end py-5 gap-2 relative">
|
||||
<el-input v-model="searchKey"/>
|
||||
<BaseIcon
|
||||
v-if="multipleSelection.length"
|
||||
@click="batchDelWord"
|
||||
class="del"
|
||||
title="删除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
<BaseIcon
|
||||
@click="addWord"
|
||||
icon="fluent:add-20-filled"
|
||||
title="添加单词"/>
|
||||
<BaseIcon
|
||||
title="改变顺序"
|
||||
icon="icon-park-outline:sort-two"
|
||||
@click="show = !show"
|
||||
/>
|
||||
<MiniDialog
|
||||
v-model="show"
|
||||
style="width: 8rem;"
|
||||
>
|
||||
<div class="mini-row-title">
|
||||
列表循环设置
|
||||
</div>
|
||||
<div class="mini-row">
|
||||
<BaseButton size="small" @click="sort(Sort.reverse)">翻转</BaseButton>
|
||||
<BaseButton size="small" @click="sort(Sort.random)">随机</BaseButton>
|
||||
</div>
|
||||
</MiniDialog>
|
||||
</div>
|
||||
<div class="flex justify-between"
|
||||
v-if="list.length "
|
||||
>
|
||||
<div class="left">
|
||||
<el-checkbox
|
||||
v-model="checkedAll"
|
||||
:indeterminate="isIndeterminate"
|
||||
@change="handleCheckedAll"
|
||||
size="large"/>
|
||||
<span>全选</span>
|
||||
</div>
|
||||
<div class="right">{{ checkedTotal }}/{{ list.length }}</div>
|
||||
</div>
|
||||
|
||||
<div class="wrapper h-100 overflow-auto">
|
||||
<WordList
|
||||
ref="listRef"
|
||||
:list="list"
|
||||
v-if="list.length"
|
||||
@click="handleCheckedChange"
|
||||
>
|
||||
<template v-slot:prefix="{item}">
|
||||
<el-checkbox v-model="item.checked"
|
||||
@change="handleCheckedChange({item})"
|
||||
size="large"/>
|
||||
</template>
|
||||
<template v-slot:suffix="{item,index}">
|
||||
<BaseIcon
|
||||
class="del"
|
||||
@click="editWord(item)"
|
||||
title="编辑"
|
||||
icon="tabler:edit"/>
|
||||
<BaseIcon
|
||||
class="del"
|
||||
@click="del({item,index})"
|
||||
title="删除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
</template>
|
||||
</WordList>
|
||||
<Empty v-else/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="add w-1/2" v-if="wordFormData.type">
|
||||
<div class="common-title">
|
||||
{{ wordFormData.type === FormMode.Add ? '添加' : '修改' }}单词
|
||||
</div>
|
||||
<el-form
|
||||
class="form"
|
||||
ref="wordFormRef"
|
||||
:rules="wordRules"
|
||||
:model="wordForm"
|
||||
label-width="6rem">
|
||||
<el-form-item label="单词" prop="word">
|
||||
<el-input v-model="wordForm.word"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="翻译">
|
||||
<el-input v-model="wordForm.trans"
|
||||
placeholder="多个翻译请换行"
|
||||
:autosize="{ minRows: 2, maxRows: 6 }"
|
||||
type="textarea"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="音标/发音①">
|
||||
<el-input v-model="wordForm.phonetic0"/>
|
||||
</el-form-item>
|
||||
<el-form-item label="音标/发音②">
|
||||
<el-input v-model="wordForm.phonetic1"/>
|
||||
</el-form-item>
|
||||
<div class="flex-center">
|
||||
<el-button @click="closeWordForm">关闭</el-button>
|
||||
<el-button type="primary" @click="onSubmitWord">保存</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
</BasePage>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
@@ -61,9 +61,9 @@ function changePerDayStudyNumber() {
|
||||
|
||||
<template>
|
||||
<BasePage>
|
||||
<div class="card flex gap-10 items-center">
|
||||
<div class="flex-1">
|
||||
<div class="flex gap-5">
|
||||
<div class="card flex gap-10">
|
||||
<div class="flex-1 flex flex-col gap-2">
|
||||
<div class="flex">
|
||||
<div class="bg-slate-200 px-3 h-14 rounded-md flex items-center">
|
||||
<span class="text-xl font-bold">{{ store.sdict.name }}</span>
|
||||
<BaseIcon
|
||||
@@ -72,23 +72,8 @@ function changePerDayStudyNumber() {
|
||||
class="ml-4"
|
||||
@click="router.push('/dict')"/>
|
||||
</div>
|
||||
<div class="flex-1 flex flex-col justify-end items-end">
|
||||
<div class="flex gap-3 items-center">
|
||||
每日目标
|
||||
<div
|
||||
style="color:#ac6ed1;"
|
||||
@click="show = true;tempPerDayStudyNumber = store.sdict.perDayStudyNumber"
|
||||
class="bg-slate-200 px-2 h-10 flex center text-2xl rounded cursor-pointer">
|
||||
{{ store.sdict.perDayStudyNumber }}
|
||||
</div>
|
||||
个单词
|
||||
</div>
|
||||
<div class="mt-2 text-sm">
|
||||
预计完成日期:{{ _getAccomplishDate(store.sdict.words.length, store.sdict.perDayStudyNumber) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
<div class="">
|
||||
<div class="text-sm flex justify-between">
|
||||
已学习{{ store.currentStudyProgress }}%
|
||||
<span>{{ store.sdict.lastLearnIndex }} / {{
|
||||
@@ -97,9 +82,12 @@ function changePerDayStudyNumber() {
|
||||
</div>
|
||||
<el-progress class="mt-1" :percentage="store.currentStudyProgress" :show-text="false"></el-progress>
|
||||
</div>
|
||||
<div class="text-sm text-align-end">
|
||||
预计完成日期:{{ _getAccomplishDate(store.sdict.words.length, store.sdict.perDayStudyNumber) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="w-3/10 flex flex-col gap-4">
|
||||
<div class="w-3/10 flex flex-col justify-evenly">
|
||||
<div class="center text-xl">今日任务</div>
|
||||
<div class="flex">
|
||||
<div class="flex-1 flex flex-col items-center">
|
||||
@@ -119,12 +107,24 @@ function changePerDayStudyNumber() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="">
|
||||
|
||||
<div class="flex flex-col items-end justify-around">
|
||||
<div class="flex gap-1 items-center">
|
||||
每日目标
|
||||
<div
|
||||
style="color:#ac6ed1;"
|
||||
@click="show = true;tempPerDayStudyNumber = store.sdict.perDayStudyNumber"
|
||||
class="bg-slate-200 px-2 h-10 flex center text-2xl rounded cursor-pointer">
|
||||
{{ store.sdict.perDayStudyNumber }}
|
||||
</div>
|
||||
个单词
|
||||
</div>
|
||||
<div class="rounded-xl bg-slate-800 flex items-center gap-2 py-3 px-5 text-white cursor-pointer"
|
||||
@click="study">
|
||||
<span>开始学习</span>
|
||||
<Icon icon="icons8:right-round" class="text-2xl"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
16
src/types.ts
16
src/types.ts
@@ -16,28 +16,26 @@ export type Word = {
|
||||
"phonetic0": string,
|
||||
"phonetic1": string,
|
||||
"trans": WordTrans[]
|
||||
checked?: boolean,
|
||||
sentences?: { v: string, tran: string }[],
|
||||
relWords?: { w: string, tran: string }[],
|
||||
phrases?: { v: string, tran: string } [],
|
||||
synos?: { w: string, tran: string } [],
|
||||
memory?: any,
|
||||
memory?: string,
|
||||
}
|
||||
|
||||
export const DefaultWord: Word = {
|
||||
word: '',
|
||||
phonetic0: '',
|
||||
phonetic1: '',
|
||||
trans: [],
|
||||
}
|
||||
|
||||
export function getDefaultWord(val?: any) {
|
||||
export function getDefaultWord(val?: any): Word {
|
||||
return {
|
||||
id: '',
|
||||
word: '',
|
||||
phonetic0: '',
|
||||
phonetic1: '',
|
||||
trans: [],
|
||||
sentences: [],
|
||||
relWords: [],
|
||||
phrases: [],
|
||||
synos: [],
|
||||
memory: '',
|
||||
...val
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user