save
This commit is contained in:
@@ -9,6 +9,7 @@ import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import DictList from "@/pages/pc/components/list/DictList.vue";
|
||||
import {enArticle} from "@/assets/dictionary.ts";
|
||||
import {DictType} from "@/types.ts";
|
||||
import BasePage from "@/pages/pc/components/BasePage.vue";
|
||||
|
||||
const base = useBaseStore()
|
||||
const router = useRouter()
|
||||
@@ -19,62 +20,59 @@ function clickEvent(e) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="word flex justify-center ">
|
||||
<div class="w-5/10 pt-5">
|
||||
<div class="flex gap-6">
|
||||
<div class="card w-1/4 flex flex-col">
|
||||
<div class="title">
|
||||
我的词典
|
||||
</div>
|
||||
<div class="grid flex-1 flex gap-5 mt-4">
|
||||
<div class="p-4 flex-1 rounded-md bg-slate-200 relative">
|
||||
<span>收藏</span>
|
||||
<div class="absolute bottom-4 right-4">3篇</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid flex-1 flex gap-5 mt-4">
|
||||
<div class="p-4 flex-1 rounded-md bg-slate-200 relative">
|
||||
<span>添加</span>
|
||||
<div class="absolute bottom-4 right-4">3篇</div>
|
||||
</div>
|
||||
<BasePage>
|
||||
<div class="flex gap-6">
|
||||
<div class="card w-1/4 flex flex-col">
|
||||
<div class="title">
|
||||
我的词典
|
||||
</div>
|
||||
<div class="grid flex-1 flex gap-5 mt-4">
|
||||
<div class="p-4 flex-1 rounded-md bg-slate-200 relative">
|
||||
<span>收藏</span>
|
||||
<div class="absolute bottom-4 right-4">3篇</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-3/4">
|
||||
<div class="card ">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="bg-slate-200 p-3 rounded-md cursor-pointer flex items-center">
|
||||
<span class="text-lg font-bold">{{ base.currentArticleDict.name }}</span>
|
||||
<Icon icon="gg:arrows-exchange" class="text-2xl ml-2"/>
|
||||
<Icon icon="uil:setting" class="text-2xl ml-2"/>
|
||||
</div>
|
||||
<div class="rounded-xl bg-slate-800 flex items-center py-3 px-5 text-white cursor-pointer"
|
||||
@click="router.push('/learn-article')">
|
||||
开始学习
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 text-sm">已学习5555个单词的1%</div>
|
||||
<el-progress class="mt-1" :percentage="80" :show-text="false"></el-progress>
|
||||
<div class="grid flex-1 flex gap-5 mt-4">
|
||||
<div class="p-4 flex-1 rounded-md bg-slate-200 relative">
|
||||
<span>添加</span>
|
||||
<div class="absolute bottom-4 right-4">3篇</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<div class="title">文章</div>
|
||||
<div class="mt-4 flex gap-4">
|
||||
<div
|
||||
class="bg-white rounded-md p-4 h-40 w-30 relative cursor-pointer"
|
||||
v-for="dict in enArticle"
|
||||
>
|
||||
<div class="top">
|
||||
<div class="name">{{ dict.name }}</div>
|
||||
<div class="desc">{{ dict.description }}</div>
|
||||
<div class="w-3/4">
|
||||
<div class="card ">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="bg-slate-200 p-3 rounded-md cursor-pointer flex items-center">
|
||||
<span class="text-lg font-bold">{{ base.currentArticleDict.name }}</span>
|
||||
<Icon icon="gg:arrows-exchange" class="text-2xl ml-2"/>
|
||||
<Icon icon="uil:setting" class="text-2xl ml-2"/>
|
||||
</div>
|
||||
<div class="rounded-xl bg-slate-800 flex items-center py-3 px-5 text-white cursor-pointer"
|
||||
@click="router.push('/learn-article')">
|
||||
开始学习
|
||||
</div>
|
||||
<div class="absolute bottom-4 right-4">{{ dict.length }}篇</div>
|
||||
</div>
|
||||
<div class="mt-5 text-sm">已学习5555个单词的1%</div>
|
||||
<el-progress class="mt-1" :percentage="80" :show-text="false"></el-progress>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<div class="title">文章</div>
|
||||
<div class="mt-4 flex gap-4">
|
||||
<div
|
||||
class="bg-white rounded-md p-4 h-40 w-30 relative cursor-pointer"
|
||||
v-for="dict in enArticle"
|
||||
>
|
||||
<div class="top">
|
||||
<div class="name">{{ dict.name }}</div>
|
||||
<div class="desc">{{ dict.description }}</div>
|
||||
</div>
|
||||
<div class="absolute bottom-4 right-4">{{ dict.length }}篇</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</BasePage>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
15
src/pages/pc/components/BasePage.vue
Normal file
15
src/pages/pc/components/BasePage.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex justify-center h-full">
|
||||
<div class="w-5/10 py-5">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
@@ -119,7 +119,7 @@ function del(e) {
|
||||
@import "@/assets/css/style";
|
||||
|
||||
.dict-list-panel {
|
||||
width: 100%;
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
$header-height: 5rem;
|
||||
//padding: var(--space);
|
||||
|
||||
@@ -124,7 +124,7 @@ useWindowClick(() => show = false)
|
||||
v-if="showAdd"
|
||||
@click="emit('add')"
|
||||
icon="fluent:add-20-filled"
|
||||
title="新增单词到本章节"/>
|
||||
title="添加单词"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="select"
|
||||
|
||||
@@ -120,7 +120,7 @@ onMounted(() => {
|
||||
ref="dictFormRef"
|
||||
:rules="dictRules"
|
||||
:model="dictForm"
|
||||
label-width="120rem">
|
||||
label-width="8rem">
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="dictForm.name"/>
|
||||
</el-form-item>
|
||||
|
||||
@@ -1,27 +1,24 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import ChapterWordList from "@/pages/pc/dict/components/ChapterWordList.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import {assign, chunk, cloneDeep, reverse, shuffle} from "lodash-es";
|
||||
import {DefaultDict, Dict, DictResource, DictType, Sort, Word} from "@/types.ts";
|
||||
import {nanoid} from "nanoid";
|
||||
import {FormInstance, FormRules} from "element-plus";
|
||||
import {reactive, watch} from "vue";
|
||||
import {reactive} from "vue";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import Dialog from "@/pages/pc/components/dialog/Dialog.vue";
|
||||
import {MessageBox} from "@/utils/MessageBox.tsx";
|
||||
import * as XLSX from "xlsx";
|
||||
import WordListDialog from "@/pages/pc/components/dialog/WordListDialog.vue";
|
||||
import {no} from "@/utils";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import EditDict from "@/pages/pc/dict/components/EditDict.vue";
|
||||
import {syncMyDictList} from "@/hooks/dict.ts";
|
||||
import MiniDialog from "@/pages/pc/components/dialog/MiniDialog.vue";
|
||||
import {useWindowClick} from "@/hooks/event.ts";
|
||||
import BaseList from "@/pages/pc/components/list/BaseList.vue";
|
||||
import ChapterWordList from "@/pages/pc/dict/components/ChapterWordList.vue";
|
||||
import {useNav} from "@/utils";
|
||||
|
||||
const emit = defineEmits<{
|
||||
back: []
|
||||
@@ -33,13 +30,11 @@ const runtimeStore = useRuntimeStore()
|
||||
|
||||
let loading = $ref(false)
|
||||
let chapterList2 = $ref([])
|
||||
let chapterWordListRef: any = $ref()
|
||||
let wordListRef: any = $ref()
|
||||
let residueWordListRef: any = $ref()
|
||||
let chapterListRef: any = $ref()
|
||||
let chapterIndex = $ref(1)
|
||||
let isEditDict = $ref(false)
|
||||
let showExport = $ref(false)
|
||||
let chapterWordNumber = $ref(settingStore.chapterWordNumber)
|
||||
|
||||
useWindowClick(() => showExport = false)
|
||||
|
||||
@@ -50,12 +45,12 @@ const isCanOperation = $computed(() => {
|
||||
return runtimeStore.editDict.type !== DictType.wrong
|
||||
})
|
||||
|
||||
let chapterWordList: Word[] = $computed({
|
||||
let wordList: Word[] = $computed({
|
||||
get() {
|
||||
return runtimeStore.editDict.chapterWords[chapterIndex] ?? []
|
||||
return runtimeStore.editDict.words ?? []
|
||||
},
|
||||
set(newValue) {
|
||||
runtimeStore.editDict.chapterWords[chapterIndex] = newValue
|
||||
runtimeStore.editDict.words[chapterIndex] = newValue
|
||||
}
|
||||
})
|
||||
|
||||
@@ -91,7 +86,10 @@ async function getDictDetail(val: {
|
||||
runtimeStore.editDict.chapterWordNumber = settingStore.chapterWordNumber
|
||||
}
|
||||
|
||||
console.log('runtimeStore', runtimeStore)
|
||||
|
||||
if ([DictType.collect, DictType.simple, DictType.wrong].includes(runtimeStore.editDict.type)) {
|
||||
|
||||
} else {
|
||||
//如果不是自定义词典,并且有url地址才去下载
|
||||
if (!runtimeStore.editDict.isCustom && runtimeStore.editDict.url) {
|
||||
@@ -113,55 +111,6 @@ async function getDictDetail(val: {
|
||||
loading = false
|
||||
}
|
||||
|
||||
function addNewChapter() {
|
||||
runtimeStore.editDict.chapterWords.push([])
|
||||
chapterList2 = runtimeStore.editDict.chapterWords.map((v, i) => ({id: i}))
|
||||
ElMessage.success('新增章节成功')
|
||||
setTimeout(() => chapterListRef?.scrollToItem(chapterList2.length - 1), 100)
|
||||
}
|
||||
|
||||
function delWordChapter(index: number) {
|
||||
let list = runtimeStore.editDict.chapterWords[index]
|
||||
list.map(v => v.checked = false)
|
||||
residueWordList = residueWordList.concat(list)
|
||||
runtimeStore.editDict.chapterWords.splice(index, 1)
|
||||
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
|
||||
|
||||
syncEditDict2MyDictList()
|
||||
}
|
||||
|
||||
let chapterWordListCheckedTotal = $computed(() => {
|
||||
return chapterWordList.filter(v => v.checked).length
|
||||
})
|
||||
|
||||
let residueWordListCheckedTotal = $computed(() => {
|
||||
return residueWordList.filter(v => v.checked).length
|
||||
})
|
||||
|
||||
function handleChangeCurrentChapter(val: {
|
||||
index: number
|
||||
}) {
|
||||
chapterIndex = val.index
|
||||
chapterWordList.map(v => {
|
||||
v.checked = false
|
||||
})
|
||||
|
||||
chapterWordListRef?.scrollToItem(0)
|
||||
closeWordForm()
|
||||
}
|
||||
|
||||
function checkRepeatWord(
|
||||
words: Word[],
|
||||
targetList: Word[],
|
||||
@@ -194,81 +143,6 @@ function checkRepeatWord(
|
||||
}
|
||||
}
|
||||
|
||||
function toResidueWordList() {
|
||||
let list = cloneDeep(chapterWordList.filter(v => v.checked))
|
||||
list.map(v => v.checked = false)
|
||||
checkRepeatWord(list, residueWordList,
|
||||
noRepeatWords => {
|
||||
if (wordFormData.type === FormMode.Edit && wordFormData.where === 'chapter') {
|
||||
if (noRepeatWords.find(v => v.word === wordForm.word)) {
|
||||
wordFormData.where = 'residue'
|
||||
}
|
||||
}
|
||||
noRepeatWords.map(v => {
|
||||
let rIndex = chapterWordList.findIndex(s => s.id === v.id)
|
||||
if (rIndex > -1) chapterWordList.splice(rIndex, 1)
|
||||
})
|
||||
residueWordList = residueWordList.concat(noRepeatWords)
|
||||
syncEditDict2MyDictList()
|
||||
setTimeout(residueWordListRef?.scrollToBottom, 100)
|
||||
},
|
||||
repeatWords => {
|
||||
if (wordFormData.type === FormMode.Edit && wordFormData.where === 'chapter') {
|
||||
if (repeatWords.find(v => v.word === wordForm.word)) {
|
||||
wordFormData.where = 'residue'
|
||||
}
|
||||
}
|
||||
repeatWords.map(v => {
|
||||
residueWordList[v.index] = v
|
||||
delete residueWordList[v.index].index
|
||||
|
||||
let rIndex = chapterWordList.findIndex(s => s.id === v.id)
|
||||
if (rIndex > -1) chapterWordList.splice(rIndex, 1)
|
||||
})
|
||||
setTimeout(residueWordListRef?.scrollToBottom, 100)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function toChapterWordList() {
|
||||
if (chapterIndex == -1) return ElMessage.warning('请选择章节')
|
||||
let list = cloneDeep(residueWordList.filter(v => v.checked))
|
||||
list.map(v => v.checked = false)
|
||||
|
||||
checkRepeatWord(list, chapterWordList,
|
||||
noRepeatWords => {
|
||||
if (wordFormData.type === FormMode.Edit && wordFormData.where !== 'chapter') {
|
||||
if (noRepeatWords.find(v => v.word === wordForm.word)) {
|
||||
wordFormData.where = 'chapter'
|
||||
}
|
||||
}
|
||||
noRepeatWords.map(v => {
|
||||
let rIndex = residueWordList.findIndex(s => s.id === v.id)
|
||||
if (rIndex > -1) residueWordList.splice(rIndex, 1)
|
||||
})
|
||||
chapterWordList = chapterWordList.concat(noRepeatWords)
|
||||
syncEditDict2MyDictList()
|
||||
setTimeout(chapterWordListRef?.scrollToBottom, 100)
|
||||
},
|
||||
repeatWords => {
|
||||
if (wordFormData.type === FormMode.Edit && wordFormData.where !== 'chapter') {
|
||||
if (repeatWords.find(v => v.word === wordForm.word)) {
|
||||
wordFormData.where = 'chapter'
|
||||
}
|
||||
}
|
||||
repeatWords.map((v) => {
|
||||
chapterWordList[v.index] = v
|
||||
delete chapterWordList[v.index].index
|
||||
|
||||
let rIndex = residueWordList.findIndex(s => s.id === v.id)
|
||||
if (rIndex > -1) residueWordList.splice(rIndex, 1)
|
||||
})
|
||||
syncEditDict2MyDictList()
|
||||
setTimeout(chapterWordListRef?.scrollToBottom, 100)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
//同步到我的词典列表
|
||||
function syncEditDict2MyDictList() {
|
||||
syncMyDictList(runtimeStore.editDict)
|
||||
@@ -317,23 +191,19 @@ async function onSubmitWord() {
|
||||
} else {
|
||||
data.trans = []
|
||||
}
|
||||
//直接使用引用修改
|
||||
let index = wordFormData.where === 'chapter' ? 0 : 1;
|
||||
let list = [chapterWordList, residueWordList][index]
|
||||
let listRef = [chapterWordListRef, residueWordListRef][index]
|
||||
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)
|
||||
let r = wordList.find(v => v.word === wordForm.word)
|
||||
// if (r) return ElMessage.warning('已有相同名称单词!')
|
||||
// else list.push(data)
|
||||
runtimeStore.editDict.originWords.push(data)
|
||||
runtimeStore.editDict.words.push(data)
|
||||
wordList.push(data)
|
||||
ElMessage.success('添加成功')
|
||||
wordForm = cloneDeep(DefaultFormWord)
|
||||
setTimeout(listRef?.scrollToBottom, 100)
|
||||
setTimeout(wordListRef?.scrollToBottom, 100)
|
||||
} else {
|
||||
let r = list.find(v => v.id === wordFormData.id)
|
||||
let r = wordList.find(v => v.id === wordFormData.id)
|
||||
if (r) assign(r, data)
|
||||
//同步修改到列表
|
||||
r = runtimeStore.editDict.originWords.find(v => v.id === wordFormData.id)
|
||||
@@ -367,20 +237,18 @@ function delWord(val: {
|
||||
syncEditDict2MyDictList()
|
||||
}
|
||||
|
||||
function editWord(word: Word, index: number, where: string) {
|
||||
function editWord(word: Word, index: number,) {
|
||||
wordFormData.type = FormMode.Edit
|
||||
wordFormData.id = word.id
|
||||
wordFormData.where = where
|
||||
wordForm.word = word.word
|
||||
wordForm.phonetic1 = word.phonetic1
|
||||
wordForm.phonetic0 = word.phonetic0
|
||||
wordForm.trans = word.trans.join('\n')
|
||||
}
|
||||
|
||||
function addWord(where: string) {
|
||||
function addWord() {
|
||||
// setTimeout(wordListRef?.scrollToBottom, 100)
|
||||
wordFormData.type = FormMode.Add
|
||||
wordFormData.where = where
|
||||
wordForm = cloneDeep(DefaultFormWord)
|
||||
}
|
||||
|
||||
@@ -393,8 +261,6 @@ function closeWordForm() {
|
||||
/* end单词修改相关end*/
|
||||
/**/
|
||||
|
||||
let showAllocationChapterDialog = $ref(false)
|
||||
|
||||
function changeSort(v: Sort) {
|
||||
if (v === Sort.normal) {
|
||||
runtimeStore.editDict.words = cloneDeep(runtimeStore.editDict.originWords)
|
||||
@@ -457,7 +323,7 @@ function exportData(type: string) {
|
||||
if (chapterIndex === -1) {
|
||||
return ElMessage.error('请选择章节')
|
||||
}
|
||||
list = chapterWordList
|
||||
list = wordList
|
||||
filename = runtimeStore.editDict.name + `-第${chapterIndex + 1}章`
|
||||
} else {
|
||||
list = runtimeStore.editDict.words
|
||||
@@ -529,21 +395,7 @@ function editDict() {
|
||||
isEditDict = true
|
||||
}
|
||||
|
||||
function s() {
|
||||
if (runtimeStore.editDict.words.length) {
|
||||
showAllocationChapterDialog = true
|
||||
} else {
|
||||
ElMessage.warning('请先添加单词')
|
||||
}
|
||||
}
|
||||
|
||||
function back() {
|
||||
emit('back')
|
||||
setTimeout(() => {
|
||||
isEditDict = false
|
||||
}, 500)
|
||||
}
|
||||
|
||||
const {back} = useNav()
|
||||
defineExpose({getDictDetail, add: addWord, editDict})
|
||||
|
||||
</script>
|
||||
@@ -561,7 +413,7 @@ defineExpose({getDictDetail, add: addWord, editDict})
|
||||
</div>
|
||||
<template v-if="!isPinDict">
|
||||
<BaseIcon icon="tabler:edit" @click='editDict'/>
|
||||
<!-- <BaseIcon icon="ph:star" @click='no'/>-->
|
||||
<!-- <BaseIcon icon="ph:star" @click='no'/>-->
|
||||
<BaseButton size="small" v-if="runtimeStore.editDict.isCustom" @click="resetDict">恢复默认</BaseButton>
|
||||
</template>
|
||||
<div class="import hvr-grow">
|
||||
@@ -591,7 +443,6 @@ defineExpose({getDictDetail, add: addWord, editDict})
|
||||
</div>
|
||||
</div>
|
||||
<div class="desc" v-if="runtimeStore.editDict.description">{{ runtimeStore.editDict.description }}</div>
|
||||
<div class="num">总词汇: {{ runtimeStore.editDict.length }}词</div>
|
||||
</div>
|
||||
</header>
|
||||
<EditDict
|
||||
@@ -600,95 +451,28 @@ defineExpose({getDictDetail, add: addWord, editDict})
|
||||
@cancel="isEditDict = false"
|
||||
@submit="isEditDict = false"/>
|
||||
<div v-else class="content">
|
||||
<div class="left-column">
|
||||
<div class="header">
|
||||
<div class="common-title">
|
||||
<span>章节管理</span>
|
||||
<div class="options">
|
||||
<BaseIcon
|
||||
v-if="isCanOperation"
|
||||
@click="addNewChapter"
|
||||
icon="fluent:add-20-filled"
|
||||
title="新增章节"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="select">
|
||||
<BaseButton v-if="isCanOperation" size="small" @click="s">智能分配</BaseButton>
|
||||
<span>{{ runtimeStore.editDict.chapterWords.length }}章</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wrapper">
|
||||
<BaseList
|
||||
ref="chapterListRef"
|
||||
: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>
|
||||
</template>
|
||||
<template v-slot:suffix="{ item, index }" v-if="isCanOperation">
|
||||
<BaseIcon
|
||||
class="del"
|
||||
@click="delWordChapter(item.id)"
|
||||
title="移除"
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
</template>
|
||||
</BaseList>
|
||||
</div>
|
||||
</div>
|
||||
<ChapterWordList
|
||||
ref="chapterWordListRef"
|
||||
ref="wordListRef"
|
||||
:can-operation="isCanOperation"
|
||||
:title="`${chapterIndex > -1 ? `第${chapterIndex + 1}章` : ''} 单词列表`"
|
||||
:show-add="chapterIndex > -1"
|
||||
@add="addWord('chapter')"
|
||||
@del="delWord"
|
||||
:empty-title="chapterIndex === -1?'请选择章节':null"
|
||||
@edit="val => editWord(val.item,val.index,'chapter')"
|
||||
@sync="syncMyDictList(runtimeStore.editDict)"
|
||||
v-model:list="chapterWordList"/>
|
||||
<div class="options-column" v-if="isCanOperation">
|
||||
<BaseButton @click="toChapterWordList"
|
||||
:disabled="residueWordListCheckedTotal === 0">
|
||||
<
|
||||
</BaseButton>
|
||||
<BaseButton @click="toResidueWordList"
|
||||
:disabled="chapterWordListCheckedTotal === 0">
|
||||
>
|
||||
</BaseButton>
|
||||
</div>
|
||||
<ChapterWordList
|
||||
v-if="isCanOperation"
|
||||
:can-operation="isCanOperation"
|
||||
ref="residueWordListRef"
|
||||
title="未分配单词列表"
|
||||
:empty-title="null"
|
||||
title="单词列表"
|
||||
:show-add="true"
|
||||
@add="addWord('residue')"
|
||||
@add="addWord"
|
||||
@del="delWord"
|
||||
@edit="val => editWord(val.item,val.index,'residue')"
|
||||
empty-title="还没有单词哦~"
|
||||
@edit="val => editWord(val.item,val.index)"
|
||||
@sync="syncMyDictList(runtimeStore.editDict)"
|
||||
v-model:list="residueWordList"/>
|
||||
v-model:list="wordList"/>
|
||||
<div class="right-column">
|
||||
<div class="add" v-if="wordFormData.type">
|
||||
<div class="common-title">
|
||||
{{ wordFormData.type === FormMode.Add ? '添加' : '修改' }}单词
|
||||
{{
|
||||
wordFormData.type === FormMode.Add ? (wordFormData.where === 'chapter' ? `> 第${chapterIndex + 1}章` : '> 未分配') : ''
|
||||
}}
|
||||
</div>
|
||||
<el-form
|
||||
class="form"
|
||||
ref="wordFormRef"
|
||||
:rules="wordRules"
|
||||
:model="wordForm"
|
||||
label-width="100rem">
|
||||
label-width="6rem">
|
||||
<el-form-item label="单词" prop="word">
|
||||
<el-input v-model="wordForm.word"/>
|
||||
</el-form-item>
|
||||
@@ -713,55 +497,6 @@ defineExpose({getDictDetail, add: addWord, editDict})
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Dialog
|
||||
title="智能分配单词"
|
||||
:footer="true"
|
||||
@ok="resetChapterList(chapterWordNumber,true)"
|
||||
@cancel="chapterWordNumber = settingStore.chapterWordNumber"
|
||||
v-model="showAllocationChapterDialog">
|
||||
<div class="allocation-chapter">
|
||||
<div class="desc">
|
||||
<div>为您自动创建章节以及分配单词</div>
|
||||
<div>注意:已存在的章节将被删除!</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="label">每章单词数</div>
|
||||
<el-slider :min="10"
|
||||
:step="10"
|
||||
show-input
|
||||
size="small"
|
||||
:max="runtimeStore.editDict.words.length < 10 ? 10 : runtimeStore.editDict.words.length"
|
||||
v-model="chapterWordNumber"
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="notice">
|
||||
<span class="text">最小:10</span>
|
||||
<span class="text">最大:{{ runtimeStore.editDict.words.length }}</span>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="label">将会创建</div>
|
||||
<div class="option">
|
||||
<span>{{ Math.ceil(runtimeStore.editDict.words.length / chapterWordNumber) }}章</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="label">每章</div>
|
||||
<div class="option">
|
||||
<span>{{ chapterWordNumber }}个单词</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" :style="{opacity:runtimeStore.editDict.words.length % chapterWordNumber}">
|
||||
<div class="label">最后一章</div>
|
||||
<div class="option">
|
||||
<span>{{ runtimeStore.editDict.words.length % chapterWordNumber }}个单词</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
<WordListDialog/>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -866,25 +601,13 @@ defineExpose({getDictDetail, add: addWord, editDict})
|
||||
background: white;
|
||||
border-radius: .6rem;
|
||||
background: var(--color-second-bg);
|
||||
background: white;
|
||||
color: var(--color-font-1);
|
||||
padding-bottom: var(--space);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.left-column {
|
||||
max-width: 16rem;
|
||||
width: 16vw;
|
||||
@extend .column;
|
||||
}
|
||||
|
||||
.options-column {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: .6rem;
|
||||
}
|
||||
|
||||
.right-column {
|
||||
//@extend .column;
|
||||
flex: 1;
|
||||
@@ -896,42 +619,4 @@ defineExpose({getDictDetail, add: addWord, editDict})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.allocation-chapter {
|
||||
width: 30rem;
|
||||
padding: var(--space);
|
||||
padding-top: 0;
|
||||
color: var(--color-font-1);
|
||||
|
||||
.desc {
|
||||
margin-top: .6rem;
|
||||
margin-bottom: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1.2rem;
|
||||
margin-bottom: 1rem;
|
||||
word-break: keep-all;
|
||||
|
||||
.label {
|
||||
width: 5.6rem;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: .7rem;
|
||||
}
|
||||
}
|
||||
|
||||
.notice {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
transform: translate3d(0, -1rem, 0);
|
||||
padding-left: 7rem;
|
||||
font-size: .8rem;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -16,7 +16,6 @@ onMounted(() => {
|
||||
<template>
|
||||
<div class="anim page">
|
||||
<header class="anim">
|
||||
<Logo/>
|
||||
<div class="nav-list">
|
||||
<nav>
|
||||
<router-link to="/pc/practice">练习</router-link>
|
||||
|
||||
@@ -4,34 +4,19 @@ import DictListPanel2 from "./DictListPanel2.vue";
|
||||
import {Icon} from '@iconify/vue'
|
||||
import "vue-activity-calendar/style.css";
|
||||
import {useRouter} from "vue-router";
|
||||
import BasePage from "@/pages/pc/components/BasePage.vue";
|
||||
|
||||
const base = useBaseStore()
|
||||
const router = useRouter()
|
||||
|
||||
function clickEvent(e) {
|
||||
console.log('e', e)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="word flex justify-center ">
|
||||
<div class="container2">
|
||||
<DictListPanel2
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<BasePage>
|
||||
<DictListPanel2
|
||||
/>
|
||||
</BasePage>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.card {
|
||||
@apply rounded-xl bg-white p-4 mt-5;
|
||||
}
|
||||
|
||||
.center {
|
||||
@apply flex justify-center items-center;
|
||||
}
|
||||
|
||||
.title {
|
||||
@apply text-lg font-medium;
|
||||
}
|
||||
</style>
|
||||
@@ -89,7 +89,7 @@ const showCollectToggleButton = $computed(() => {
|
||||
<div class="panel anim" v-show="settingStore.showPanel || 1">
|
||||
<header>
|
||||
<div class="tabs">
|
||||
<div class="tab" :class="tabIndex === 0 && 'active'" @click="tabIndex = 0">当前学习</div>
|
||||
<div class="tab" :class="tabIndex === 0 && 'active'" @click="tabIndex = 0">当前</div>
|
||||
<div class="tab" :class="tabIndex === 1 && 'active'" @click="tabIndex = 1">{{ store.collect.name }}</div>
|
||||
<div class="tab" :class="tabIndex === 2 && 'active'" @click="tabIndex = 2">{{ store.simple.name }}</div>
|
||||
<div class="tab" :class="tabIndex === 3 && 'active'" @click="tabIndex = 3">{{ store.wrong.name }}</div>
|
||||
|
||||
@@ -385,6 +385,11 @@ defineExpose({showSentence, play, del,hideSentence,nextSentence})
|
||||
:title="`下一句(${settingStore.shortcutKeyMap[ShortcutKey.Next]})`"
|
||||
icon="icon-park-outline:go-ahead"
|
||||
@click="emit('over')"/>
|
||||
|
||||
<BaseIcon
|
||||
@click="settingStore.showPanel = !settingStore.showPanel"
|
||||
:title="`单词本(${settingStore.shortcutKeyMap[ShortcutKey.TogglePanel]})`"
|
||||
icon="tdesign:menu-unfold"/>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -445,10 +445,10 @@ defineExpose({getCurrentPractice})
|
||||
.panel-wrapper {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 10rem;
|
||||
top: .6rem;
|
||||
z-index: 1;
|
||||
margin-left: var(--article-panel-margin-left);
|
||||
height: calc(100% - 20rem);
|
||||
height: calc(100% - 1.2rem);
|
||||
}
|
||||
|
||||
</style>
|
||||
16
src/pages/pc/word/EditWordDict.vue
Normal file
16
src/pages/pc/word/EditWordDict.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import BasePage from "@/pages/pc/components/BasePage.vue";
|
||||
import WordDictDetail from "@/pages/pc/dict/components/WordDictDetail.vue";
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BasePage>
|
||||
<WordDictDetail/>
|
||||
</BasePage>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
@@ -1,14 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import DictListPanel from "@/pages/pc/components/DictListPanel.vue";
|
||||
import {Icon} from '@iconify/vue'
|
||||
import {ActivityCalendar} from "vue-activity-calendar";
|
||||
import "vue-activity-calendar/style.css";
|
||||
import {useRouter} from "vue-router";
|
||||
import BaseIcon from "@/components/BaseIcon.vue";
|
||||
import {useNav} from "@/utils";
|
||||
import BasePage from "@/pages/pc/components/BasePage.vue";
|
||||
|
||||
const base = useBaseStore()
|
||||
const router = useRouter()
|
||||
const {nav} = useNav()
|
||||
|
||||
function clickEvent(e) {
|
||||
console.log('e', e)
|
||||
@@ -16,110 +18,107 @@ function clickEvent(e) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="word flex justify-center ">
|
||||
<div class="w-5/10 pt-5">
|
||||
<div class="flex gap-6">
|
||||
<div class="card w-1/2 flex flex-col">
|
||||
<div class="title">
|
||||
我的词典
|
||||
</div>
|
||||
<div class="grid flex-1 flex gap-5 mt-4">
|
||||
<div class="p-4 flex-1 rounded-md bg-slate-200 relative">
|
||||
<span>收藏</span>
|
||||
<div class="absolute bottom-4 right-4">{{ base.collectWord.length}}个词</div>
|
||||
</div>
|
||||
<div class="p-4 flex-1 rounded-md bg-slate-200 relative">
|
||||
<span>生词本</span>
|
||||
<div class="absolute bottom-4 right-4">{{ base.wrong2.length}}个词</div>
|
||||
</div>
|
||||
<div class="p-4 flex-1 rounded-md bg-slate-200 relative">
|
||||
<span>简单词</span>
|
||||
<div class="absolute bottom-4 right-4">{{ base.simple2.length}}个词</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
<div class="card ">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="bg-slate-200 p-3 rounded-md cursor-pointer flex items-center">
|
||||
<span class="text-lg font-bold">{{ base.currentWordDict.name }}</span>
|
||||
<Icon icon="gg:arrows-exchange" class="text-2xl ml-2"/>
|
||||
<Icon icon="uil:setting" class="text-2xl ml-2"/>
|
||||
</div>
|
||||
<div class="rounded-xl bg-slate-800 flex items-center py-3 px-5 text-white cursor-pointer"
|
||||
@click="router.push('/practice')">
|
||||
开始学习
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 text-sm">已学习5555个单词的1%</div>
|
||||
<el-progress class="mt-1" :percentage="80" :show-text="false"></el-progress>
|
||||
</div>
|
||||
<div class="card flex gap-3">
|
||||
<div class="bg-slate-200 w-10 h-10 flex center text-2xl rounded">
|
||||
0
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex justify-between">
|
||||
<div class="title">
|
||||
每日目标
|
||||
</div>
|
||||
<div style="color:#ac6ed1;" class="cursor-pointer">
|
||||
更改目标
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2 text-xs">学习 {{ base.currentStudy.word.perDayStudyNumber }} 个单词</div>
|
||||
<el-progress class="flex-1 mt-1" :percentage="80" :show-text="false"></el-progress>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="flex justify-between">
|
||||
<div class="title">
|
||||
其他学习词典
|
||||
</div>
|
||||
<BaseIcon icon="ic:round-add" @click="router.push('/dict')"/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-6 mt-5 ">
|
||||
<div class=" p-4 rounded-md justify-between items-center bg-slate-200 " v-for="i in 3">
|
||||
<div class="flex justify-between w-full">
|
||||
<span>{{ base.currentDict.name }}</span>
|
||||
<div class="text-2xl ml-2 flex gap-4">
|
||||
<Icon icon="hugeicons:delete-02"/>
|
||||
<Icon icon="nonicons:go-16"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 text-sm">已学习5555个单词的1%</div>
|
||||
<el-progress class="mt-1" :percentage="80" color="white" :show-text="false"></el-progress>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center mt-2 text-2xl">
|
||||
<Icon icon="mingcute:down-line"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<BasePage>
|
||||
<div class="flex gap-6">
|
||||
<div class="card w-1/2 flex flex-col">
|
||||
<div class="title">
|
||||
学习记录
|
||||
我的词典
|
||||
</div>
|
||||
<div class="center">
|
||||
<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 class="grid flex-1 flex gap-5 mt-4">
|
||||
<div class="my-dict" @click="nav('edit-word-dict')">
|
||||
<span>收藏</span>
|
||||
<div class="absolute bottom-4 right-4">{{ base.collectWord.length }}个词</div>
|
||||
</div>
|
||||
<div class="my-dict">
|
||||
<span>生词本</span>
|
||||
<div class="absolute bottom-4 right-4">{{ base.wrong2.length }}个词</div>
|
||||
</div>
|
||||
<div class="my-dict">
|
||||
<span>简单词</span>
|
||||
<div class="absolute bottom-4 right-4">{{ base.simple2.length }}个词</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
<div class="card ">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="bg-slate-200 p-3 rounded-md cursor-pointer flex items-center">
|
||||
<span class="text-lg font-bold">{{ base.currentWordDict.name }}</span>
|
||||
<Icon icon="gg:arrows-exchange" class="text-2xl ml-2"/>
|
||||
<Icon icon="uil:setting" class="text-2xl ml-2"/>
|
||||
</div>
|
||||
<div class="rounded-xl bg-slate-800 flex items-center py-3 px-5 text-white cursor-pointer"
|
||||
@click="router.push('/practice')">
|
||||
开始学习
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 text-sm">已学习5555个单词的1%</div>
|
||||
<el-progress class="mt-1" :percentage="80" :show-text="false"></el-progress>
|
||||
</div>
|
||||
<div class="card flex gap-3">
|
||||
<div class="bg-slate-200 w-10 h-10 flex center text-2xl rounded">
|
||||
0
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex justify-between">
|
||||
<div class="title">
|
||||
每日目标
|
||||
</div>
|
||||
<div style="color:#ac6ed1;" class="cursor-pointer">
|
||||
更改目标
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2 text-xs">学习 {{ base.currentStudy.word.perDayStudyNumber }} 个单词</div>
|
||||
<el-progress class="flex-1 mt-1" :percentage="80" :show-text="false"></el-progress>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="flex justify-between">
|
||||
<div class="title">
|
||||
其他学习词典
|
||||
</div>
|
||||
<BaseIcon icon="ic:round-add" @click="router.push('/dict')"/>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-6 mt-5 ">
|
||||
<div class=" p-4 rounded-md justify-between items-center bg-slate-200 " v-for="i in 3">
|
||||
<div class="flex justify-between w-full">
|
||||
<span>{{ base.currentDict.name }}</span>
|
||||
<div class="text-2xl ml-2 flex gap-4">
|
||||
<Icon icon="hugeicons:delete-02"/>
|
||||
<Icon icon="nonicons:go-16"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-5 text-sm">已学习5555个单词的1%</div>
|
||||
<el-progress class="mt-1" :percentage="80" color="white" :show-text="false"></el-progress>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-center mt-2 text-2xl">
|
||||
<Icon icon="mingcute:down-line"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="title">
|
||||
学习记录
|
||||
</div>
|
||||
<div class="center">
|
||||
<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>
|
||||
</BasePage>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -134,4 +133,8 @@ function clickEvent(e) {
|
||||
.title {
|
||||
@apply text-lg font-medium;
|
||||
}
|
||||
|
||||
.my-dict {
|
||||
@apply p-4 flex-1 rounded-md bg-slate-200 relative cursor-pointer;
|
||||
}
|
||||
</style>
|
||||
@@ -23,6 +23,7 @@ import Dict2 from '@/pages/pc/dict2/index.vue'
|
||||
import ArticleIndex from "@/pages/pc/article/ArticleIndex.vue";
|
||||
import HomeIndex from "@/pages/pc/home/HomeIndex.vue";
|
||||
import LearnArticle from "@/pages/pc/article/LearnArticle.vue";
|
||||
import EditWordDict from "@/pages/pc/word/EditWordDict.vue";
|
||||
|
||||
export const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
@@ -31,6 +32,7 @@ export const routes: RouteRecordRaw[] = [
|
||||
children: [
|
||||
{path: 'home', component: HomeIndex},
|
||||
{path: 'word', component: WordHome},
|
||||
{path: 'edit-word-dict', component: EditWordDict},
|
||||
{path: 'dict', component: Dict2},
|
||||
{path: 'practice', component: Practice},
|
||||
{path: 'article', component: ArticleIndex},
|
||||
|
||||
Reference in New Issue
Block a user