This commit is contained in:
zyronon
2024-05-20 14:10:33 +08:00
parent 3c0a0df3bf
commit 8775997b6b
7 changed files with 404 additions and 82 deletions

View File

@@ -0,0 +1,92 @@
<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";
const base = useBaseStore()
const router = useRouter()
function clickEvent(e) {
console.log('e', 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" v-for="i in 3">
<span>收藏</span>
<div class="absolute bottom-4 right-4">333个词</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.currentDict.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>
</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>
</div>
</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>

View File

@@ -0,0 +1,164 @@
<script setup lang="ts">
import Toolbar from "@/pages/pc/components/toolbar/index.vue"
import {onMounted, onUnmounted, watch} from "vue";
import {usePracticeStore} from "@/stores/practice.ts";
import Footer from "@/pages/pc/practice/Footer.vue";
import {useBaseStore} from "@/stores/base.ts";
import Statistics from "@/pages/pc/practice/Statistics.vue";
import {emitter, EventKey} from "@/utils/eventBus.ts";
import {useSettingStore} from "@/stores/setting.ts";
import {useRuntimeStore} from "@/stores/runtime.ts";
import {MessageBox} from "@/utils/MessageBox.tsx";
import PracticeArticle from "@/pages/pc/practice/practice-article/index.vue";
import {ShortcutKey} from "@/types.ts";
import DictModal from "@/pages/pc/components/dialog/DictDiglog.vue";
import {useStartKeyboardEventListener} from "@/hooks/event.ts";
import useTheme from "@/hooks/theme.ts";
const practiceStore = usePracticeStore()
const store = useBaseStore()
const settingStore = useSettingStore()
const runtimeStore = useRuntimeStore()
const {toggleTheme} = useTheme()
const practiceRef: any = $ref()
watch(practiceStore, () => {
if (practiceStore.inputWordNumber < 1) {
return practiceStore.correctRate = -1
}
if (practiceStore.wrongWordNumber > practiceStore.inputWordNumber) {
return practiceStore.correctRate = 0
}
practiceStore.correctRate = 100 - Math.trunc(((practiceStore.wrongWordNumber) / (practiceStore.inputWordNumber)) * 100)
})
function test() {
MessageBox.confirm(
'2您选择了“本地翻译”但译文内容却为空白是否修改为“不需要翻译”并保存?',
'1提示',
() => {
console.log('ok')
},
() => {
console.log('cencal')
})
}
function write() {
// console.log('write')
settingStore.dictation = true
repeat()
}
//TODO 需要判断是否已忽略
function repeat() {
// console.log('repeat')
emitter.emit(EventKey.resetWord)
practiceRef.getCurrentPractice()
}
function prev() {
// console.log('next')
if (store.currentDict.chapterIndex === 0) {
ElMessage.warning('已经在第一章了~')
} else {
store.currentDict.chapterIndex--
repeat()
}
}
function toggleShowTranslate() {
settingStore.translate = !settingStore.translate
}
function toggleDictation() {
settingStore.dictation = !settingStore.dictation
}
function openSetting() {
runtimeStore.showSettingModal = true
}
function openDictDetail() {
emitter.emit(EventKey.openDictModal, 'detail')
}
function toggleConciseMode() {
settingStore.showToolbar = !settingStore.showToolbar
settingStore.showPanel = settingStore.showToolbar
}
function togglePanel() {
settingStore.showPanel = !settingStore.showPanel
}
function jumpSpecifiedChapter(val: number) {
store.currentDict.chapterIndex = val
repeat()
}
onMounted(() => {
emitter.on(EventKey.write, write)
emitter.on(EventKey.repeat, repeat)
emitter.on(EventKey.jumpSpecifiedChapter, jumpSpecifiedChapter)
emitter.on(ShortcutKey.PreviousChapter, prev)
emitter.on(ShortcutKey.RepeatChapter, repeat)
emitter.on(ShortcutKey.DictationChapter, write)
emitter.on(ShortcutKey.ToggleShowTranslate, toggleShowTranslate)
emitter.on(ShortcutKey.ToggleDictation, toggleDictation)
emitter.on(ShortcutKey.OpenSetting, openSetting)
emitter.on(ShortcutKey.OpenDictDetail, openDictDetail)
emitter.on(ShortcutKey.ToggleTheme, toggleTheme)
emitter.on(ShortcutKey.ToggleConciseMode, toggleConciseMode)
emitter.on(ShortcutKey.TogglePanel, togglePanel)
})
onUnmounted(() => {
emitter.off(EventKey.write, write)
emitter.off(EventKey.repeat, repeat)
emitter.off(EventKey.jumpSpecifiedChapter, jumpSpecifiedChapter)
emitter.off(ShortcutKey.PreviousChapter, prev)
emitter.off(ShortcutKey.RepeatChapter, repeat)
emitter.off(ShortcutKey.DictationChapter, write)
emitter.off(ShortcutKey.ToggleShowTranslate, toggleShowTranslate)
emitter.off(ShortcutKey.ToggleDictation, toggleDictation)
emitter.off(ShortcutKey.OpenSetting, openSetting)
emitter.off(ShortcutKey.OpenDictDetail, openDictDetail)
emitter.off(ShortcutKey.ToggleTheme, toggleTheme)
emitter.off(ShortcutKey.ToggleConciseMode, toggleConciseMode)
emitter.off(ShortcutKey.TogglePanel, togglePanel)
})
useStartKeyboardEventListener()
</script>
<template>
<div class="practice-wrapper">
<Toolbar/>
<PracticeArticle ref="practiceRef"/>
<Footer/>
</div>
<DictModal/>
<Statistics/>
</template>
<style scoped lang="scss">
.practice-wrapper {
font-size: 0.9rem;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
//padding-right: var(--practice-wrapper-padding-right);
transform: translateX(var(--practice-wrapper-translateX));
}
</style>

View File

@@ -1,8 +1,7 @@
<script setup lang="ts">
import {useBaseStore} from "@/stores/base.ts"
import {onMounted} from "vue"
import {DefaultDict, Dict, DictResource, DictType} from "@/types.ts"
import {chunk, cloneDeep} from "lodash-es";
import {chunk} from "lodash-es";
import {$computed, $ref} from "vue/macros";
import BaseButton from "@/components/BaseButton.vue";
import {Icon} from '@iconify/vue';
@@ -14,11 +13,7 @@ import {useSettingStore} from "@/stores/setting.ts";
import {emitter, EventKey} from "@/utils/eventBus.ts";
import BaseIcon from "@/components/BaseIcon.vue";
import Dialog from "@/pages/pc/components/dialog/Dialog.vue";
import EditBatchArticleModal from "@/pages/pc/components/article/EditBatchArticleModal.vue";
import {nanoid} from "nanoid";
import {useRouter} from "vue-router";
import {MessageBox} from "@/utils/MessageBox.tsx";
import {getDictFile} from "@/utils";
const store = useBaseStore()
const settingStore = useSettingStore()
@@ -30,69 +25,10 @@ let chapterWordNumber = $ref(0)
let toggleLoading = $ref(false)
async function selectDict(val: { dict: DictResource | Dict, index: number }) {
let item = val.dict
// console.log('item', item)
let find: Dict = store.myDictList.find((v: Dict) => v.id === item.id)
if (find) {
runtimeStore.editDict = cloneDeep(find)
} else {
runtimeStore.editDict = cloneDeep({
...cloneDeep(DefaultDict),
...item,
})
runtimeStore.editDict.id = nanoid(6)
//设置默认章节单词数
runtimeStore.editDict.chapterWordNumber = settingStore.chapterWordNumber
}
if ([DictType.collect, DictType.simple, DictType.wrong].includes(runtimeStore.editDict.type)) {
} else {
//如果不是自定义词典并且有url地址才去下载
if (!runtimeStore.editDict.isCustom && runtimeStore.editDict.url) {
let url = `./dicts/${runtimeStore.editDict.language}/${runtimeStore.editDict.type}/${runtimeStore.editDict.translateLanguage}/${runtimeStore.editDict.url}`;
if (runtimeStore.editDict.type === DictType.word) {
if (!runtimeStore.editDict.originWords.length) {
let v = await getDictFile(url)
v.map(s => {
s.id = nanoid(6)
})
runtimeStore.editDict.originWords = cloneDeep(v)
} else {
runtimeStore.editDict.length = runtimeStore.editDict.words.length
}
}
if (runtimeStore.editDict.type === DictType.article) {
if (!runtimeStore.editDict.articles.length) {
let v = await getDictFile(url)
v.map(s => {
s.id = nanoid(6)
})
runtimeStore.editDict.articles = cloneDeep(v)
} else {
runtimeStore.editDict.length = runtimeStore.editDict.articles.length
}
}
}
}
chapterWordNumber = runtimeStore.editDict.chapterWordNumber
}
function close() {
show = false
}
//TODO 切大词典太卡了
function changeDict() {
close()
store.changeDict(runtimeStore.editDict)
setTimeout(() => {
runtimeStore.editDict = cloneDeep(DefaultDict)
})
ElMessage.success('切换成功')
}
const dictIsArticle = $computed(() => {
return isArticle(runtimeStore.editDict.type)
})
@@ -117,7 +53,6 @@ function resetChapterList(v: number) {
}
}
function option(type: string) {
show = false
setTimeout(() => {
@@ -126,10 +61,7 @@ function option(type: string) {
}
onMounted(() => {
emitter.on(EventKey.openDictModal, (type: 'detail' | 'list' | 'my') => {
if (type === "detail") {
selectDict({dict: store.currentDict, index: 0})
}
emitter.on(EventKey.openDictModal, (typ) => {
show = true
})
})
@@ -145,7 +77,7 @@ onMounted(() => {
<div id="DictDialog">
<header>
<div class="text-2xl">
{{ runtimeStore.editDict.name }}
{{ store.currentDict.name }}
</div>
<Icon @click="close"
class="hvr-grow pointer"
@@ -153,13 +85,13 @@ onMounted(() => {
icon="ion:close-outline"/>
</header>
<div class="detail">
<div class="desc">{{ runtimeStore.editDict.description }}</div>
<div class="desc">{{ store.currentDict.description }}</div>
<div class="text flex align-center">
<div v-if="dictIsArticle">总文章{{ runtimeStore.editDict.articles.length }}
<div v-if="dictIsArticle">总文章{{ store.currentDict.articles.length }}
</div>
<div v-else>总词汇
<span class="count" @click="showAllWordModal">{{
runtimeStore.editDict.originWords.length
store.currentDict.originWords.length
}}</span>
</div>
<BaseIcon icon="mi:add"
@@ -181,7 +113,7 @@ onMounted(() => {
class="my-slider"
:min="10"
:step="10"
:max="runtimeStore.editDict.words.length < 10 ? 10 : 500"
:max="store.currentDict.words.length < 10 ? 10 : 500"
size="small"
v-model="chapterWordNumber"
@change="resetChapterList"
@@ -189,17 +121,15 @@ onMounted(() => {
</div>
<div class="notice">
<span class="text">最小:10</span>
<span class="text">最大:{{ runtimeStore.editDict.words.length < 10 ? 10 : 500 }}</span>
<span class="text">最大:{{ store.currentDict.words.length < 10 ? 10 : 500 }}</span>
</div>
</div>
<div class="footer">
<BaseButton @click="close">关闭</BaseButton>
<BaseButton :loading="toggleLoading" @click="changeDict">切换</BaseButton>
</div>
</div>
</Dialog>
<WordListDialog/>
<EditBatchArticleModal/>
</template>
<style scoped lang="scss">

View File

@@ -0,0 +1,129 @@
<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";
const base = useBaseStore()
const router = useRouter()
function clickEvent(e) {
console.log('e', 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" v-for="i in 3">
<span>收藏</span>
<div class="absolute bottom-4 right-4">333个词</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.currentDict.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">学习 50 个单词</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">
<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>
</div>
</div>
</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>

View File

@@ -21,12 +21,17 @@ const router = useRouter()
<div class="aside">
<div class="top">
<Logo/>
<div class="row" @click="router.push('/home')">
<Icon icon="material-symbols-light:dictionary-outline-sharp"/>
<!-- <Icon icon="streamline:dictionary-language-book"/>-->
<span>主页</span>
</div>
<div class="row" @click="router.push('/word')">
<Icon icon="material-symbols-light:dictionary-outline-sharp"/>
<!-- <Icon icon="streamline:dictionary-language-book"/>-->
<span>单词</span>
</div>
<div class="row">
<div class="row" @click="router.push('/article')">
<Icon icon="ph:article-ny-times"/>
<span>文章</span>
</div>

View File

@@ -143,9 +143,7 @@ useStartKeyboardEventListener()
<template>
<div class="practice-wrapper">
<Toolbar/>
<!-- <BaseButton @click="test">test</BaseButton>-->
<PracticeArticle ref="practiceRef" v-if="store.isArticle"/>
<PracticeWord ref="practiceRef" v-else/>
<PracticeWord ref="practiceRef"/>
<Footer/>
</div>
<DictModal/>