save
This commit is contained in:
3
components.d.ts
vendored
3
components.d.ts
vendored
@@ -9,12 +9,10 @@ declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
Add: typeof import('./src/components/Toolbar/Add.vue')['default']
|
||||
AddDict: typeof import('./src/components/Add/AddDict.vue')['default']
|
||||
AddWordDialog: typeof import('./src/components/Modal/AddWordDialog.vue')['default']
|
||||
ArticleList: typeof import('./src/components/Article/ArticleList.vue')['default']
|
||||
Backgorund: typeof import('./src/components/Backgorund.vue')['default']
|
||||
BaseButton: typeof import('./src/components/BaseButton.vue')['default']
|
||||
BaseIcon: typeof import('./src/components/BaseIcon.vue')['default']
|
||||
ChapterDetail: typeof import('./src/components/ChapterDetail.vue')['default']
|
||||
ChapterList: typeof import('./src/components/list/ChapterList.vue')['default']
|
||||
ChapterName: typeof import('./src/components/Toolbar/ChapterName.vue')['default']
|
||||
Close: typeof import('./src/components/icon/Close.vue')['default']
|
||||
@@ -23,7 +21,6 @@ declare module 'vue' {
|
||||
DictGroup: typeof import('./src/components/Toolbar/DictGroup.vue')['default']
|
||||
DictItem: typeof import('./src/components/list/DictItem.vue')['default']
|
||||
DictList: typeof import('./src/components/list/DictList.vue')['default']
|
||||
DictModal: typeof import('./src/components/Modal/DictModal.vue')['default']
|
||||
DictModal2: typeof import('./src/components/Modal/DictModal2.vue')['default']
|
||||
EditAbleText: typeof import('./src/components/EditAbleText.vue')['default']
|
||||
EditArticle: typeof import('./src/components/Article/EditArticle.vue')['default']
|
||||
|
||||
@@ -10,6 +10,7 @@ import {cloneDeep} from "lodash-es";
|
||||
import Backgorund from "@/components/Backgorund.vue";
|
||||
import useTheme from "@/hooks/useTheme.ts";
|
||||
import * as localforage from "localforage";
|
||||
import {useStartKeyboardEventListener} from "@/hooks/event.ts";
|
||||
|
||||
const store = useBaseStore()
|
||||
const runtimeStore = useRuntimeStore()
|
||||
@@ -33,6 +34,7 @@ watch(settingStore.$state, (n) => {
|
||||
|
||||
//检测几个特定词典
|
||||
watch(store.collect.originWords, (n) => {
|
||||
console.log('watch(store.collect.originWords', n)
|
||||
store.collect.words = cloneDeep(n)
|
||||
store.collect.chapterWords = [store.collect.words]
|
||||
})
|
||||
@@ -59,7 +61,7 @@ onMounted(() => {
|
||||
init()
|
||||
})
|
||||
|
||||
// useStartKeyboardEventListener()
|
||||
useStartKeyboardEventListener()
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import {Icon} from "@iconify/vue";
|
||||
import {computed, inject} from "vue"
|
||||
import WordList from "@/components/list/WordList.vue"
|
||||
import {useBaseStore} from "@/stores/base.ts"
|
||||
|
||||
const store = useBaseStore()
|
||||
const back: () => void = inject('back')
|
||||
const stepIndex: any = inject('stepIndex')
|
||||
const tabIndex: any = inject('tabIndex')
|
||||
const isActive = computed(() => {
|
||||
return stepIndex.value === 2 && tabIndex.value === 0 && store.sideIsOpen
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="chapter-detail page">
|
||||
<header>
|
||||
<Icon icon="octicon:arrow-right-24" @click="back" width="20" color="#929596"/>
|
||||
<div class="dict-name">16.</div>
|
||||
</header>
|
||||
<WordList :isActive="isActive" :list="store.chapter" :activeIndex="store.wordIndex"></WordList>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.chapter-wrapper {
|
||||
header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rem;
|
||||
margin-bottom: 10rem;
|
||||
|
||||
.dict-name {
|
||||
font-size: 26rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -36,12 +36,13 @@ let wordList = $ref([])
|
||||
|
||||
let step = $ref(1)
|
||||
let loading = $ref(false)
|
||||
let show = $ref(false)
|
||||
|
||||
watch(() => runtimeStore.showDictModal, (n: boolean) => {
|
||||
runtimeStore.editDict = cloneDeep(store.currentDict)
|
||||
})
|
||||
function close() {
|
||||
show = false
|
||||
}
|
||||
|
||||
async function selectDict(val: { dict: DictResource, index: number }) {
|
||||
async function selectDict(val: { dict: DictResource | Dict, index: number }) {
|
||||
let item = val.dict
|
||||
console.log('item', item)
|
||||
step = 1
|
||||
@@ -49,7 +50,7 @@ async function selectDict(val: { dict: DictResource, index: number }) {
|
||||
detailListTabIndex = 0
|
||||
wordFormMode = FormMode.None
|
||||
loading = true
|
||||
let find: Dict = store.myDictList.find((v: Dict) => v.name === item.name)
|
||||
let find: Dict = store.myDictList.find((v: Dict) => v.id === item.id)
|
||||
if (find) {
|
||||
runtimeStore.editDict = cloneDeep(find)
|
||||
} else {
|
||||
@@ -90,8 +91,6 @@ async function selectDict(val: { dict: DictResource, index: number }) {
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
loading = false
|
||||
}
|
||||
@@ -101,9 +100,6 @@ function changeDict() {
|
||||
close()
|
||||
}
|
||||
|
||||
function close() {
|
||||
runtimeStore.showDictModal = false
|
||||
}
|
||||
|
||||
function groupByDictTags(dictList: DictResource[]) {
|
||||
return dictList.reduce<Record<string, DictResource[]>>((result, dict) => {
|
||||
@@ -218,26 +214,6 @@ const dictRules = reactive<FormRules>({
|
||||
watch(() => dictForm.language, () => isAddDict && (dictForm.category = ''))
|
||||
watch(() => dictForm.category, () => isAddDict && (dictForm.tags = []))
|
||||
|
||||
onMounted(() => {
|
||||
dictionaryResources.map(v => {
|
||||
if (categoryList[v.language]) {
|
||||
if (!categoryList[v.language].find(w => w === v.category)) {
|
||||
categoryList[v.language].push(v.category)
|
||||
}
|
||||
} else {
|
||||
categoryList[v.language] = [v.category]
|
||||
}
|
||||
if (tagList[v.category]) {
|
||||
tagList[v.category] = Array.from(new Set(tagList[v.category].concat(v.tags)))
|
||||
} else {
|
||||
tagList[v.category] = v.tags
|
||||
}
|
||||
})
|
||||
|
||||
// console.log('categoryList', categoryList)
|
||||
// console.log('tagList', tagList)
|
||||
})
|
||||
|
||||
function editDict() {
|
||||
// dictForm.id = store.editDict.id
|
||||
// dictForm.name = store.editDict.name
|
||||
@@ -292,6 +268,10 @@ async function onSubmit() {
|
||||
})
|
||||
}
|
||||
|
||||
/**/
|
||||
/*词典相关*/
|
||||
/**/
|
||||
|
||||
|
||||
/**/
|
||||
/* 单词修改相关*/
|
||||
@@ -440,6 +420,10 @@ function addWord() {
|
||||
wordForm = cloneDeep(DefaultFormWord)
|
||||
}
|
||||
|
||||
/**/
|
||||
/* 单词修改相关*/
|
||||
/**/
|
||||
|
||||
watch(() => step, v => {
|
||||
if (v === 0) {
|
||||
closeWordForm()
|
||||
@@ -447,12 +431,58 @@ watch(() => step, v => {
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
dictionaryResources.map(v => {
|
||||
if (categoryList[v.language]) {
|
||||
if (!categoryList[v.language].find(w => w === v.category)) {
|
||||
categoryList[v.language].push(v.category)
|
||||
}
|
||||
} else {
|
||||
categoryList[v.language] = [v.category]
|
||||
}
|
||||
if (tagList[v.category]) {
|
||||
tagList[v.category] = Array.from(new Set(tagList[v.category].concat(v.tags)))
|
||||
} else {
|
||||
tagList[v.category] = v.tags
|
||||
}
|
||||
})
|
||||
|
||||
emitter.on(EventKey.openDictModal, (type: 'detail' | 'list' | 'my' | 'collect' | 'simple') => {
|
||||
if (type === "detail") {
|
||||
selectDict({dict: store.currentDict, index: 0})
|
||||
}
|
||||
if (type === "list") {
|
||||
currentLanguage = 'en'
|
||||
step = 0
|
||||
}
|
||||
if (type === "my") {
|
||||
currentLanguage = 'my'
|
||||
step = 0
|
||||
}
|
||||
if (type === "collect") {
|
||||
selectDict({dict: store.collect, index: 0})
|
||||
wordFormMode = FormMode.Add
|
||||
addWord()
|
||||
}
|
||||
if (type === "simple") {
|
||||
selectDict({dict: store.simple, index: 0})
|
||||
addWord()
|
||||
}
|
||||
|
||||
show = true
|
||||
})
|
||||
|
||||
// console.log('categoryList', categoryList)
|
||||
// console.log('tagList', tagList)
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal
|
||||
:header="false"
|
||||
v-model="runtimeStore.showDictModal"
|
||||
v-model="show"
|
||||
:show-close="false">
|
||||
<div id="DictDialog">
|
||||
<Slide :slide-count="2" :step="step">
|
||||
|
||||
@@ -1,550 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import {dictionaryResources} from '@/assets/dictionary.ts'
|
||||
import {useBaseStore} from "@/stores/base.ts"
|
||||
import {watch} from "vue"
|
||||
import {DefaultDict, Dict, DictResource, DictType, languageCategoryOptions, Sort} from "@/types.ts"
|
||||
import {chunk, cloneDeep, groupBy, reverse, shuffle} from "lodash-es";
|
||||
import {$computed, $ref} from "vue/macros";
|
||||
import Modal from "@/components/Modal/Modal.vue";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
import {Icon} from '@iconify/vue';
|
||||
import DictGroup from "@/components/Toolbar/DictGroup.vue";
|
||||
import {v4 as uuidv4} from "uuid";
|
||||
import {ActivityCalendar} from "vue-activity-calendar";
|
||||
import "vue-activity-calendar/style.css";
|
||||
import ChapterList from "@/components/list/ChapterList.vue";
|
||||
import WordListModal from "@/components/Modal/WordListModal.vue";
|
||||
import {isArticle} from "@/hooks/article.ts";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts";
|
||||
|
||||
const baseStore = useBaseStore()
|
||||
const settingStore = useSettingStore()
|
||||
const runtimeStore = useRuntimeStore()
|
||||
let currentLanguage = $ref('en')
|
||||
let currentTranslateLanguage = $ref('common')
|
||||
let groupByLanguage = groupBy(dictionaryResources, 'language')
|
||||
let translateLanguageList = $ref([])
|
||||
|
||||
let step = $ref(1)
|
||||
let loading = $ref(false)
|
||||
|
||||
watch(() => runtimeStore.showDictModal, (n: boolean) => {
|
||||
runtimeStore.editDict = cloneDeep(baseStore.currentDict)
|
||||
})
|
||||
|
||||
async function selectDict(item: DictResource) {
|
||||
console.log('item', item)
|
||||
step = 1
|
||||
loading = true
|
||||
let find: Dict = baseStore.myDictList.find((v: Dict) => v.name === item.name)
|
||||
if (find) {
|
||||
runtimeStore.editDict = cloneDeep(find)
|
||||
if (find.type === DictType.article) {
|
||||
if (!find.articles.length) {
|
||||
let r = await fetch(`./dicts/${find.language}/${find.type}/${find.translateLanguage}/${find.url}`)
|
||||
let v = await r.json()
|
||||
runtimeStore.editDict.articles = v.map(s => {
|
||||
s.id = uuidv4()
|
||||
return s
|
||||
})
|
||||
}
|
||||
}
|
||||
loading = false
|
||||
} else {
|
||||
let data: Dict = {
|
||||
...cloneDeep(DefaultDict),
|
||||
...item,
|
||||
}
|
||||
runtimeStore.editDict = cloneDeep(data)
|
||||
let r = await fetch(`./dicts/${data.language}/${data.type}/${data.translateLanguage}/${item.url}`)
|
||||
r.json().then(v => {
|
||||
console.log('v', v)
|
||||
if (data.type === DictType.article) {
|
||||
runtimeStore.editDict.articles = cloneDeep(v.map(s => {
|
||||
s.id = uuidv4()
|
||||
return s
|
||||
}))
|
||||
} else {
|
||||
runtimeStore.editDict.originWords = v
|
||||
runtimeStore.editDict.words = v
|
||||
runtimeStore.editDict.chapterWords = chunk(v, runtimeStore.editDict.chapterWordNumber)
|
||||
console.log(' runtimeStore.editDict', runtimeStore.editDict)
|
||||
}
|
||||
loading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function changeDict() {
|
||||
baseStore.changeDict(runtimeStore.editDict)
|
||||
close()
|
||||
}
|
||||
|
||||
function close() {
|
||||
runtimeStore.showDictModal = false
|
||||
}
|
||||
|
||||
function groupByDictTags(dictList: DictResource[]) {
|
||||
return dictList.reduce<Record<string, DictResource[]>>((result, dict) => {
|
||||
dict.tags.forEach((tag) => {
|
||||
if (Object.prototype.hasOwnProperty.call(result, tag)) {
|
||||
result[tag].push(dict)
|
||||
} else {
|
||||
result[tag] = [dict]
|
||||
}
|
||||
})
|
||||
return result
|
||||
}, {})
|
||||
}
|
||||
|
||||
const groupByTranslateLanguage = $computed(() => {
|
||||
let data: any
|
||||
if (currentLanguage === 'article') {
|
||||
let articleList = dictionaryResources.filter(v => v.type === 'article')
|
||||
data = groupBy(articleList, 'translateLanguage')
|
||||
} else {
|
||||
data = groupBy(groupByLanguage[currentLanguage], 'translateLanguage')
|
||||
}
|
||||
translateLanguageList = Object.keys(data)
|
||||
currentTranslateLanguage = translateLanguageList[0]
|
||||
return data
|
||||
})
|
||||
|
||||
const groupedByCategoryAndTag = $computed(() => {
|
||||
const currentTranslateLanguageDictList = groupByTranslateLanguage[currentTranslateLanguage]
|
||||
const groupByCategory = groupBy(currentTranslateLanguageDictList, 'category')
|
||||
|
||||
let data = []
|
||||
for (const [key, value] of Object.entries(groupByCategory)) {
|
||||
data.push([key, groupByDictTags(value)])
|
||||
}
|
||||
// console.log('data', data)
|
||||
return data
|
||||
})
|
||||
|
||||
function clickEvent(e) {
|
||||
console.log('e', e)
|
||||
}
|
||||
|
||||
const dictIsArticle = $computed(() => {
|
||||
return isArticle(runtimeStore.editDict.type)
|
||||
})
|
||||
|
||||
function showAllWordModal() {
|
||||
emitter.emit(EventKey.openWordListModal, {
|
||||
title: runtimeStore.editDict.name,
|
||||
translateLanguage: runtimeStore.editDict.translateLanguage,
|
||||
list: runtimeStore.editDict.words
|
||||
})
|
||||
}
|
||||
|
||||
function resetChapterList() {
|
||||
runtimeStore.editDict.chapterWords = chunk(runtimeStore.editDict.words, runtimeStore.editDict.chapterWordNumber)
|
||||
}
|
||||
|
||||
function changeSort(v) {
|
||||
if (v === Sort.normal) {
|
||||
runtimeStore.editDict.words = cloneDeep(runtimeStore.editDict.originWords)
|
||||
} else if (v === Sort.random) {
|
||||
runtimeStore.editDict.words = shuffle(cloneDeep(runtimeStore.editDict.originWords))
|
||||
} else {
|
||||
runtimeStore.editDict.words = reverse(cloneDeep(runtimeStore.editDict.originWords))
|
||||
}
|
||||
resetChapterList()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal
|
||||
:header="false"
|
||||
v-model="runtimeStore.showDictModal"
|
||||
:show-close="false">
|
||||
<div class="slide">
|
||||
<div class="slide-list" :class="`step${step}`">
|
||||
<div class="dict-page">
|
||||
<header>
|
||||
<div class="tabs">
|
||||
<div class="tab"
|
||||
:class="currentLanguage === item.id && 'active'"
|
||||
@click="currentLanguage = item.id"
|
||||
v-for="item in languageCategoryOptions">
|
||||
<img :src='item.flag'/>
|
||||
<span>{{ item.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<Icon @click="close"
|
||||
class="hvr-grow pointer"
|
||||
width="20" color="#929596"
|
||||
icon="ion:close-outline"/>
|
||||
</header>
|
||||
<div class="page-content">
|
||||
<div class="dict-list-wrapper">
|
||||
<div class="translate">
|
||||
<span>翻译:</span>
|
||||
<el-radio-group v-model="currentTranslateLanguage">
|
||||
<el-radio-button border v-for="i in translateLanguageList" :label="i">{{ i }}</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<DictGroup
|
||||
v-for="item in groupedByCategoryAndTag"
|
||||
:select-dict-name="runtimeStore.editDict.resourceId"
|
||||
@selectDict="selectDict"
|
||||
@detail="step = 1"
|
||||
:groupByTag="item[1]"
|
||||
:category="item[0]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dict-detail-page">
|
||||
<header>
|
||||
<div class="left" @click.stop="step = 0">
|
||||
<Icon icon="octicon:arrow-left-24" class="go" width="20"/>
|
||||
<div class="title">
|
||||
词典详情
|
||||
</div>
|
||||
</div>
|
||||
<Icon @click="close"
|
||||
class="hvr-grow pointer"
|
||||
width="20" color="#929596"
|
||||
icon="ion:close-outline"/>
|
||||
</header>
|
||||
<div class="page-content">
|
||||
<div class="detail">
|
||||
<div class="name">{{ runtimeStore.editDict.name }}</div>
|
||||
<div class="desc">{{ runtimeStore.editDict.description }}</div>
|
||||
<div class="num"
|
||||
v-if="dictIsArticle"
|
||||
>总文章:{{ runtimeStore.editDict.articles.length }}篇
|
||||
</div>
|
||||
<div class="num" v-else>
|
||||
总词汇:<span class="count"
|
||||
@click="showAllWordModal"
|
||||
>{{ runtimeStore.editDict.originWords.length }}词</span>
|
||||
</div>
|
||||
<div class="num">开始日期:-</div>
|
||||
<div class="num">花费时间:-</div>
|
||||
<div class="num">累积错误:-</div>
|
||||
<div class="num">进度:
|
||||
<el-progress :percentage="0"
|
||||
:stroke-width="8"
|
||||
:show-text="false"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting">
|
||||
<div class="common-title">学习设置</div>
|
||||
<div class="row" v-if="!isArticle(runtimeStore.editDict.type)">
|
||||
<div class="label">每章单词数</div>
|
||||
<el-slider :min="10"
|
||||
:step="10"
|
||||
:max="100"
|
||||
v-model="runtimeStore.editDict.chapterWordNumber"
|
||||
@change="resetChapterList"
|
||||
/>
|
||||
<div class="option">
|
||||
<span>{{ runtimeStore.editDict.chapterWordNumber }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="label">单词顺序</div>
|
||||
<div class="option">
|
||||
<el-radio-group v-model="runtimeStore.editDict.sort"
|
||||
@change="changeSort"
|
||||
>
|
||||
<el-radio :label="Sort.normal" size="large">默认</el-radio>
|
||||
<el-radio :label="Sort.random" size="large">随机</el-radio>
|
||||
<el-radio :label="Sort.reverse" size="large">反转</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="label">学习模式</div>
|
||||
<div class="option">
|
||||
<el-radio-group v-model="settingStore.dictation">
|
||||
<el-radio :label="false" size="large">再认</el-radio>
|
||||
<el-radio :label="true" size="large">拼写</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="label">单词发音</div>
|
||||
<div class="option">
|
||||
<el-radio-group v-model="settingStore.wordSoundType">
|
||||
<el-radio label="us" size="large">美音</el-radio>
|
||||
<el-radio label="uk" size="large">英音</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="label">单词自动发音</div>
|
||||
<div class="option">
|
||||
<el-switch v-model="settingStore.wordSound"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="label">是否显示翻译</div>
|
||||
<div class="option">
|
||||
<el-switch v-model="settingStore.translate"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="label">忽略大小写</div>
|
||||
<div class="option">
|
||||
<el-switch v-model="settingStore.ignoreCase"
|
||||
inline-prompt
|
||||
active-text="开"
|
||||
inactive-text="关"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="other" v-loading="loading">
|
||||
<div class="common-title">
|
||||
<template v-if="dictIsArticle">
|
||||
文章列表:共{{ runtimeStore.editDict.articles.length }}章
|
||||
</template>
|
||||
<template v-else>
|
||||
章节列表:共{{
|
||||
runtimeStore.editDict.chapterWords.length
|
||||
}}章(每章{{ runtimeStore.editDict.chapterWordNumber }}词)
|
||||
</template>
|
||||
</div>
|
||||
<ChapterList
|
||||
:is-article="dictIsArticle"
|
||||
v-model:active-index="runtimeStore.editDict.chapterIndex"
|
||||
:dict="runtimeStore.editDict"/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="false" class="activity">
|
||||
<ActivityCalendar
|
||||
:data="[{ date: '2023-05-22', count: 5 }]"
|
||||
:width="40"
|
||||
:height="7"
|
||||
:cellLength="16"
|
||||
:cellInterval="8"
|
||||
:fontSize="12"
|
||||
:showLevelFlag="false"
|
||||
:showWeekDayFlag="false"
|
||||
:clickEvent="clickEvent"
|
||||
/>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<!-- <BaseButton @click="step = 0">导出</BaseButton>-->
|
||||
<BaseButton @click="close">关闭</BaseButton>
|
||||
<BaseButton @click="changeDict">切换</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
<WordListModal/>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "@/assets/css/variable.scss";
|
||||
|
||||
$modal-mask-bg: rgba(#000, .15);
|
||||
$radius: 16rem;
|
||||
$time: 0.3s;
|
||||
$header-height: 60rem;
|
||||
|
||||
.slide {
|
||||
width: 1000rem;
|
||||
height: 75vh;
|
||||
|
||||
.slide-list {
|
||||
width: 200%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
transition: all .5s;
|
||||
}
|
||||
|
||||
.step1 {
|
||||
transform: translate3d(-50%, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.dict-page {
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
$header-height: 60rem;
|
||||
padding: var(--space);
|
||||
padding-top: 0;
|
||||
box-sizing: border-box;
|
||||
|
||||
header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: $header-height;
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
gap: 20rem;
|
||||
|
||||
.tab {
|
||||
color: var(--color-font-1);
|
||||
cursor: pointer;
|
||||
padding: 10rem;
|
||||
padding-bottom: 5rem;
|
||||
transition: all .5s;
|
||||
border-bottom: 2px solid transparent;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6rem;
|
||||
|
||||
&.active {
|
||||
border-bottom: 2px solid $main;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 30rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.page-content {
|
||||
display: flex;
|
||||
height: calc(100% - $header-height);
|
||||
|
||||
.dict-list-wrapper {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
padding-right: var(--space);
|
||||
|
||||
.translate {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--color-font-1);
|
||||
margin-bottom: 30rem;
|
||||
|
||||
& > span {
|
||||
font-size: 22rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dict-detail-page {
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
$header-height: 60rem;
|
||||
padding: var(--space);
|
||||
padding-top: 0;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
header {
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
height: $header-height;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: var(--color-font-3);
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
gap: 10rem;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.page-content {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
position: relative;
|
||||
gap: var(--space);
|
||||
|
||||
.detail {
|
||||
overflow: auto;
|
||||
flex: 3;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10rem;
|
||||
min-height: 100rem;
|
||||
position: relative;
|
||||
border-radius: 10rem;
|
||||
background: var(--color-second-bg);
|
||||
color: var(--color-font-1);
|
||||
font-size: 14rem;
|
||||
|
||||
.name {
|
||||
font-size: 28rem;
|
||||
margin-bottom: 10rem;
|
||||
}
|
||||
|
||||
.desc {
|
||||
font-size: 18rem;
|
||||
margin-bottom: 30rem;
|
||||
}
|
||||
|
||||
.count {
|
||||
cursor: pointer;
|
||||
border-bottom: 2px solid var(--color-item-active);
|
||||
}
|
||||
}
|
||||
|
||||
.setting {
|
||||
overflow: auto;
|
||||
flex: 5;
|
||||
background: white;
|
||||
border-radius: 10rem;
|
||||
background: var(--color-second-bg);
|
||||
color: var(--color-font-1);
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 40rem;
|
||||
word-break: keep-all;
|
||||
gap: 10rem;
|
||||
|
||||
.el-radio {
|
||||
margin-right: 10rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.other {
|
||||
flex: 5;
|
||||
border-radius: 10rem;
|
||||
background: var(--color-second-bg);
|
||||
color: var(--color-font-1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.activity {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.footer {
|
||||
box-sizing: content-box;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-end;
|
||||
gap: var(--space);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -133,6 +133,13 @@ onUnmounted(() => {
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
:deep(.el-progress-bar__inner) {
|
||||
background: var(--color-scrollbar);
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
@@ -3,7 +3,7 @@ import {useBaseStore} from "@/stores/base.ts"
|
||||
import WordList from "@/components/list/WordList.vue"
|
||||
|
||||
import {$ref} from "vue/macros"
|
||||
import {computed, provide, watch} from "vue"
|
||||
import {computed, onMounted, provide, watch} from "vue"
|
||||
import {Dict, DictType, ShortcutKey} from "@/types.ts"
|
||||
import PopConfirm from "@/components/PopConfirm.vue"
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
@@ -34,10 +34,13 @@ let practiceType = $ref(DictType.word)
|
||||
|
||||
function changeIndex(i: number, dict: Dict) {
|
||||
store.changeDict(dict, dict.chapterIndex, i, practiceType)
|
||||
setTimeout(() => {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
emitter.on(EventKey.changeDict, () => {
|
||||
tabIndex = 0
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const {
|
||||
delWrongWord,
|
||||
@@ -79,17 +82,17 @@ const {
|
||||
<el-radio-button border :label="DictType.word">单词</el-radio-button>
|
||||
<el-radio-button border :label="DictType.article">文章</el-radio-button>
|
||||
</el-radio-group>
|
||||
<Tooltip title="添加">
|
||||
<IconWrapper>
|
||||
<Icon icon="fluent:add-12-regular" @click="emitter.emit(EventKey.editDict,store.collect)"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<div class="dict-name" v-if="practiceType === DictType.word && store.collect.words.length">
|
||||
{{ store.collect.words.length }}个单词
|
||||
</div>
|
||||
<div class="dict-name" v-if="practiceType === DictType.article && store.collect.articles.length">
|
||||
{{ store.collect.articles.length }}篇文章
|
||||
</div>
|
||||
<Tooltip title="添加">
|
||||
<IconWrapper>
|
||||
<Icon icon="fluent:add-12-regular" @click="emitter.emit(EventKey.openDictModal,'collect')"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<template v-if="store.currentDict.type !== DictType.collect &&
|
||||
(
|
||||
@@ -130,9 +133,16 @@ const {
|
||||
</div>
|
||||
</div>
|
||||
<div class="slide-item">
|
||||
<div class="panel-page-item" v-if="store.simple.words.length">
|
||||
<div class="panel-page-item">
|
||||
<div class="list-header">
|
||||
<div class="dict-name">总词数:{{ store.simple.words.length }}</div>
|
||||
<div class="left">
|
||||
<div class="dict-name">总词数:{{ store.simple.words.length }}</div>
|
||||
<Tooltip title="添加">
|
||||
<IconWrapper>
|
||||
<Icon icon="fluent:add-12-regular" @click="emitter.emit(EventKey.openDictModal,'simple')"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<template v-if="store.currentDict.type !== DictType.simple && store.simple.words.length">
|
||||
<PopConfirm
|
||||
:title="`确认切换?`"
|
||||
@@ -143,6 +153,7 @@ const {
|
||||
</template>
|
||||
</div>
|
||||
<CommonWordList
|
||||
v-if="store.simple.words.length"
|
||||
class="word-list"
|
||||
:list="store.simple.words">
|
||||
<template v-slot="{word,index}">
|
||||
@@ -153,8 +164,8 @@ const {
|
||||
icon="solar:trash-bin-minimalistic-linear"/>
|
||||
</template>
|
||||
</CommonWordList>
|
||||
<Empty v-else/>
|
||||
</div>
|
||||
<Empty v-else/>
|
||||
</div>
|
||||
<div class="slide-item">
|
||||
<div class="panel-page-item" v-if="store.wrong.words.length">
|
||||
|
||||
@@ -99,7 +99,7 @@ function openSetting() {
|
||||
}
|
||||
|
||||
function openDictDetail() {
|
||||
runtimeStore.showDictModal = true
|
||||
emitter.emit(EventKey.openDictModal, 'detail')
|
||||
}
|
||||
|
||||
function toggleConciseMode() {
|
||||
@@ -164,7 +164,7 @@ onUnmounted(() => {
|
||||
<PracticeWord ref="practiceRef" v-else/>
|
||||
<Footer/>
|
||||
</div>
|
||||
<!-- <AddWordDialog></AddWordDialog>-->
|
||||
<!-- <AddWordDialog></AddWordDialog>-->
|
||||
<DictModal/>
|
||||
<SettingModal v-if="runtimeStore.showSettingModal" @close="runtimeStore.showSettingModal = false"/>
|
||||
<Statistics/>
|
||||
|
||||
@@ -247,7 +247,7 @@ function changePracticeArticle(val: Article) {
|
||||
<div class="left">
|
||||
<Tooltip title="切换词典">
|
||||
<IconWrapper>
|
||||
<Icon @click="runtimeStore.showDictModal = true" icon="basil:exchange-outline"/>
|
||||
<Icon @click="emitter.emit(EventKey.openDictModal,'list')" icon="basil:exchange-outline"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<div class="title">
|
||||
|
||||
@@ -280,7 +280,7 @@ onUnmounted(() => {
|
||||
<div class="left">
|
||||
<Tooltip title="切换词典">
|
||||
<IconWrapper>
|
||||
<Icon @click="runtimeStore.showDictModal = true" icon="basil:exchange-outline"/>
|
||||
<Icon @click="emitter.emit(EventKey.openDictModal,'list')" icon="basil:exchange-outline"/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
<div class="title">
|
||||
@@ -320,13 +320,13 @@ onUnmounted(() => {
|
||||
<BaseIcon
|
||||
v-if="!isWordSimple(word)"
|
||||
class-name="easy"
|
||||
@click="toggleWordCollect(word)"
|
||||
@click="toggleWordSimple(word)"
|
||||
title="标记为简单词"
|
||||
icon="material-symbols:check-circle-outline-rounded"/>
|
||||
<BaseIcon
|
||||
v-else
|
||||
class-name="fill"
|
||||
@click="toggleWordCollect(word)"
|
||||
@click="toggleWordSimple(word)"
|
||||
title="取消标记简单词"
|
||||
icon="material-symbols:check-circle-rounded"/>
|
||||
</template>
|
||||
|
||||
@@ -17,6 +17,7 @@ import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {$ref} from "vue/macros";
|
||||
import {ShortcutKey} from "@/types.ts";
|
||||
import ChapterName from "@/components/Toolbar/ChapterName.vue";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts";
|
||||
|
||||
const {toggleTheme} = useTheme()
|
||||
const store = useBaseStore()
|
||||
@@ -64,7 +65,7 @@ watch(() => store.load, n => {
|
||||
<div class="dict-name">
|
||||
<Tooltip
|
||||
:title="`词典详情(快捷键:${settingStore.shortcutKeyMap[ShortcutKey.OpenDictDetail]})`">
|
||||
<div class="info hvr-grow" @click="runtimeStore.showDictModal = true">
|
||||
<div class="info hvr-grow" @click="emitter.emit(EventKey.openDictModal,'detail')">
|
||||
{{ store.currentDict.name }} {{ practiceStore.repeatNumber ? ' 复习错词' : '' }}
|
||||
</div>
|
||||
</Tooltip>
|
||||
@@ -102,7 +103,16 @@ watch(() => store.load, n => {
|
||||
|
||||
<RepeatSetting/>
|
||||
|
||||
<!-- <Add/>-->
|
||||
<!-- <Add/>-->
|
||||
|
||||
<Tooltip title="添加">
|
||||
<IconWrapper>
|
||||
<Icon icon="ic:outline-cloud-upload"
|
||||
@click="emitter.emit(EventKey.openDictModal,'my')"
|
||||
/>
|
||||
</IconWrapper>
|
||||
</Tooltip>
|
||||
|
||||
|
||||
<Tooltip title="反馈">
|
||||
<IconWrapper>
|
||||
|
||||
@@ -23,7 +23,7 @@ const emit = defineEmits<{
|
||||
<template v-if="dict.name">
|
||||
<div class="name">{{ dict.name }}</div>
|
||||
<div class="desc">{{ dict.description }}</div>
|
||||
<div class="num">{{ dict.length }}词</div>
|
||||
<div class="num">{{ dict.length ?? dict.originWords.length }}词</div>
|
||||
</template>
|
||||
<div v-else class="add" @click.stop="emit('add')">
|
||||
<Icon icon="fluent:add-20-filled" width="38" color="#929596"/>
|
||||
|
||||
@@ -1,64 +1,117 @@
|
||||
import {Word} from "@/types.ts";
|
||||
import {Dict, DictType, Word} from "@/types.ts";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {chunk, cloneDeep} from "lodash-es";
|
||||
import {v4 as uuidv4} from "uuid";
|
||||
|
||||
|
||||
export function useWordOptions() {
|
||||
const store = useBaseStore()
|
||||
const store = useBaseStore()
|
||||
|
||||
function isWordCollect(val: Word) {
|
||||
return !!store.collect.originWords.find(v => v.name.toLowerCase() === val.name.toLowerCase())
|
||||
}
|
||||
|
||||
function toggleWordCollect(val: Word) {
|
||||
let rIndex = store.collect.originWords.findIndex(v => v.name.toLowerCase() === val.name.toLowerCase())
|
||||
if (rIndex > -1) {
|
||||
store.collect.originWords.splice(rIndex, 1)
|
||||
} else {
|
||||
let rIndex = store.simple.originWords.findIndex(v => v.name.toLowerCase() === val.name.toLowerCase())
|
||||
if (rIndex > -1) {
|
||||
store.simple.originWords.splice(rIndex, 1)
|
||||
}
|
||||
store.collect.originWords.push(val)
|
||||
function isWordCollect(val: Word) {
|
||||
return !!store.collect.originWords.find(v => v.name.toLowerCase() === val.name.toLowerCase())
|
||||
}
|
||||
}
|
||||
|
||||
function isWordSimple(val: Word) {
|
||||
return !!store.simple.originWords.find(v => v.name.toLowerCase() === val.name.toLowerCase())
|
||||
}
|
||||
|
||||
function toggleWordSimple(val: Word) {
|
||||
let rIndex = store.simple.originWords.findIndex(v => v.name.toLowerCase() === val.name.toLowerCase())
|
||||
if (rIndex > -1) {
|
||||
store.simple.originWords.splice(rIndex, 1)
|
||||
} else {
|
||||
let rIndex = store.collect.originWords.findIndex(v => v.name.toLowerCase() === val.name.toLowerCase())
|
||||
if (rIndex > -1) {
|
||||
store.collect.originWords.splice(rIndex, 1)
|
||||
}
|
||||
store.simple.originWords.push(val)
|
||||
function toggleWordCollect(val: Word) {
|
||||
let rIndex = store.collect.originWords.findIndex(v => v.name.toLowerCase() === val.name.toLowerCase())
|
||||
if (rIndex > -1) {
|
||||
store.collect.originWords.splice(rIndex, 1)
|
||||
} else {
|
||||
let rIndex = store.simple.originWords.findIndex(v => v.name.toLowerCase() === val.name.toLowerCase())
|
||||
if (rIndex > -1) {
|
||||
store.simple.originWords.splice(rIndex, 1)
|
||||
}
|
||||
store.collect.originWords.push(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function delWrongWord(val: Word) {
|
||||
let rIndex = store.wrong.originWords.findIndex(v => v.name.toLowerCase() === val.name.toLowerCase())
|
||||
if (rIndex > -1) {
|
||||
store.wrong.originWords.splice(rIndex, 1)
|
||||
function isWordSimple(val: Word) {
|
||||
return !!store.simple.originWords.find(v => v.name.toLowerCase() === val.name.toLowerCase())
|
||||
}
|
||||
}
|
||||
|
||||
function delSimpleWord(val: Word) {
|
||||
let rIndex = store.simple.originWords.findIndex(v => v.name.toLowerCase() === val.name.toLowerCase())
|
||||
if (rIndex > -1) {
|
||||
store.simple.originWords.splice(rIndex, 1)
|
||||
function toggleWordSimple(val: Word) {
|
||||
let rIndex = store.simple.originWords.findIndex(v => v.name.toLowerCase() === val.name.toLowerCase())
|
||||
if (rIndex > -1) {
|
||||
store.simple.originWords.splice(rIndex, 1)
|
||||
} else {
|
||||
let rIndex = store.collect.originWords.findIndex(v => v.name.toLowerCase() === val.name.toLowerCase())
|
||||
if (rIndex > -1) {
|
||||
store.collect.originWords.splice(rIndex, 1)
|
||||
}
|
||||
store.simple.originWords.push(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
isWordCollect,
|
||||
toggleWordCollect,
|
||||
isWordSimple,
|
||||
toggleWordSimple,
|
||||
delWrongWord,
|
||||
delSimpleWord
|
||||
}
|
||||
function delWrongWord(val: Word) {
|
||||
let rIndex = store.wrong.originWords.findIndex(v => v.name.toLowerCase() === val.name.toLowerCase())
|
||||
if (rIndex > -1) {
|
||||
store.wrong.originWords.splice(rIndex, 1)
|
||||
}
|
||||
}
|
||||
|
||||
function delSimpleWord(val: Word) {
|
||||
let rIndex = store.simple.originWords.findIndex(v => v.name.toLowerCase() === val.name.toLowerCase())
|
||||
if (rIndex > -1) {
|
||||
store.simple.originWords.splice(rIndex, 1)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
isWordCollect,
|
||||
toggleWordCollect,
|
||||
isWordSimple,
|
||||
toggleWordSimple,
|
||||
delWrongWord,
|
||||
delSimpleWord
|
||||
}
|
||||
}
|
||||
|
||||
export async function checkDictHasTranslate(dict: Dict) {
|
||||
let dictResourceUrl = `./dicts/${dict.language}/${dict.type}/${dict.translateLanguage}/${dict.url}`;
|
||||
if ([
|
||||
DictType.word,
|
||||
DictType.customWord,
|
||||
].includes(dict.type)) {
|
||||
if (!dict.originWords.length) {
|
||||
let r = await fetch(dictResourceUrl)
|
||||
// let r = await fetch(`.${dict.url}`)
|
||||
let v = await r.json()
|
||||
if (dict.translateLanguage === 'common') {
|
||||
const runtimeStore = useRuntimeStore()
|
||||
let r2 = await fetch('./translate/en2zh_CN-min.json')
|
||||
// fetch('http://sc.ttentau.top/en2zh_CN-min.json').then(r2 => {
|
||||
let list: Word[] = await r2.json()
|
||||
|
||||
runtimeStore.translateWordList = list
|
||||
|
||||
dict.originWords = cloneDeep(v)
|
||||
dict.words = cloneDeep(v)
|
||||
dict.chapterWords = chunk(dict.words, dict.chapterWordNumber)
|
||||
dict.chapterWords[dict.chapterIndex].map((w: Word) => {
|
||||
let res = list.find(a => a.name === w.name)
|
||||
if (res) w = Object.assign(w, res)
|
||||
})
|
||||
} else {
|
||||
dict.originWords = cloneDeep(v)
|
||||
dict.words = cloneDeep(v)
|
||||
dict.chapterWords = chunk(dict.words, dict.chapterWordNumber)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ([
|
||||
DictType.article,
|
||||
DictType.customArticle,
|
||||
].includes(dict.type)) {
|
||||
if (!dict.articles.length) {
|
||||
let r = await fetch(dictResourceUrl)
|
||||
let s: any[] = await r.json()
|
||||
dict.articles = cloneDeep(s.map(v => {
|
||||
v.id = uuidv4()
|
||||
return v
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,17 +1,16 @@
|
||||
import {defineStore} from 'pinia'
|
||||
import {DefaultDict, DefaultWord, Dict, DictType, DisplayStatistics, SaveDict, Word} from "../types.ts"
|
||||
import {chunk, cloneDeep} from "lodash-es";
|
||||
import {DefaultDict, Dict, DictType, DisplayStatistics, SaveDict, Word} from "../types.ts"
|
||||
import {chunk, cloneDeep, merge} from "lodash-es";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts"
|
||||
import {v4 as uuidv4} from 'uuid';
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import * as localforage from "localforage";
|
||||
import {sizeofByte} from "@/utils";
|
||||
import {checkDictHasTranslate} from "@/hooks/dict.ts";
|
||||
|
||||
export interface BaseState {
|
||||
myDictList: Dict[],
|
||||
current: {
|
||||
index: number,
|
||||
editIndex: number,
|
||||
practiceType: DictType,//练习类型,目前仅词典为collect时判断是练单词还是文章使用
|
||||
},
|
||||
simpleWords: string[],
|
||||
@@ -116,7 +115,6 @@ export const useBaseStore = defineStore('base', {
|
||||
],
|
||||
current: {
|
||||
index: 3,
|
||||
editIndex: 0,
|
||||
// dictType: DictType.article,
|
||||
// index: 0,
|
||||
practiceType: DictType.word,
|
||||
@@ -134,7 +132,7 @@ export const useBaseStore = defineStore('base', {
|
||||
},
|
||||
getters: {
|
||||
collect() {
|
||||
return this.myDictList[0]
|
||||
return this.myDictList[0] ?? {}
|
||||
},
|
||||
simple(): Dict {
|
||||
return this.myDictList[1]
|
||||
@@ -158,21 +156,9 @@ export const useBaseStore = defineStore('base', {
|
||||
DictType.customArticle
|
||||
].includes(this.currentDict.type)
|
||||
},
|
||||
editDict(state: BaseState) {
|
||||
if (state.current.editIndex === -1) {
|
||||
return cloneDeep(DefaultDict)
|
||||
}
|
||||
return state.myDictList.filter(v => [DictType.customWord, DictType.customArticle].includes(v.type))[state.current.editIndex - 3]
|
||||
},
|
||||
currentDict(): Dict {
|
||||
return this.myDictList[this.current.index]
|
||||
},
|
||||
currentEditDict(): Dict {
|
||||
return this.myDictList[this.current.editIndex]
|
||||
},
|
||||
wordIndex(state: BaseState): number {
|
||||
return this.currentDict.wordIndex
|
||||
},
|
||||
chapter(state: BaseState): Word[] {
|
||||
return this.currentDict.chapterWords[this.currentDict.chapterIndex] ?? []
|
||||
},
|
||||
@@ -184,9 +170,10 @@ export const useBaseStore = defineStore('base', {
|
||||
let title = ''
|
||||
switch (this.currentDict.type) {
|
||||
case DictType.collect:
|
||||
if (state.current.practiceType === DictType.word) {
|
||||
if (state.current.practiceType === DictType.article || state.current.practiceType === DictType.customArticle) {
|
||||
return `第${this.currentDict.chapterIndex + 1}章`
|
||||
}
|
||||
return ''
|
||||
case DictType.word:
|
||||
case DictType.customWord:
|
||||
return `第${this.currentDict.chapterIndex + 1}章`
|
||||
@@ -196,17 +183,16 @@ export const useBaseStore = defineStore('base', {
|
||||
},
|
||||
actions: {
|
||||
setState(obj: any) {
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
this[key] = value
|
||||
}
|
||||
// console.log('this/', this)
|
||||
//这样不会丢失watch的值的引用
|
||||
merge(this, obj)
|
||||
},
|
||||
async init() {
|
||||
return new Promise(async resolve => {
|
||||
try {
|
||||
let configStr: string = await localforage.getItem(SaveDict.key)
|
||||
// console.log('s', configStr)
|
||||
console.log(configStr)
|
||||
console.log('s', new Blob([configStr]).size)
|
||||
configStr = ''
|
||||
if (configStr) {
|
||||
let data = JSON.parse(configStr)
|
||||
let state: BaseState = data.val
|
||||
@@ -219,7 +205,7 @@ export const useBaseStore = defineStore('base', {
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('读取本地dict数据失败',e)
|
||||
console.error('读取本地dict数据失败', e)
|
||||
}
|
||||
|
||||
if (this.current.index < 3) {
|
||||
@@ -239,21 +225,13 @@ export const useBaseStore = defineStore('base', {
|
||||
let r2 = await fetch('./translate/en2zh_CN-min.json')
|
||||
// fetch('http://sc.ttentau.top/en2zh_CN-min.json').then(r2 => {
|
||||
let list: Word[] = await r2.json()
|
||||
|
||||
runtimeStore.translateWordList = list
|
||||
|
||||
this.currentDict.originWords = cloneDeep(v)
|
||||
this.currentDict.words = cloneDeep(v)
|
||||
this.currentDict.chapterWords = chunk(this.currentDict.words, this.currentDict.chapterWordNumber)
|
||||
this.currentDict.chapterWords[this.currentDict.chapterIndex].map((w: Word) => {
|
||||
let res = list.find(a => a.name === w.name)
|
||||
if (res) w = Object.assign(w, res)
|
||||
})
|
||||
} else {
|
||||
this.currentDict.originWords = cloneDeep(v)
|
||||
this.currentDict.words = cloneDeep(v)
|
||||
this.currentDict.chapterWords = chunk(this.currentDict.words, this.currentDict.chapterWordNumber)
|
||||
if (list && list.length) {
|
||||
runtimeStore.translateWordList = list
|
||||
}
|
||||
}
|
||||
this.currentDict.originWords = cloneDeep(v)
|
||||
this.currentDict.words = cloneDeep(v)
|
||||
this.currentDict.chapterWords = chunk(this.currentDict.words, this.currentDict.chapterWordNumber)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,38 +258,45 @@ export const useBaseStore = defineStore('base', {
|
||||
this.currentDict.statistics.push(statistics)
|
||||
}
|
||||
},
|
||||
async changeDict(dict: Dict, chapterIndex: number = dict.chapterIndex, chapterWordIndex: number = dict.chapterWordNumber, practiceType: DictType) {
|
||||
async changeDict(dict: Dict, chapterIndex: number = dict.chapterIndex, wordIndex: number = dict.wordIndex, practiceType: DictType) {
|
||||
//TODO 保存统计
|
||||
// this.saveStatistics()
|
||||
console.log('changeDict', cloneDeep(dict), chapterIndex, chapterWordIndex)
|
||||
console.log('changeDict', cloneDeep(dict), chapterIndex, wordIndex)
|
||||
this.currentDict.type = dict.type
|
||||
this.current.practiceType = practiceType
|
||||
if ([DictType.collect,
|
||||
DictType.simple,
|
||||
DictType.wrong].includes(dict.type)) {
|
||||
this[dict.type].chapterIndex = 0
|
||||
this[dict.type].chapterWordIndex = chapterWordIndex
|
||||
this[dict.type].chapterWords = [this[dict.type].words]
|
||||
dict.chapterIndex = 0
|
||||
dict.wordIndex = wordIndex
|
||||
dict.chapterWordNumber = dict.words.length
|
||||
dict.chapterWords = [dict.words]
|
||||
} else {
|
||||
if (dict.type === DictType.article || dict.type === DictType.customArticle) {
|
||||
if (chapterIndex > dict.articles.length) {
|
||||
dict.chapterIndex = 0
|
||||
dict.wordIndex = 0
|
||||
}
|
||||
} else {
|
||||
if (chapterIndex > dict.chapterWords.length) {
|
||||
dict.chapterIndex = 0
|
||||
dict.wordIndex = 0
|
||||
}
|
||||
}
|
||||
let rIndex = this.myDictList.findIndex((v: Dict) => v.name === dict.name)
|
||||
if (rIndex > -1) {
|
||||
this.myDictList[rIndex] = dict
|
||||
this.current.index = rIndex
|
||||
} else {
|
||||
this.myDictList.push(cloneDeep(dict))
|
||||
this.current.index = this.myDictList.length - 1
|
||||
}
|
||||
}
|
||||
|
||||
// await checkDictHasTranslate(dict)
|
||||
|
||||
let rIndex = this.myDictList.findIndex((v: Dict) => v.id === dict.id)
|
||||
if (rIndex > -1) {
|
||||
this.myDictList[rIndex] = dict
|
||||
this.current.index = rIndex
|
||||
} else {
|
||||
this.myDictList.push(cloneDeep(dict))
|
||||
this.current.index = this.myDictList.length - 1
|
||||
}
|
||||
emitter.emit(EventKey.resetWord)
|
||||
emitter.emit(EventKey.changeDict)
|
||||
}
|
||||
},
|
||||
})
|
||||
@@ -3,8 +3,10 @@ import mitt from 'mitt'
|
||||
export const emitter = mitt()
|
||||
export const EventKey = {
|
||||
resetWord: 'resetWord',
|
||||
changeDict: 'changeDict',
|
||||
openStatModal: 'openStatModal',
|
||||
openWordListModal: 'openWordListModal',
|
||||
openDictModal: 'openDictModal',
|
||||
openArticleListModal: 'openArticleListModal',
|
||||
closeOther: 'closeOther',
|
||||
keydown: 'keydown',
|
||||
|
||||
@@ -1,42 +1,3 @@
|
||||
export function getRandom(a: number, b: number): number {
|
||||
return Math.random() * (b - a) + a;
|
||||
}
|
||||
|
||||
export function sizeofByte(str, charset = 'utf-16') {
|
||||
let total = 0
|
||||
let charCode
|
||||
|
||||
charset = charset.toLowerCase()
|
||||
|
||||
if (charset === 'utf-8' || charset === 'utf8') {
|
||||
for (let i = 0, len = str.length; i < len; i++) {
|
||||
charCode = str.codePointAt(i)
|
||||
|
||||
if (charCode <= 0x007f) {
|
||||
total += 1
|
||||
} else if (charCode <= 0x07ff) {
|
||||
total += 2
|
||||
} else if (charCode <= 0xffff) {
|
||||
total += 3
|
||||
} else {
|
||||
total += 4
|
||||
i++
|
||||
}
|
||||
}
|
||||
} else if (charset === 'utf-16' || charset === 'utf16') {
|
||||
for (let i = 0, len = str.length; i < len; i++) {
|
||||
charCode = str.codePointAt(i)
|
||||
|
||||
if (charCode <= 0xffff) {
|
||||
total += 2
|
||||
} else {
|
||||
total += 4
|
||||
i++
|
||||
}
|
||||
}
|
||||
} else {
|
||||
total = str.replace(/[^\x00-\xff]/g, 'aa').length
|
||||
}
|
||||
|
||||
return total
|
||||
}
|
||||
Reference in New Issue
Block a user