Develop dictionary management function zyronon Today 1:17

This commit is contained in:
zyronon
2023-11-25 23:43:57 +08:00
parent 0254bf1e24
commit 502d4942dd
10 changed files with 776 additions and 691 deletions

View File

@@ -18,7 +18,8 @@ export interface ModalProps {
header?: boolean
confirmButtonText?: string
cancelButtonText?: string,
keyboard?: boolean
keyboard?: boolean,
confirm?: any
}
const props = withDefaults(defineProps<ModalProps>(), {
@@ -39,6 +40,7 @@ const emit = defineEmits([
'cancel',
])
let confirmButtonLoading = $ref(false)
let zIndex = $ref(999)
let visible = $ref(false)
let openTime = $ref(Date.now())
@@ -118,6 +120,11 @@ useEventListener('keyup', (e: KeyboardEvent) => {
})
async function ok() {
if (props.confirm) {
confirmButtonLoading = true
await props.confirm()
confirmButtonLoading = false
}
await close()
emit('ok')
}
@@ -162,7 +169,10 @@ async function cancel() {
</div>
<div class="right">
<BaseButton type="link" @click="cancel">{{ cancelButtonText }}</BaseButton>
<BaseButton @click="ok">{{ confirmButtonText }}</BaseButton>
<BaseButton
:loading="confirmButtonLoading"
@click="ok">{{ confirmButtonText }}
</BaseButton>
</div>
</div>
</div>

View File

@@ -54,10 +54,14 @@ function reset() {
}
function scrollToBottom() {
listRef.scrollToIndex(props.list.length - 1)
listRef.scrollToBottom()
}
defineExpose({scrollToBottom})
function scrollToItem(index: number) {
listRef.scrollToItem(index)
}
defineExpose({scrollToBottom, scrollToItem})
</script>

View File

@@ -14,7 +14,6 @@ const store = useBaseStore()
const settingStore = useSettingStore()
let show = $ref(false)
let radio1 = $ref('1')
useWindowClick(() => show = false)
let timer = 0

View File

@@ -1,12 +1,15 @@
<script setup lang="ts">
import {no} from "@/utils";
import {Word} from "@/types.ts";
import {Sort, Word} from "@/types.ts";
import VirtualWordList2 from "@/components/list/VirtualWordList2.vue";
import BaseIcon from "@/components/BaseIcon.vue";
import Empty from "@/components/Empty.vue";
import {$computed, $ref} from "vue/macros";
import {watch} from "vue";
import MiniDialog from "@/components/dialog/MiniDialog.vue";
import BaseButton from "@/components/BaseButton.vue";
import {useWindowClick} from "@/hooks/event.ts";
import {reverse, shuffle} from "lodash-es";
const props = defineProps<{
title: string,
@@ -18,7 +21,8 @@ const props = defineProps<{
const emit = defineEmits<{
add: []
edit: [val: { word: Word, index: number }]
del: [val: { word: Word, index: number }]
del: [val: { word: Word, index: number }],
'update:list': [val: Word[]]
}>()
let checkedAll = $ref(false)
@@ -57,6 +61,33 @@ function del(val: { word: Word, index: number }) {
props.list.splice(val.index, 1)
emit('del', val)
}
function sort(type: Sort) {
if (type === Sort.reverse) {
ElMessage.success('已翻转排序')
emit('update:list', reverse(props.list))
}
if (type === Sort.random) {
ElMessage.success('已随机排序')
emit('update:list', shuffle(props.list))
}
}
let listRef: any = $ref()
function scrollToBottom() {
listRef.scrollToBottom()
}
function scrollToItem(index: number) {
listRef.scrollToItem(index)
}
defineExpose({scrollToBottom, scrollToItem})
let show = $ref(false)
useWindowClick(() => show = false)
</script>
<template>
@@ -65,11 +96,27 @@ function del(val: { word: Word, index: number }) {
<div class="common-title">
<span>{{ title }}</span>
<div class="options">
<BaseIcon
v-if="list.length"
@click="no"
icon="icon-park-outline:sort-two"
title="改变顺序"/>
<div class="setting"
v-if="list.length"
@click.stop="null">
<BaseIcon
title="改变顺序"
icon="icon-park-outline:sort-two"
@click="show = !show"
/>
<MiniDialog
v-model="show"
style="width: 130rem;"
>
<div class="mini-row-title">
列表循环设置
</div>
<div class="mini-row">
<BaseButton size="small" @click="sort(Sort.reverse)">翻转</BaseButton>
<BaseButton size="small" @click="sort(Sort.random)">随机</BaseButton>
</div>
</MiniDialog>
</div>
<BaseIcon
v-if="showAdd"
@click="emit('add')"
@@ -93,6 +140,7 @@ function del(val: { word: Word, index: number }) {
</div>
<div class="wrapper">
<VirtualWordList2
ref="listRef"
:list="list"
v-if="list.length"
@click="handleCheckedChange"

View File

@@ -30,6 +30,7 @@ import {no} from "@/utils";
import Test from "@/pages/dict/Test.vue";
import VirtualWordList2 from "@/components/list/VirtualWordList2.vue";
import ChapterWordList from "@/pages/dict/ChapterWordList.vue";
import {MessageBox} from "@/utils/MessageBox.tsx";
const store = useBaseStore()
const settingStore = useSettingStore()
@@ -43,6 +44,9 @@ let step = $ref(1)
let loading = $ref(false)
let chapterList2 = $ref([])
let chapterWordNumber = $ref(settingStore.chapterWordNumber)
let chapterWordListRef: any = $ref()
let residueWordListRef: any = $ref()
let chapterListRef: any = $ref()
let chapterIndex = $ref(-1)
let residueWordList = $ref([])
@@ -65,35 +69,35 @@ async function selectDict(val: {
...cloneDeep(DefaultDict),
...item,
})
//设置默认章节单词数
runtimeStore.editDict.chapterWordNumber = settingStore.chapterWordNumber
}
if ([DictType.collect, DictType.simple, DictType.wrong].includes(runtimeStore.editDict.type)) {
} else {
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 r = await fetch(url)
let v = await r.json()
v.map(s => {
s.id = nanoid(6)
})
runtimeStore.editDict.originWords = cloneDeep(v)
changeSort(runtimeStore.editDict.sort)
//如果不是自定义词典并且有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 r = await fetch(url)
let v = await r.json()
v.map(s => {
s.id = nanoid(6)
})
runtimeStore.editDict.originWords = cloneDeep(v)
changeSort(runtimeStore.editDict.sort)
}
}
}
if (runtimeStore.editDict.type === DictType.customWord) {
}
if (runtimeStore.editDict.type === DictType.article) {
if (!runtimeStore.editDict.articles.length) {
let r = await fetch(url)
let v = await r.json()
runtimeStore.editDict.articles = cloneDeep(v.map(s => {
s.id = uuidv4()
return s
}))
if (runtimeStore.editDict.type === DictType.article) {
if (!runtimeStore.editDict.articles.length) {
let r = await fetch(url)
let v = await r.json()
runtimeStore.editDict.articles = cloneDeep(v.map(s => {
s.id = uuidv4()
return s
}))
}
}
}
}
@@ -153,13 +157,13 @@ const dictIsArticle = $computed(() => {
return isArticle(runtimeStore.editDict.type)
})
function changeSort(v) {
function changeSort(v: Sort) {
if (v === Sort.normal) {
runtimeStore.editDict.words = cloneDeep(runtimeStore.editDict.originWords)
} else if (v === Sort.random) {
runtimeStore.editDict.words = shuffle(cloneDeep(runtimeStore.editDict.originWords))
runtimeStore.editDict.words = shuffle(runtimeStore.editDict.originWords)
} else {
runtimeStore.editDict.words = reverse(cloneDeep(runtimeStore.editDict.originWords))
runtimeStore.editDict.words = reverse(runtimeStore.editDict.originWords)
}
resetChapterList()
}
@@ -290,13 +294,11 @@ const wordRules = reactive<FormRules>({
{max: 30, message: '名称不能超过30个字符', trigger: 'blur'},
],
})
let wordListRef: any = $ref()
//同步到我的词典列表
function syncMyDictList() {
//任意修改,都将其变为自定义词典
if (runtimeStore.editDict.type === DictType.word) runtimeStore.editDict.type = DictType.customWord
if (runtimeStore.editDict.type === DictType.article) runtimeStore.editDict.type = DictType.customArticle
runtimeStore.editDict.isCustom = true
let rIndex = store.myDictList.findIndex(v => v.id === runtimeStore.editDict.id)
if (rIndex > -1) {
@@ -315,47 +317,29 @@ 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
if (wordFormData.where === 'chapter') {
r = currentChapterWordList.find(v => v.name === wordForm.name)
if (r) return ElMessage.warning('已有相同名称单词!')
else {
currentChapterWordList.push(data)
}
} else {
r = residueWordList.find(v => v.name === wordForm.name)
if (r) return ElMessage.warning('已有相同名称单词!')
else {
residueWordList.push(data)
}
}
let r = list.find(v => v.name === wordForm.name)
if (r) return ElMessage.warning('已有相同名称单词!')
else list.push(data)
runtimeStore.editDict.originWords.push(data)
runtimeStore.editDict.words.push(data)
ElMessage.success('添加成功')
wordForm = cloneDeep(DefaultFormWord)
setTimeout(wordListRef?.scrollToBottom, 100)
console.log('runtimeStore.editDict', runtimeStore.editDict)
setTimeout(listRef?.scrollToBottom, 100)
} else {
//直接使用引用修改
let r
if (wordFormData.where === 'chapter') {
r = currentChapterWordList.find(v => v.id === wordFormData.id)
if (r) assign(r, data)
} else {
r = residueWordList.find(v => v.id === wordFormData.id)
if (r) assign(r, data)
}
let r = list.find(v => v.id === wordFormData.id)
if (r) assign(r, data)
//同步修改到列表
r = runtimeStore.editDict.originWords.find(v => v.id === wordFormData.id)
if (r) assign(r, data)
r = runtimeStore.editDict.words.find(v => v.id === wordFormData.id)
if (r) assign(r, data)
ElMessage.success('修改成功')
}
syncMyDictList()
@@ -421,7 +405,6 @@ watch(() => store.load, v => {
}
})
const playWordAudio = usePlayWordAudio()
let showAllocationChapterDialog = $ref(false)
onMounted(() => {
@@ -468,12 +451,17 @@ onMounted(() => {
// console.log('tagList', tagList)
})
let currentChapterWordList: any[] = $computed(() => {
return runtimeStore.editDict.chapterWords[chapterIndex] ?? []
let chapterWordList: any[] = $computed({
get() {
return runtimeStore.editDict.chapterWords[chapterIndex] ?? []
},
set(newValue) {
runtimeStore.editDict.chapterWords[chapterIndex] = newValue
}
})
let currentChapterWordListCheckedTotal = $computed(() => {
return currentChapterWordList.filter(v => v.checked).length
let chapterWordListCheckedTotal = $computed(() => {
return chapterWordList.filter(v => v.checked).length
})
let residueWordListCheckedTotal = $computed(() => {
@@ -481,19 +469,19 @@ let residueWordListCheckedTotal = $computed(() => {
})
function handleChangeCurrentChapter(index: number) {
currentChapterWordList.map(v => v.checked = false)
chapterWordList.map(v => v.checked = false)
chapterIndex = index
closeWordForm()
}
function toResidueWordList() {
let list = currentChapterWordList.filter(v => v.checked)
let list = chapterWordList.filter(v => v.checked)
if (wordFormData.type === FormMode.Edit && wordFormData.where === 'chapter') {
if (list.find(v => v.name === wordForm.name)) {
wordFormData.where = 'residue'
}
}
runtimeStore.editDict.chapterWords[chapterIndex] = currentChapterWordList.filter(v => !v.checked)
runtimeStore.editDict.chapterWords[chapterIndex] = chapterWordList.filter(v => !v.checked)
list.map(v => v.checked = false)
residueWordList = residueWordList.concat(list)
}
@@ -508,12 +496,15 @@ function toChapterWordList() {
}
residueWordList = residueWordList.filter(v => !v.checked)
list.map(v => v.checked = false)
runtimeStore.editDict.chapterWords[chapterIndex] = currentChapterWordList.concat(list)
runtimeStore.editDict.chapterWords[chapterIndex] = chapterWordList.concat(list)
}
function addNewChapter() {
runtimeStore.editDict.chapterWords.push([])
chapterList2 = Array.from({length: runtimeStore.editDict.chapterWords.length}).map((v, i) => ({id: i}))
chapterListRef?.scrollToItem(chapterList2.length - 1)
ElMessage.success('新增章节成功')
console.log('scrollToBottom', chapterListRef)
}
function delWordChapter(index: number) {
@@ -529,14 +520,17 @@ function delWordChapter(index: number) {
syncMyDictList()
}
function resetChapterList() {
function resetChapterList(num?: number) {
if (num !== undefined) {
runtimeStore.editDict.chapterWordNumber = num
}
residueWordList = []
chapterIndex = -1
runtimeStore.editDict.words.map(v => v.checked = false)
runtimeStore.editDict.chapterWords = chunk(runtimeStore.editDict.words, chapterWordNumber)
runtimeStore.editDict.chapterWords = chunk(runtimeStore.editDict.words, runtimeStore.editDict.chapterWordNumber)
chapterList2 = Array.from({length: runtimeStore.editDict.chapterWords.length}).map((v, i) => ({id: i}))
console.log('runtimeStore.editDict.chapterWords',runtimeStore.editDict.chapterWords)
console.log('chapterList2',chapterList2)
// console.log('runtimeStore.editDict.chapterWords',runtimeStore.editDict.chapterWords)
// console.log('chapterList2',chapterList2)
}
function exportData() {
@@ -551,6 +545,31 @@ const isPinDict = $computed(() => {
return [DictType.collect, DictType.wrong, DictType.simple].includes(runtimeStore.editDict.type)
})
async function resetDict() {
MessageBox.confirm(
'删除所有自定义内容: 章节、排序、单词,并恢复至默认状态,确认恢复?',
'提示',
async () => {
isAddDict = false
dictForm = cloneDeep(DefaultDictForm)
closeWordForm()
chapterIndex = -1
if (runtimeStore.editDict.url) {
runtimeStore.editDict.chapterWordNumber = settingStore.chapterWordNumber
let url = `./dicts/${runtimeStore.editDict.language}/${runtimeStore.editDict.type}/${runtimeStore.editDict.translateLanguage}/${runtimeStore.editDict.url}`;
let r = await fetch(url)
let v = await r.json()
v.map(s => {
s.id = nanoid(6)
})
runtimeStore.editDict.originWords = cloneDeep(v)
changeSort(runtimeStore.editDict.sort)
}
}
)
// runtimeStore.editDict
}
</script>
<template>
@@ -608,7 +627,7 @@ const isPinDict = $computed(() => {
<template v-if="!isPinDict">
<BaseIcon icon="tabler:edit" @click='editDict'/>
<BaseIcon icon="ph:star" @click='no'/>
<BaseButton size="small" @click="no">恢复默认</BaseButton>
<BaseButton size="small" @click="resetDict">恢复默认</BaseButton>
</template>
<div class="import hvr-grow">
<BaseButton size="small">导入</BaseButton>
@@ -641,6 +660,7 @@ const isPinDict = $computed(() => {
<div class="wrapper">
<RecycleScroller
v-if="chapterList2.length"
ref="chapterListRef"
style="height: 100%;"
:items="chapterList2"
:item-size="63"
@@ -671,30 +691,34 @@ const isPinDict = $computed(() => {
<Empty v-else/>
</div>
</div>
<ChapterWordList :title="`${chapterIndex > -1 ? `第${chapterIndex + 1}章` : ''} 单词列表`"
:show-add="chapterIndex > -1"
@add="addWord('chapter')"
@del="delWord"
empty-title="请选择章节"
@edit="val => editWord(val.word,val.index,'chapter')"
:list="currentChapterWordList"/>
<ChapterWordList
ref="chapterWordListRef"
:title="`${chapterIndex > -1 ? `第${chapterIndex + 1}章` : ''} 单词列表`"
:show-add="chapterIndex > -1"
@add="addWord('chapter')"
@del="delWord"
:empty-title="chapterIndex === -1?'请选择章节':null"
@edit="val => editWord(val.word,val.index,'chapter')"
v-model:list="chapterWordList"/>
<div class="options-column">
<BaseButton @click="toChapterWordList"
:disabled="residueWordListCheckedTotal === 0">
&lt;
</BaseButton>
<BaseButton @click="toResidueWordList"
:disabled="currentChapterWordListCheckedTotal === 0">
:disabled="chapterWordListCheckedTotal === 0">
&gt;
</BaseButton>
</div>
<ChapterWordList title="未分配单词列表"
:empty-title="null"
:show-add="true"
@add="addWord('residue')"
@del="delWord"
@edit="val => editWord(val.word,val.index,'residue')"
:list="residueWordList"/>
<ChapterWordList
ref="residueWordListRef"
title="未分配单词列表"
:empty-title="null"
:show-add="true"
@add="addWord('residue')"
@del="delWord"
@edit="val => editWord(val.word,val.index,'residue')"
v-model:list="residueWordList"/>
<div class="right-column">
<div class="add" v-if="wordFormData.type">
<div class="common-title">
@@ -796,7 +820,7 @@ const isPinDict = $computed(() => {
<Dialog
title="智能分配单词"
:footer="true"
@ok="resetChapterList"
@ok="resetChapterList(chapterWordNumber)"
@cancel="chapterWordNumber = settingStore.chapterWordNumber"
v-model="showAllocationChapterDialog">
<div class="allocation-chapter">

View File

@@ -5,17 +5,16 @@ 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 {checkDictHasTranslate} from "@/hooks/dict.ts";
import {nanoid} from "nanoid";
export interface BaseState {
myDictList: Dict[],
current: {
index: number,
practiceType: DictType,//练习类型目前仅词典为collect时判断是练单词还是文章使用
},
simpleWords: string[],
load: boolean
myDictList: Dict[],
current: {
index: number,
practiceType: DictType,//练习类型目前仅词典为collect时判断是练单词还是文章使用
},
simpleWords: string[],
load: boolean
}
// words: [
@@ -64,242 +63,244 @@ export interface BaseState {
// ],
export const useBaseStore = defineStore('base', {
state: (): BaseState => {
return {
myDictList: [
{
...cloneDeep(DefaultDict),
id: 'collect',
name: '收藏',
type: DictType.collect,
category: '自带字典',
tags: ['自带'],
},
{
...cloneDeep(DefaultDict),
id: 'skip',
name: '简单词',
type: DictType.simple,
category: '自带字典'
},
{
...cloneDeep(DefaultDict),
id: 'wrong',
name: '错词本',
type: DictType.wrong,
category: '自带字典'
},
// {
// ...cloneDeep(DefaultDict),
// id: 'article_nce2',
// name: "新概念英语2-课文",
// description: '新概念英语2-课文',
// category: '英语学习',
// tags: ['新概念英语'],
// url: 'NCE_2.json',
// translateLanguage: 'common',
// language: 'en',
// type: DictType.article
// },
{
...cloneDeep(DefaultDict),
id: 'nce-new-2',
name: '新概念英语(新版)-2',
description: '新概念英语新版第二册',
category: '青少年英语',
tags: ['新概念英语'],
url: 'nce-new-2.json',
translateLanguage: 'common',
language: 'en',
type: DictType.word
},
],
current: {
index: 3,
// dictType: DictType.article,
// index: 0,
practiceType: DictType.word,
},
simpleWords: [
'a', 'an',
'i', 'my', 'you', 'your', 'me', 'it',
'am', 'is', 'do', 'are', 'did', 'were',
'what', 'who', 'where', 'how', 'no', 'yes',
'not', 'can', 'could',
'the', 'to', 'of', 'for', 'and', 'that', 'this', 'be'
],
load: false
}
},
getters: {
collect() {
return this.myDictList[0] ?? {}
},
simple(): Dict {
return this.myDictList[1]
},
wrong() {
return this.myDictList[2]
},
skipWordNames() {
return this.simple.originWords.map(v => v.name.toLowerCase())
},
skipWordNamesWithSimpleWords() {
return this.simple.originWords.map(v => v.name.toLowerCase()).concat(this.simpleWords)
},
isArticle(state: BaseState): boolean {
//如果是收藏时,特殊判断
if (this.currentDict.type === DictType.collect) {
return state.current.practiceType === DictType.article
}
return [
DictType.article,
DictType.customArticle
].includes(this.currentDict.type)
},
currentDict(): Dict {
return this.myDictList[this.current.index]
},
chapter(state: BaseState): Word[] {
return this.currentDict.chapterWords[this.currentDict.chapterIndex] ?? []
},
dictTitle(state: BaseState) {
let title = this.currentDict.name
return title + this.chapterName
},
chapterName(state: BaseState) {
let title = ''
switch (this.currentDict.type) {
case DictType.collect:
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}`
}
return title
}
},
actions: {
setState(obj: any) {
//这样不会丢失watch的值的引用
merge(this, obj)
},
async init() {
return new Promise(async resolve => {
try {
let configStr: string = await localforage.getItem(SaveDict.key)
// console.log(configStr)
console.log('s', new Blob([configStr]).size)
configStr = ''
if (configStr) {
let data = JSON.parse(configStr)
let state: BaseState = data.val
state.load = false
if (data.version === SaveDict.version) {
this.setState(state)
} else {
this.setState(state)
}
}
} catch (e) {
console.error('读取本地dict数据失败', e)
state: (): BaseState => {
return {
myDictList: [
{
...cloneDeep(DefaultDict),
id: 'collect',
name: '收藏',
type: DictType.collect,
category: '自带字典',
tags: ['自带'],
},
{
...cloneDeep(DefaultDict),
id: 'skip',
name: '简单词',
type: DictType.simple,
category: '自带字典'
},
{
...cloneDeep(DefaultDict),
id: 'wrong',
name: '错词本',
type: DictType.wrong,
category: '自带字典'
},
// {
// ...cloneDeep(DefaultDict),
// id: 'article_nce2',
// name: "新概念英语2-课文",
// description: '新概念英语2-课文',
// category: '英语学习',
// tags: ['新概念英语'],
// url: 'NCE_2.json',
// translateLanguage: 'common',
// language: 'en',
// type: DictType.article
// resourceId: 'article_nce2',
// },
{
...cloneDeep(DefaultDict),
id: 'nce-new-2',
name: '新概念英语(新版)-2',
description: '新概念英语新版第二册',
category: '青少年英语',
tags: ['新概念英语'],
url: 'nce-new-2.json',
translateLanguage: 'common',
language: 'en',
type: DictType.word,
resourceId: 'nce-new-2',
},
],
current: {
index: 3,
// dictType: DictType.article,
// index: 0,
practiceType: DictType.word,
},
simpleWords: [
'a', 'an',
'i', 'my', 'you', 'your', 'me', 'it',
'am', 'is', 'do', 'are', 'did', 'were',
'what', 'who', 'where', 'how', 'no', 'yes',
'not', 'can', 'could',
'the', 'to', 'of', 'for', 'and', 'that', 'this', 'be'
],
load: false
}
},
getters: {
collect() {
return this.myDictList[0] ?? {}
},
simple(): Dict {
return this.myDictList[1]
},
wrong() {
return this.myDictList[2]
},
skipWordNames() {
return this.simple.originWords.map(v => v.name.toLowerCase())
},
skipWordNamesWithSimpleWords() {
return this.simple.originWords.map(v => v.name.toLowerCase()).concat(this.simpleWords)
},
isArticle(state: BaseState): boolean {
//如果是收藏时,特殊判断
if (this.currentDict.type === DictType.collect) {
return state.current.practiceType === DictType.article
}
return [
DictType.article,
DictType.customArticle
].includes(this.currentDict.type)
},
currentDict(): Dict {
return this.myDictList[this.current.index]
},
chapter(state: BaseState): Word[] {
return this.currentDict.chapterWords[this.currentDict.chapterIndex] ?? []
},
dictTitle(state: BaseState) {
let title = this.currentDict.name
return title + this.chapterName
},
chapterName(state: BaseState) {
let title = ''
switch (this.currentDict.type) {
case DictType.collect:
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}`
}
return title
}
},
actions: {
setState(obj: any) {
//这样不会丢失watch的值的引用
merge(this, obj)
},
async init() {
return new Promise(async resolve => {
try {
let configStr: string = await localforage.getItem(SaveDict.key)
// console.log(configStr)
console.log('s', new Blob([configStr]).size)
configStr = ''
if (configStr) {
let data = JSON.parse(configStr)
let state: BaseState = data.val
state.load = false
if (this.current.index < 3) {
} else {
let dictResourceUrl = `./dicts/${this.currentDict.language}/${this.currentDict.type}/${this.currentDict.translateLanguage}/${this.currentDict.url}`;
if ([
DictType.word,
].includes(this.currentDict.type)) {
if (!this.currentDict.originWords.length) {
let r = await fetch(dictResourceUrl)
// let r = await fetch(`.${this.currentDict.url}`)
let v = await r.json()
v.map(s => {
s.id = nanoid(6)
})
if (this.currentDict.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()
if (list && list.length) {
runtimeStore.translateWordList = list
if (data.version === SaveDict.version) {
this.setState(state)
} else {
this.setState(state)
}
}
} catch (e) {
console.error('读取本地dict数据失败', e)
}
}
this.currentDict.originWords = cloneDeep(v)
this.currentDict.words = cloneDeep(v)
this.currentDict.chapterWords = chunk(this.currentDict.words, this.currentDict.chapterWordNumber)
if (this.current.index < 3) {
} else {
let dictResourceUrl = `./dicts/${this.currentDict.language}/${this.currentDict.type}/${this.currentDict.translateLanguage}/${this.currentDict.url}`;
if ([
DictType.word,
].includes(this.currentDict.type)) {
if (!this.currentDict.originWords.length) {
let r = await fetch(dictResourceUrl)
// let r = await fetch(`.${this.currentDict.url}`)
let v = await r.json()
v.map(s => {
s.id = nanoid(6)
})
if (this.currentDict.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()
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)
}
}
if ([
DictType.article,
DictType.customArticle,
].includes(this.currentDict.type)) {
if (!this.currentDict.articles.length) {
let r = await fetch(dictResourceUrl)
let s: any[] = await r.json()
this.currentDict.articles = cloneDeep(s.map(v => {
v.id = uuidv4()
return v
}))
}
}
}
resolve(true)
})
},
saveStatistics(statistics: DisplayStatistics) {
if (statistics.spend > 1000 * 10) {
delete statistics.wrongWords
this.currentDict.statistics.push(statistics)
}
}
if ([
DictType.article,
DictType.customArticle,
].includes(this.currentDict.type)) {
if (!this.currentDict.articles.length) {
let r = await fetch(dictResourceUrl)
let s: any[] = await r.json()
this.currentDict.articles = cloneDeep(s.map(v => {
v.id = uuidv4()
return v
}))
},
async changeDict(dict: Dict, chapterIndex: number = dict.chapterIndex, wordIndex: number = dict.wordIndex, practiceType: DictType) {
//TODO 保存统计
// this.saveStatistics()
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)) {
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
}
}
}
}
}
resolve(true)
})
},
saveStatistics(statistics: DisplayStatistics) {
if (statistics.spend > 1000 * 10) {
delete statistics.wrongWords
this.currentDict.statistics.push(statistics)
}
},
async changeDict(dict: Dict, chapterIndex: number = dict.chapterIndex, wordIndex: number = dict.wordIndex, practiceType: DictType) {
//TODO 保存统计
// this.saveStatistics()
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)) {
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
}
}
}
// await checkDictHasTranslate(dict)
// 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)
}
},
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)
}
},
})

View File

@@ -3,125 +3,125 @@ import {cloneDeep} from "lodash-es";
import {DefaultShortcutKeyMap, SaveConfig} from "@/types.ts";
export interface SettingState {
showToolbar: boolean,
show: boolean,
showToolbar: boolean,
show: boolean,
allSound: boolean,
wordSound: boolean,
wordSoundVolume: number,
wordSoundSpeed: number,
wordSoundType: string,
keyboardSound: boolean,
keyboardSoundVolume: number,
keyboardSoundFile: string,
translateSound: boolean,
translateSoundVolume: number,
effectSound: boolean,
effectSoundVolume: number,
repeatCount: number,
repeatCustomCount?: number,
dictation: boolean,
translate: boolean,
showNearWord: boolean
ignoreCase: boolean
allowWordTip: boolean
waitTimeForChangeWord: number
fontSize: {
articleForeignFontSize: number,
articleTranslateFontSize: number,
wordForeignFontSize: number,
wordTranslateFontSize: number,
},
showPanel: boolean,
theme: string,
collapse: boolean,
chapterWordNumber: number,
shortcutKeyMap: Record<string, string>
allSound: boolean,
wordSound: boolean,
wordSoundVolume: number,
wordSoundSpeed: number,
wordSoundType: string,
keyboardSound: boolean,
keyboardSoundVolume: number,
keyboardSoundFile: string,
translateSound: boolean,
translateSoundVolume: number,
effectSound: boolean,
effectSoundVolume: number,
repeatCount: number,
repeatCustomCount?: number,
dictation: boolean,
translate: boolean,
showNearWord: boolean
ignoreCase: boolean
allowWordTip: boolean
waitTimeForChangeWord: number
fontSize: {
articleForeignFontSize: number,
articleTranslateFontSize: number,
wordForeignFontSize: number,
wordTranslateFontSize: number,
},
showPanel: boolean,
theme: string,
collapse: boolean,
chapterWordNumber: number,
shortcutKeyMap: Record<string, string>
}
export const DefaultChapterWordNumber = 30
export const useSettingStore = defineStore('setting', {
state: (): SettingState => {
return {
showToolbar: true,
show: false,
showPanel: true,
state: (): SettingState => {
return {
showToolbar: true,
show: false,
showPanel: true,
allSound: true,
wordSound: true,
wordSoundVolume: 100,
wordSoundSpeed: 1,
wordSoundType: 'us',
keyboardSound: true,
keyboardSoundVolume: 100,
keyboardSoundFile: '老式机械',
translateSound: true,
translateSoundVolume: 100,
effectSound: true,
effectSoundVolume: 100,
repeatCount: 1,
repeatCustomCount: null,
dictation: false,
translate: true,
allSound: true,
wordSound: true,
wordSoundVolume: 100,
wordSoundSpeed: 1,
wordSoundType: 'us',
keyboardSound: true,
keyboardSoundVolume: 100,
keyboardSoundFile: '老式机械',
translateSound: true,
translateSoundVolume: 100,
effectSound: true,
effectSoundVolume: 100,
repeatCount: 1,
repeatCustomCount: null,
dictation: false,
translate: true,
showNearWord: true,
ignoreCase: true,
allowWordTip: true,
fontSize: {
articleForeignFontSize: 48,
articleTranslateFontSize: 20,
wordForeignFontSize: 48,
wordTranslateFontSize: 20,
},
waitTimeForChangeWord: 300,
showNearWord: true,
ignoreCase: true,
allowWordTip: true,
fontSize: {
articleForeignFontSize: 48,
articleTranslateFontSize: 20,
wordForeignFontSize: 48,
wordTranslateFontSize: 20,
},
waitTimeForChangeWord: 300,
theme: 'auto',
collapse: false,
chapterWordNumber: 30,
shortcutKeyMap: cloneDeep(DefaultShortcutKeyMap)
}
},
actions: {
setState(obj: any) {
for (const [key, value] of Object.entries(obj)) {
this[key] = value
}
theme: 'auto',
collapse: false,
chapterWordNumber: DefaultChapterWordNumber,
shortcutKeyMap: cloneDeep(DefaultShortcutKeyMap)
}
},
init() {
return new Promise(resolve => {
const setDefaultConfig = () => {
localStorage.setItem(SaveConfig.key, JSON.stringify({val: this.$state, version: SaveConfig.version}))
}
let configStr = localStorage.getItem(SaveConfig.key)
if (configStr) {
try {
let obj: any = JSON.parse(configStr)
if (!obj.version) {
setDefaultConfig()
} else {
if (obj.version !== SaveConfig.version) {
for (const [key, value] of Object.entries(this.shortcutKeyMap)) {
if (obj.val.shortcutKeyMap[key]) this.shortcutKeyMap[key] = obj.val.shortcutKeyMap[key]
}
delete obj.val.shortcutKeyMap
for (const [key, value] of Object.entries(this.fontSize)) {
if (obj.val.fontSize[key]) this.fontSize[key] = obj.val.fontSize[key]
}
delete obj.val.fontSize
this.setState(obj.val)
} else {
this.setState(obj.val)
}
localStorage.setItem(SaveConfig.key, JSON.stringify({val: this.$state, version: SaveConfig.version}))
actions: {
setState(obj: any) {
for (const [key, value] of Object.entries(obj)) {
this[key] = value
}
} catch (e) {
setDefaultConfig()
}
},
init() {
return new Promise(resolve => {
const setDefaultConfig = () => {
localStorage.setItem(SaveConfig.key, JSON.stringify({val: this.$state, version: SaveConfig.version}))
}
let configStr = localStorage.getItem(SaveConfig.key)
if (configStr) {
try {
let obj: any = JSON.parse(configStr)
if (!obj.version) {
setDefaultConfig()
} else {
if (obj.version !== SaveConfig.version) {
for (const [key, value] of Object.entries(this.shortcutKeyMap)) {
if (obj.val.shortcutKeyMap[key]) this.shortcutKeyMap[key] = obj.val.shortcutKeyMap[key]
}
delete obj.val.shortcutKeyMap
for (const [key, value] of Object.entries(this.fontSize)) {
if (obj.val.fontSize[key]) this.fontSize[key] = obj.val.fontSize[key]
}
delete obj.val.fontSize
this.setState(obj.val)
} else {
this.setState(obj.val)
}
localStorage.setItem(SaveConfig.key, JSON.stringify({val: this.$state, version: SaveConfig.version}))
}
} catch (e) {
setDefaultConfig()
}
}
resolve(true)
})
}
resolve(true)
})
}
}
})

View File

@@ -4,21 +4,22 @@ import jpFlag from "@/assets/img/flags/ja.png";
import deFlag from "./assets/img/flags/de.png";
import codeFlag from "@/assets/img/flags/code.png";
import myFlag from "@/assets/img/flags/my.png";
import {DefaultChapterWordNumber} from "@/stores/setting.ts";
export type Word = {
"name": string,
"usphone": string,
"ukphone": string,
"trans": string[]
checked?: boolean,
id?: any,
"name": string,
"usphone": string,
"ukphone": string,
"trans": string[]
checked?: boolean,
id?: any,
}
export const DefaultWord: Word = {
name: '',
usphone: '',
ukphone: '',
trans: []
name: '',
usphone: '',
ukphone: '',
trans: []
}
export const PronunciationApi = 'https://dict.youdao.com/dictvoice?audio='
@@ -27,236 +28,238 @@ export type TranslateLanguageType = 'en' | 'zh-CN' | 'ja' | 'de' | 'common' | ''
export type LanguageType = 'en' | 'ja' | 'de' | 'code'
export type DictResource = {
id: string
name: string
description: string
url: string
length: number
category: string
tags: string[]
translateLanguage: TranslateLanguageType
type: DictType
language: LanguageType
id: string
name: string
description: string
url: string
length: number
category: string
tags: string[]
translateLanguage: TranslateLanguageType
type: DictType
language: LanguageType
}
export enum DictType {
collect = 'collect',
simple = 'simple',
wrong = 'wrong',
word = 'word',
customWord = 'customWord',
article = 'article',
customArticle = 'customArticle'
collect = 'collect',
simple = 'simple',
wrong = 'wrong',
word = 'word',
customWord = 'customWord',
article = 'article',
customArticle = 'customArticle'
}
export const DefaultArticleWord: ArticleWord = {
name: '',
usphone: '',
ukphone: '',
trans: [],
nextSpace: true,
isSymbol: false,
symbolPosition: ''
name: '',
usphone: '',
ukphone: '',
trans: [],
nextSpace: true,
isSymbol: false,
symbolPosition: ''
}
export interface ArticleWord extends Word {
nextSpace: boolean,
isSymbol: boolean,
symbolPosition: 'start' | 'end' | '',
nextSpace: boolean,
isSymbol: boolean,
symbolPosition: 'start' | 'end' | '',
}
export interface Sentence {
text: string,
translate: string,
words: ArticleWord[]
text: string,
translate: string,
words: ArticleWord[]
}
export enum TranslateType {
custom = 'custom',
network = 'network',
none = 'none'
custom = 'custom',
network = 'network',
none = 'none'
}
export interface Article {
id: string,
title: string,
titleTranslate: string,
text: string,
textFormat: string,
textCustomTranslate: string,
textCustomTranslateIsFormat: boolean,//翻译是否格式化
textNetworkTranslate: string,
newWords: Word[],
textAllWords: string[],
sections: Sentence[][],
useTranslateType: TranslateType
id: string,
title: string,
titleTranslate: string,
text: string,
textFormat: string,
textCustomTranslate: string,
textCustomTranslateIsFormat: boolean,//翻译是否格式化
textNetworkTranslate: string,
newWords: Word[],
textAllWords: string[],
sections: Sentence[][],
useTranslateType: TranslateType
}
export const DefaultArticle: Article = {
// id: uuidv4(),
id: '',
title: '',
titleTranslate: '',
text: '',
textFormat: '',
textCustomTranslate: '',
textNetworkTranslate: '',
textCustomTranslateIsFormat: false,
newWords: [],
textAllWords: [],
sections: [],
useTranslateType: TranslateType.network
// id: uuidv4(),
id: '',
title: '',
titleTranslate: '',
text: '',
textFormat: '',
textCustomTranslate: '',
textNetworkTranslate: '',
textCustomTranslateIsFormat: false,
newWords: [],
textAllWords: [],
sections: [],
useTranslateType: TranslateType.network
}
export interface Statistics {
startDate: number,//开始日期
endDate: number//结束日期
spend: number,//花费时间
total: number//单词数量
wrongWordNumber: number//错误数
correctRate: number//正确率
startDate: number,//开始日期
endDate: number//结束日期
spend: number,//花费时间
total: number//单词数量
wrongWordNumber: number//错误数
correctRate: number//正确率
}
export interface DisplayStatistics extends Statistics {
wrongWords: Word[]
inputWordNumber: number//输入数
wrongWords: Word[]
inputWordNumber: number//输入数
}
export const DefaultDisplayStatistics: DisplayStatistics = {
startDate: Date.now(),
endDate: -1,
spend: -1,
total: -1,
correctRate: -1,
wrongWordNumber: -1,
inputWordNumber: -1,
wrongWords: [],
startDate: Date.now(),
endDate: -1,
spend: -1,
total: -1,
correctRate: -1,
wrongWordNumber: -1,
inputWordNumber: -1,
wrongWords: [],
}
export enum Sort {
normal = 0,
random = 1,
reverse = 2
normal = 0,
random = 1,
reverse = 2
}
export const ShortcutKeyMap = {
Show: 'Escape',
Ignore: 'Tab',
Remove: '`',
Collect: 'Enter',
Show: 'Escape',
Ignore: 'Tab',
Remove: '`',
Collect: 'Enter',
}
export const SaveDict = {
key: 'typing-word-dict',
version: 1
key: 'typing-word-dict',
version: 1
}
export const SaveConfig = {
key: 'typing-word-config',
version: 8
key: 'typing-word-config',
version: 8
}
export enum ShortcutKey {
ShowWord = 'ShowWord',
EditArticle = 'EditArticle',
Next = 'Next',
Previous = 'Previous',
ToggleSimple = 'ToggleSimple',
ToggleCollect = 'ToggleCollect',
NextChapter = 'NextChapter',
PreviousChapter = 'PreviousChapter',
RepeatChapter = 'RepeatChapter',
DictationChapter = 'DictationChapter',
PlayWordPronunciation = 'PlayWordPronunciation',
// PlayTranslatePronunciation = 'PlayTranslatePronunciation',
ToggleShowTranslate = 'ToggleShowTranslate',
ToggleDictation = 'ToggleDictation',
OpenSetting = 'OpenSetting',
OpenDictDetail = 'OpenDictDetail',
ToggleTheme = 'ToggleTheme',
ToggleConciseMode = 'ToggleConciseMode',
TogglePanel = 'TogglePanel'
ShowWord = 'ShowWord',
EditArticle = 'EditArticle',
Next = 'Next',
Previous = 'Previous',
ToggleSimple = 'ToggleSimple',
ToggleCollect = 'ToggleCollect',
NextChapter = 'NextChapter',
PreviousChapter = 'PreviousChapter',
RepeatChapter = 'RepeatChapter',
DictationChapter = 'DictationChapter',
PlayWordPronunciation = 'PlayWordPronunciation',
// PlayTranslatePronunciation = 'PlayTranslatePronunciation',
ToggleShowTranslate = 'ToggleShowTranslate',
ToggleDictation = 'ToggleDictation',
OpenSetting = 'OpenSetting',
OpenDictDetail = 'OpenDictDetail',
ToggleTheme = 'ToggleTheme',
ToggleConciseMode = 'ToggleConciseMode',
TogglePanel = 'TogglePanel'
}
export const DefaultShortcutKeyMap = {
[ShortcutKey.EditArticle]: 'Ctrl+E',
[ShortcutKey.ShowWord]: 'Escape',
[ShortcutKey.Previous]: 'Alt+⬅',
[ShortcutKey.Next]: 'Tab',
[ShortcutKey.ToggleSimple]: '`',
[ShortcutKey.ToggleCollect]: 'Enter',
[ShortcutKey.PreviousChapter]: 'Ctrl+⬅',
[ShortcutKey.NextChapter]: 'Ctrl+➡',
[ShortcutKey.RepeatChapter]: 'Ctrl+Enter',
[ShortcutKey.DictationChapter]: 'Alt+Enter',
[ShortcutKey.PlayWordPronunciation]: 'Ctrl+P',
// [ShortcutKey.PlayTranslatePronunciation]: 'Ctrl+O',
[ShortcutKey.ToggleShowTranslate]: 'Ctrl+Z',
[ShortcutKey.ToggleDictation]: 'Ctrl+I',
[ShortcutKey.OpenSetting]: 'Ctrl+S',
[ShortcutKey.ToggleTheme]: 'Ctrl+Q',
[ShortcutKey.OpenDictDetail]: 'Ctrl+J',
[ShortcutKey.ToggleConciseMode]: 'Ctrl+M',
[ShortcutKey.TogglePanel]: 'Ctrl+L',
[ShortcutKey.EditArticle]: 'Ctrl+E',
[ShortcutKey.ShowWord]: 'Escape',
[ShortcutKey.Previous]: 'Alt+⬅',
[ShortcutKey.Next]: 'Tab',
[ShortcutKey.ToggleSimple]: '`',
[ShortcutKey.ToggleCollect]: 'Enter',
[ShortcutKey.PreviousChapter]: 'Ctrl+⬅',
[ShortcutKey.NextChapter]: 'Ctrl+➡',
[ShortcutKey.RepeatChapter]: 'Ctrl+Enter',
[ShortcutKey.DictationChapter]: 'Alt+Enter',
[ShortcutKey.PlayWordPronunciation]: 'Ctrl+P',
// [ShortcutKey.PlayTranslatePronunciation]: 'Ctrl+O',
[ShortcutKey.ToggleShowTranslate]: 'Ctrl+Z',
[ShortcutKey.ToggleDictation]: 'Ctrl+I',
[ShortcutKey.OpenSetting]: 'Ctrl+S',
[ShortcutKey.ToggleTheme]: 'Ctrl+Q',
[ShortcutKey.OpenDictDetail]: 'Ctrl+J',
[ShortcutKey.ToggleConciseMode]: 'Ctrl+M',
[ShortcutKey.TogglePanel]: 'Ctrl+L',
}
export enum TranslateEngine {
Baidu = 0,
Baidu = 0,
}
export const languageCategoryOptions = [
{id: 'article', name: '文章', flag: bookFlag},
{id: 'en', name: '英语', flag: enFlag},
{id: 'ja', name: '日语', flag: jpFlag},
{id: 'de', name: '德语', flag: deFlag},
{id: 'code', name: 'Code', flag: codeFlag},
{id: 'my', name: '我的', flag: myFlag},
{id: 'article', name: '文章', flag: bookFlag},
{id: 'en', name: '英语', flag: enFlag},
{id: 'ja', name: '日语', flag: jpFlag},
{id: 'de', name: '德语', flag: deFlag},
{id: 'code', name: 'Code', flag: codeFlag},
{id: 'my', name: '我的', flag: myFlag},
]
export const DefaultDict: Dict = {
id: '',
name: '',
description: '',
sort: Sort.normal,
originWords: [],//原始单词
words: [],
chapterWordNumber: 30,//章节单词数量
chapterWords: [],
chapterIndex: 0,//章节下标
wordIndex: 0,//单词下标
articles: [],
statistics: [],
/*资源属性*/
resourceId: '',
url: '',
category: '',
tags: [],
translateLanguage: 'common',
type: DictType.customWord,
language: 'en',
id: '',
name: '',
description: '',
sort: Sort.normal,
originWords: [],//原始单词
words: [],
chapterWordNumber: DefaultChapterWordNumber,//章节单词数量
chapterWords: [],
chapterIndex: 0,//章节下标
wordIndex: 0,//单词下标
articles: [],
statistics: [],
isCustom: false,
/*资源属性*/
resourceId: '',
url: '',
category: '',
tags: [],
translateLanguage: 'common',
type: DictType.customWord,
language: 'en',
}
export interface Dict {
id: string,
name: string,
description: string,
sort: Sort,
originWords: Word[],//原始单词
words: Word[],
chapterWordNumber: number,//章节单词数量
chapterWords: Word[][],
chapterIndex: number,//章节下标
wordIndex: number,//单词下标
articles: Article[],
statistics: Statistics[],
/*资源属性*/
resourceId: string,
url: string,
category: string
tags: string[]
translateLanguage: TranslateLanguageType
type: DictType
language: LanguageType
id: string,
name: string,
description: string,
sort: Sort,
originWords: Word[],//原始单词
words: Word[],
chapterWordNumber: number,//章节单词数量
chapterWords: Word[][],
chapterIndex: number,//章节下标
wordIndex: number,//单词下标
articles: Article[],
statistics: Statistics[],
isCustom: boolean,
/*资源属性*/
resourceId: string,
category: string
tags: string[]
language: LanguageType
type: DictType
translateLanguage: TranslateLanguageType
url: string,
}

View File

@@ -3,67 +3,61 @@ import Dialog, {ModalProps} from "@/components/dialog/Dialog.vue";
import {AppContext, Component, ComponentPublicInstance, createVNode, getCurrentInstance, render, VNode} from 'vue';
export class MessageBox {
static confirm(
content: string,
title: string,
onOk: () => any = () => void 0,
onCancel: () => any = () => void 0,
config: ModalProps = {}
) {
let container = document.createElement('div')
const close = () => {
render(null, container);
container.remove()
}
let tempOnCancel = () => {
onCancel()
close()
}
let tempOnOk = () => {
onOk()
close()
}
const vNode = createVNode(Dialog, {
title,
content,
onCancel: tempOnCancel,
onOk: tempOnOk,
footer: true,
...config
});
// const appContext = getCurrentInstance()?.appContext;
// // 补丁Component中获取当前组件树的provides
// if (appContext) {
// const currentProvides = (getCurrentInstance() as any)?.provides;
// Reflect.set(appContext, 'provides', {...appContext.provides, ...currentProvides});
// }
// vNode.appContext = appContext;
render(vNode, container);
document.body.append(container)
}
static confirm(
content: string,
title: string,
onOk: () => any = () => void 0,
onCancel: () => any = () => void 0,
config: ModalProps = {}
) {
let container = document.createElement('div')
const close = () => {
render(null, container);
container.remove()
}
static notice(
content: string,
title: string,
) {
let container = document.createElement('div')
let tempOnCancel = () => {
render(null, container);
container.remove()
const vNode = createVNode(Dialog, {
title,
content,
onCancel: onCancel,
confirm: onOk,
onClose: close,
footer: true,
...config
});
// const appContext = getCurrentInstance()?.appContext;
// // 补丁Component中获取当前组件树的provides
// if (appContext) {
// const currentProvides = (getCurrentInstance() as any)?.provides;
// Reflect.set(appContext, 'provides', {...appContext.provides, ...currentProvides});
// }
// vNode.appContext = appContext;
render(vNode, container);
document.body.append(container)
}
static notice(
content: string,
title: string,
) {
let container = document.createElement('div')
let tempOnCancel = () => {
render(null, container);
container.remove()
}
const vNode = createVNode(Dialog, {
title,
content,
onCancel: tempOnCancel,
});
// const appContext = getCurrentInstance()?.appContext;
// // 补丁Component中获取当前组件树的provides
// if (appContext) {
// const currentProvides = (getCurrentInstance() as any)?.provides;
// Reflect.set(appContext, 'provides', {...appContext.provides, ...currentProvides});
// }
// vNode.appContext = appContext;
render(vNode, container);
document.body.append(container)
}
const vNode = createVNode(Dialog, {
title,
content,
onCancel: tempOnCancel,
});
// const appContext = getCurrentInstance()?.appContext;
// // 补丁Component中获取当前组件树的provides
// if (appContext) {
// const currentProvides = (getCurrentInstance() as any)?.provides;
// Reflect.set(appContext, 'provides', {...appContext.provides, ...currentProvides});
// }
// vNode.appContext = appContext;
render(vNode, container);
document.body.append(container)
}
}