Optimize UI interface
This commit is contained in:
22
src/App.vue
22
src/App.vue
@@ -2,14 +2,13 @@
|
||||
|
||||
import {onMounted, watch} from "vue";
|
||||
import {useBaseStore} from "@/stores/base.ts";
|
||||
import {DictResource, SaveDictKey} from "@/types.ts"
|
||||
import {SaveConfig, SaveDict} from "@/types.ts"
|
||||
import Practice from "@/components/Practice/Practice.vue"
|
||||
import {useEventListener, useStartKeyboardEventListener} from "@/hooks/event.ts";
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
import {useSettingStore} from "@/stores/setting.ts";
|
||||
import {dictionaryResources} from "@/assets/dictionary.ts";
|
||||
import {cloneDeep, groupBy} from "lodash-es";
|
||||
import {$ref} from "vue/macros";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import Backgorund from "@/components/Backgorund.vue";
|
||||
|
||||
const store = useBaseStore()
|
||||
const runtimeStore = useRuntimeStore()
|
||||
@@ -26,9 +25,11 @@ function followSystem() {
|
||||
}
|
||||
|
||||
watch(store.$state, (n) => {
|
||||
// console.log('state', JSON.stringify(n.current, null, 2))
|
||||
// console.log('state', n)
|
||||
localStorage.setItem(SaveDictKey, JSON.stringify(n))
|
||||
localStorage.setItem(SaveDict.key, JSON.stringify({val: n, version: SaveDict.version}))
|
||||
})
|
||||
|
||||
watch(settingStore.$state, (n) => {
|
||||
localStorage.setItem(SaveConfig.key, JSON.stringify({val: n, version: SaveConfig.version}))
|
||||
})
|
||||
|
||||
//检测几个特定词典
|
||||
@@ -49,6 +50,7 @@ useStartKeyboardEventListener()
|
||||
|
||||
onMounted(() => {
|
||||
store.init()
|
||||
settingStore.init()
|
||||
if (settingStore.theme !== 'auto') {
|
||||
document.documentElement.setAttribute('data-theme', settingStore.theme)
|
||||
}
|
||||
@@ -67,7 +69,9 @@ onMounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- <Backgorund/>-->
|
||||
<Transition name="fade">
|
||||
<Backgorund v-if="settingStore.theme === 'dark'"/>
|
||||
</Transition>
|
||||
<div class="main-page">
|
||||
<Practice/>
|
||||
<!-- <AddArticle/>-->
|
||||
@@ -87,6 +91,6 @@ onMounted(() => {
|
||||
font-size: 14rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
background-color: var(--color-main-bg);
|
||||
background-color: var(--color-background);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
@import "anim";
|
||||
|
||||
:root {
|
||||
--color-background: #E6E8EB;
|
||||
--color-main-bg: #E6E8EB;
|
||||
--color-second-bg: rgb(240, 242, 244);
|
||||
|
||||
@@ -33,6 +34,7 @@
|
||||
html[data-theme='dark'] {
|
||||
//--color-main-bg: rgba(0, 5, 24, 1);
|
||||
//--color-main-bg: rgba(17,24,39, 1);
|
||||
--color-background: transparent;
|
||||
--color-main-bg: rgba(14, 18, 23, 1);
|
||||
--color-second-bg: rgb(60, 63, 65);
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import {useDisableEventListener, useEventListener} from "@/hooks/event.ts";
|
||||
import {$computed, $ref} from "vue/macros";
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import {DefaultShortcutKeyMap} from "@/types.ts";
|
||||
import BaseButton from "@/components/BaseButton.vue";
|
||||
|
||||
const tabIndex = $ref(2)
|
||||
const settingStore = useSettingStore()
|
||||
@@ -37,11 +38,26 @@ useEventListener('keydown', (e: KeyboardEvent) => {
|
||||
if (e.keyCode >= 65 && e.keyCode <= 90) {
|
||||
shortcutKey += e.key.toUpperCase()
|
||||
} else {
|
||||
shortcutKey += e.key
|
||||
if (e.key === 'ArrowRight') {
|
||||
shortcutKey += '➡'
|
||||
} else if (e.key === 'ArrowLeft') {
|
||||
shortcutKey += '⬅'
|
||||
} else if (e.key === 'ArrowUp') {
|
||||
shortcutKey += '⬆'
|
||||
} else if (e.key === 'ArrowDown') {
|
||||
shortcutKey += '⬇'
|
||||
} else {
|
||||
shortcutKey += e.key
|
||||
}
|
||||
}
|
||||
}
|
||||
shortcutKey = shortcutKey.trim()
|
||||
|
||||
// if (shortcutKey[shortcutKey.length-1] === '+') {
|
||||
// settingStore.shortcutKeyMap[editShortcutKey] = DefaultShortcutKeyMap[editShortcutKey]
|
||||
// return ElMessage.warning('设备失败!')
|
||||
// }
|
||||
|
||||
if (editShortcutKey) {
|
||||
for (const [k, v] of Object.entries(settingStore.shortcutKeyMap)) {
|
||||
if (v === shortcutKey && k !== editShortcutKey) {
|
||||
@@ -51,7 +67,6 @@ useEventListener('keydown', (e: KeyboardEvent) => {
|
||||
}
|
||||
settingStore.shortcutKeyMap[editShortcutKey] = shortcutKey
|
||||
}
|
||||
|
||||
console.log('key', shortcutKey)
|
||||
})
|
||||
|
||||
@@ -286,6 +301,12 @@ useEventListener('keydown', (e: KeyboardEvent) => {
|
||||
<div v-else> {{ item[1] }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="item-title"></label>
|
||||
<div class="wrapper">
|
||||
<BaseButton @click="settingStore.shortcutKeyMap = cloneDeep(DefaultShortcutKeyMap)">恢复默认</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -368,10 +389,16 @@ useEventListener('keydown', (e: KeyboardEvent) => {
|
||||
|
||||
input {
|
||||
width: 150rem;
|
||||
box-sizing: border-box;
|
||||
margin-right: 10rem;
|
||||
height: 24rem;
|
||||
height: 28rem;
|
||||
outline: none;
|
||||
font-size: 16rem;
|
||||
border: 1px solid gray;
|
||||
border-radius: 3rem;
|
||||
padding: 0 5rem;
|
||||
background: var(--color-second-bg);
|
||||
color: var(--color-font-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import {defineStore} from 'pinia'
|
||||
import {DefaultDict, Dict, DictType, DisplayStatistics, SaveDictKey, Word} from "../types.ts"
|
||||
import {DefaultDict, Dict, DictType, DisplayStatistics, SaveDict, Word} from "../types.ts"
|
||||
import {chunk, cloneDeep} from "lodash-es";
|
||||
import {emitter, EventKey} from "@/utils/eventBus.ts"
|
||||
import {v4 as uuidv4} from 'uuid';
|
||||
import {useRuntimeStore} from "@/stores/runtime.ts";
|
||||
|
||||
export interface State {
|
||||
collect: Dict,
|
||||
simple: Dict,
|
||||
wrong: Dict,
|
||||
myDicts: Dict[],
|
||||
current: {
|
||||
dictType: DictType,
|
||||
index: number,
|
||||
practiceType: DictType,//练习类型,目前仅词典为collect时判断是练单词还是文章使用
|
||||
},
|
||||
simpleWords: string[],
|
||||
load: boolean
|
||||
collect: Dict,
|
||||
simple: Dict,
|
||||
wrong: Dict,
|
||||
myDicts: Dict[],
|
||||
current: {
|
||||
dictType: DictType,
|
||||
index: number,
|
||||
practiceType: DictType,//练习类型,目前仅词典为collect时判断是练单词还是文章使用
|
||||
},
|
||||
simpleWords: string[],
|
||||
load: boolean
|
||||
}
|
||||
|
||||
// words: [
|
||||
@@ -65,236 +65,236 @@ export interface State {
|
||||
// ],
|
||||
|
||||
export const useBaseStore = defineStore('base', {
|
||||
state: (): State => {
|
||||
return {
|
||||
collect: {
|
||||
...cloneDeep(DefaultDict),
|
||||
id: 'collect',
|
||||
name: '收藏',
|
||||
type: DictType.collect,
|
||||
},
|
||||
simple: {
|
||||
...cloneDeep(DefaultDict),
|
||||
id: 'skip',
|
||||
name: '简单词',
|
||||
type: DictType.simple,
|
||||
},
|
||||
wrong: {
|
||||
...cloneDeep(DefaultDict),
|
||||
id: 'wrong',
|
||||
name: '错词本',
|
||||
type: DictType.wrong,
|
||||
},
|
||||
myDicts: [
|
||||
{
|
||||
...cloneDeep(DefaultDict),
|
||||
id: '新概念英语2-课文',
|
||||
name: '新概念英语2-课文',
|
||||
type: DictType.article,
|
||||
url: 'NCE_2.json',
|
||||
translateLanguage: 'common',
|
||||
language: 'en',
|
||||
state: (): State => {
|
||||
return {
|
||||
collect: {
|
||||
...cloneDeep(DefaultDict),
|
||||
id: 'collect',
|
||||
name: '收藏',
|
||||
type: DictType.collect,
|
||||
},
|
||||
simple: {
|
||||
...cloneDeep(DefaultDict),
|
||||
id: 'skip',
|
||||
name: '简单词',
|
||||
type: DictType.simple,
|
||||
},
|
||||
wrong: {
|
||||
...cloneDeep(DefaultDict),
|
||||
id: 'wrong',
|
||||
name: '错词本',
|
||||
type: DictType.wrong,
|
||||
},
|
||||
myDicts: [
|
||||
{
|
||||
...cloneDeep(DefaultDict),
|
||||
id: '新概念英语2-课文',
|
||||
name: '新概念英语2-课文',
|
||||
type: DictType.article,
|
||||
url: 'NCE_2.json',
|
||||
translateLanguage: 'common',
|
||||
language: 'en',
|
||||
},
|
||||
{
|
||||
...cloneDeep(DefaultDict),
|
||||
id: '新概念英语2',
|
||||
name: '新概念英语2',
|
||||
type: DictType.word,
|
||||
url: 'nce-new-2.json',
|
||||
resourceId: 'nce-new-2',
|
||||
translateLanguage: 'common',
|
||||
language: 'en',
|
||||
}
|
||||
],
|
||||
current: {
|
||||
dictType: DictType.word,
|
||||
index: 1,
|
||||
// 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: {
|
||||
skipWordNames: (state: State) => {
|
||||
return state.simple.originWords.map(v => v.name.toLowerCase())
|
||||
},
|
||||
{
|
||||
...cloneDeep(DefaultDict),
|
||||
id: '新概念英语2',
|
||||
name: '新概念英语2',
|
||||
type: DictType.word,
|
||||
url: 'nce-new-2.json',
|
||||
resourceId: 'nce-new-2',
|
||||
translateLanguage: 'common',
|
||||
language: 'en',
|
||||
skipWordNamesWithSimpleWords: (state: State) => {
|
||||
return state.simple.originWords.map(v => v.name.toLowerCase()).concat(state.simpleWords)
|
||||
},
|
||||
isArticle(state: State): boolean {
|
||||
//如果是收藏时,特殊判断
|
||||
if (state.current.dictType === DictType.collect) {
|
||||
return state.current.practiceType === DictType.article
|
||||
}
|
||||
return [
|
||||
DictType.article,
|
||||
DictType.customArticle
|
||||
].includes(state.current.dictType)
|
||||
},
|
||||
currentDict(state: State): Dict {
|
||||
switch (state.current.dictType) {
|
||||
case DictType.collect:
|
||||
return state.collect
|
||||
case DictType.simple:
|
||||
return state.simple
|
||||
case DictType.wrong:
|
||||
return state.wrong
|
||||
case DictType.word:
|
||||
case DictType.article:
|
||||
case DictType.customWord:
|
||||
case DictType.customArticle:
|
||||
return this.myDicts[this.current.index]
|
||||
}
|
||||
},
|
||||
currentEditDict(): Dict {
|
||||
return this.myDicts[this.current.editIndex]
|
||||
},
|
||||
wordIndex(state: State): number {
|
||||
return this.currentDict.wordIndex
|
||||
},
|
||||
chapter(state: State): Word[] {
|
||||
return this.currentDict.chapterWords[this.currentDict.chapterIndex] ?? []
|
||||
},
|
||||
//TODO 废弃
|
||||
word(state: State): Word {
|
||||
return {trans: [], name: '', usphone: '', ukphone: '',}
|
||||
},
|
||||
dictTitle(state: State) {
|
||||
let title = this.currentDict.name
|
||||
switch (state.current.dictType) {
|
||||
case DictType.collect:
|
||||
if (state.current.dictType === DictType.collect) {
|
||||
title += ` 第${this.currentDict.chapterIndex + 1}章`
|
||||
}
|
||||
break
|
||||
case DictType.word:
|
||||
case DictType.article:
|
||||
case DictType.customWord:
|
||||
case DictType.customArticle:
|
||||
title += ` 第${this.currentDict.chapterIndex + 1}章`
|
||||
break
|
||||
}
|
||||
return title
|
||||
}
|
||||
],
|
||||
current: {
|
||||
dictType: DictType.word,
|
||||
index: 1,
|
||||
// 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: {
|
||||
skipWordNames: (state: State) => {
|
||||
return state.simple.originWords.map(v => v.name.toLowerCase())
|
||||
},
|
||||
skipWordNamesWithSimpleWords: (state: State) => {
|
||||
return state.simple.originWords.map(v => v.name.toLowerCase()).concat(state.simpleWords)
|
||||
},
|
||||
isArticle(state: State): boolean {
|
||||
//如果是收藏时,特殊判断
|
||||
if (state.current.dictType === DictType.collect) {
|
||||
return state.current.practiceType === DictType.article
|
||||
}
|
||||
return [
|
||||
DictType.article,
|
||||
DictType.customArticle
|
||||
].includes(state.current.dictType)
|
||||
},
|
||||
currentDict(state: State): Dict {
|
||||
switch (state.current.dictType) {
|
||||
case DictType.collect:
|
||||
return state.collect
|
||||
case DictType.simple:
|
||||
return state.simple
|
||||
case DictType.wrong:
|
||||
return state.wrong
|
||||
case DictType.word:
|
||||
case DictType.article:
|
||||
case DictType.customWord:
|
||||
case DictType.customArticle:
|
||||
return this.myDicts[this.current.index]
|
||||
}
|
||||
},
|
||||
currentEditDict(): Dict {
|
||||
return this.myDicts[this.current.editIndex]
|
||||
},
|
||||
wordIndex(state: State): number {
|
||||
return this.currentDict.wordIndex
|
||||
},
|
||||
chapter(state: State): Word[] {
|
||||
return this.currentDict.chapterWords[this.currentDict.chapterIndex] ?? []
|
||||
},
|
||||
//TODO 废弃
|
||||
word(state: State): Word {
|
||||
return {trans: [], name: '', usphone: '', ukphone: '',}
|
||||
},
|
||||
dictTitle(state: State) {
|
||||
let title = this.currentDict.name
|
||||
switch (state.current.dictType) {
|
||||
case DictType.collect:
|
||||
if (state.current.dictType === DictType.collect) {
|
||||
title += ` 第${this.currentDict.chapterIndex + 1}章`
|
||||
}
|
||||
break
|
||||
case DictType.word:
|
||||
case DictType.article:
|
||||
case DictType.customWord:
|
||||
case DictType.customArticle:
|
||||
title += ` 第${this.currentDict.chapterIndex + 1}章`
|
||||
break
|
||||
}
|
||||
return title
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
setState(obj: any) {
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
this[key] = value
|
||||
}
|
||||
// console.log('this/', this)
|
||||
},
|
||||
async init() {
|
||||
let configStr = localStorage.getItem(SaveDictKey)
|
||||
if (configStr) {
|
||||
let obj: State = JSON.parse(configStr)
|
||||
// this.setState(obj)
|
||||
}
|
||||
actions: {
|
||||
setState(obj: any) {
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
this[key] = value
|
||||
}
|
||||
// console.log('this/', this)
|
||||
},
|
||||
async init() {
|
||||
let configStr = localStorage.getItem(SaveDict.key)
|
||||
if (configStr) {
|
||||
let obj: State = JSON.parse(configStr)
|
||||
// this.setState(obj)
|
||||
}
|
||||
|
||||
if ([
|
||||
DictType.collect,
|
||||
DictType.wrong,
|
||||
DictType.simple,
|
||||
].includes(this.current.dictType)) {
|
||||
if ([
|
||||
DictType.collect,
|
||||
DictType.wrong,
|
||||
DictType.simple,
|
||||
].includes(this.current.dictType)) {
|
||||
|
||||
} else {
|
||||
if ([
|
||||
DictType.word,
|
||||
DictType.customWord,
|
||||
].includes(this.current.dictType)) {
|
||||
if (!this.currentDict.originWords.length) {
|
||||
let r = await fetch(`./dicts/${this.currentDict.language}/${this.currentDict.type}/${this.currentDict.translateLanguage}/${this.currentDict.url}`)
|
||||
// let r = await fetch(`.${this.currentDict.url}`)
|
||||
r.json().then(v => {
|
||||
if (this.currentDict.translateLanguage === 'common') {
|
||||
const runtimeStore = useRuntimeStore()
|
||||
fetch('./translate/en2zh_CN.json').then(r => {
|
||||
r.json().then((list: Word[]) => {
|
||||
console.time()
|
||||
runtimeStore.translateWordList = list
|
||||
} else {
|
||||
if ([
|
||||
DictType.word,
|
||||
DictType.customWord,
|
||||
].includes(this.current.dictType)) {
|
||||
if (!this.currentDict.originWords.length) {
|
||||
let r = await fetch(`./dicts/${this.currentDict.language}/${this.currentDict.type}/${this.currentDict.translateLanguage}/${this.currentDict.url}`)
|
||||
// let r = await fetch(`.${this.currentDict.url}`)
|
||||
r.json().then(v => {
|
||||
if (this.currentDict.translateLanguage === 'common') {
|
||||
const runtimeStore = useRuntimeStore()
|
||||
fetch('./translate/en2zh_CN.json').then(r => {
|
||||
r.json().then((list: Word[]) => {
|
||||
console.time()
|
||||
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)
|
||||
})
|
||||
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)
|
||||
})
|
||||
|
||||
this.load = true
|
||||
this.load = true
|
||||
|
||||
console.timeEnd()
|
||||
})
|
||||
})
|
||||
} else {
|
||||
this.currentDict.originWords = cloneDeep(v)
|
||||
this.currentDict.words = cloneDeep(v)
|
||||
this.currentDict.chapterWords = chunk(this.currentDict.words, this.currentDict.chapterWordNumber)
|
||||
this.load = true
|
||||
}
|
||||
})
|
||||
}
|
||||
console.timeEnd()
|
||||
})
|
||||
})
|
||||
} else {
|
||||
this.currentDict.originWords = cloneDeep(v)
|
||||
this.currentDict.words = cloneDeep(v)
|
||||
this.currentDict.chapterWords = chunk(this.currentDict.words, this.currentDict.chapterWordNumber)
|
||||
this.load = true
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if ([
|
||||
DictType.article,
|
||||
DictType.customArticle,
|
||||
].includes(this.current.dictType)) {
|
||||
console.log(1, this.currentDict)
|
||||
if (!this.currentDict.articles.length) {
|
||||
console.log(2)
|
||||
let r = await fetch(`./dicts/${this.currentDict.language}/${this.currentDict.type}/${this.currentDict.translateLanguage}/${this.currentDict.url}`)
|
||||
r.json().then((v: any[]) => {
|
||||
console.log(3)
|
||||
this.currentDict.articles = cloneDeep(v.map(v => {
|
||||
v.id = uuidv4()
|
||||
return v
|
||||
}))
|
||||
this.load = 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, chapterWordIndex: number = dict.chapterWordNumber, practiceType: DictType) {
|
||||
//TODO 保存统计
|
||||
// this.saveStatistics()
|
||||
console.log('changeDict', cloneDeep(dict), chapterIndex, chapterWordIndex)
|
||||
this.current.dictType = 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]
|
||||
} else {
|
||||
let rIndex = this.myDicts.findIndex((v: Dict) => v.name === dict.name)
|
||||
if (rIndex > -1) {
|
||||
this.myDicts[rIndex] = dict
|
||||
this.current.index = rIndex
|
||||
} else {
|
||||
this.myDicts.push(cloneDeep(dict))
|
||||
this.current.index = this.myDicts.length - 1
|
||||
}
|
||||
}
|
||||
emitter.emit(EventKey.resetWord)
|
||||
}
|
||||
|
||||
if ([
|
||||
DictType.article,
|
||||
DictType.customArticle,
|
||||
].includes(this.current.dictType)) {
|
||||
console.log(1, this.currentDict)
|
||||
if (!this.currentDict.articles.length) {
|
||||
console.log(2)
|
||||
let r = await fetch(`./dicts/${this.currentDict.language}/${this.currentDict.type}/${this.currentDict.translateLanguage}/${this.currentDict.url}`)
|
||||
r.json().then((v: any[]) => {
|
||||
console.log(3)
|
||||
this.currentDict.articles = cloneDeep(v.map(v => {
|
||||
v.id = uuidv4()
|
||||
return v
|
||||
}))
|
||||
this.load = 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, chapterWordIndex: number = dict.chapterWordNumber, practiceType: DictType) {
|
||||
//TODO 保存统计
|
||||
// this.saveStatistics()
|
||||
console.log('changeDict', cloneDeep(dict), chapterIndex, chapterWordIndex)
|
||||
this.current.dictType = 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]
|
||||
} else {
|
||||
let rIndex = this.myDicts.findIndex((v: Dict) => v.name === dict.name)
|
||||
if (rIndex > -1) {
|
||||
this.myDicts[rIndex] = dict
|
||||
this.current.index = rIndex
|
||||
} else {
|
||||
this.myDicts.push(cloneDeep(dict))
|
||||
this.current.index = this.myDicts.length - 1
|
||||
}
|
||||
}
|
||||
emitter.emit(EventKey.resetWord)
|
||||
}
|
||||
},
|
||||
})
|
||||
@@ -1,81 +1,96 @@
|
||||
import {defineStore} from "pinia"
|
||||
import {cloneDeep} from "lodash-es";
|
||||
import {DefaultShortcutKeyMap} from "@/types.ts";
|
||||
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,
|
||||
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,
|
||||
shortcutKeyMap: Record<string, string>
|
||||
}
|
||||
|
||||
export const useSettingStore = defineStore('setting', {
|
||||
state: (): SettingState => {
|
||||
return {
|
||||
showToolbar: true,
|
||||
show: false,
|
||||
state: (): SettingState => {
|
||||
return {
|
||||
showToolbar: true,
|
||||
show: false,
|
||||
showPanel: false,
|
||||
|
||||
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,
|
||||
showPanel: 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,
|
||||
shortcutKeyMap: cloneDeep(DefaultShortcutKeyMap)
|
||||
theme: 'auto',
|
||||
collapse: false,
|
||||
shortcutKeyMap: cloneDeep(DefaultShortcutKeyMap)
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
setState(obj: any) {
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
this[key] = value
|
||||
}
|
||||
},
|
||||
init() {
|
||||
let configStr = localStorage.getItem(SaveConfig.key)
|
||||
if (configStr) {
|
||||
let obj = JSON.parse(configStr)
|
||||
// this.setState(obj)
|
||||
this.setState(obj.val)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
275
src/types.ts
275
src/types.ts
@@ -5,21 +5,27 @@ import deFlag from "./assets/img/flags/de.png";
|
||||
import codeFlag from "@/assets/img/flags/code.png";
|
||||
|
||||
export type Word = {
|
||||
"name": string,
|
||||
"usphone": string,
|
||||
"ukphone": string,
|
||||
"trans": string[]
|
||||
"name": string,
|
||||
"usphone": string,
|
||||
"ukphone": string,
|
||||
"trans": string[]
|
||||
}
|
||||
|
||||
export const DefaultWord: Word = {
|
||||
name: '',
|
||||
usphone: '',
|
||||
ukphone: '',
|
||||
trans: []
|
||||
name: '',
|
||||
usphone: '',
|
||||
ukphone: '',
|
||||
trans: []
|
||||
}
|
||||
|
||||
export const SaveDictKey = 'typing-word-dict'
|
||||
export const SaveConfigKey = 'typing-word-config'
|
||||
export const SaveDict = {
|
||||
key: 'typing-word-dict',
|
||||
version: 1
|
||||
}
|
||||
export const SaveConfig = {
|
||||
key: 'typing-word-config',
|
||||
version: 1
|
||||
}
|
||||
|
||||
export const PronunciationApi = 'https://dict.youdao.com/dictvoice?audio='
|
||||
|
||||
@@ -27,179 +33,184 @@ 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
|
||||
category: string
|
||||
tags: string[]
|
||||
url: string
|
||||
length: number
|
||||
translateLanguage: TranslateLanguageType
|
||||
type: DictType
|
||||
language: LanguageType
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
category: string
|
||||
tags: string[]
|
||||
url: string
|
||||
length: number
|
||||
translateLanguage: TranslateLanguageType
|
||||
type: DictType
|
||||
language: LanguageType
|
||||
}
|
||||
|
||||
export interface Dict {
|
||||
id: string,
|
||||
name: string,
|
||||
sort: Sort,
|
||||
originWords: Word[],//原始单词
|
||||
words: Word[],
|
||||
chapterWordNumber: number,//章节单词数量
|
||||
chapterWords: Word[][],
|
||||
chapterIndex: number,//章节下标
|
||||
wordIndex: number,//单词下标
|
||||
articles: Article[],
|
||||
statistics: Statistics[],
|
||||
resourceId: string,
|
||||
type: DictType,
|
||||
translateLanguage: TranslateLanguageType
|
||||
language: LanguageType
|
||||
url: string,
|
||||
id: string,
|
||||
name: string,
|
||||
sort: Sort,
|
||||
originWords: Word[],//原始单词
|
||||
words: Word[],
|
||||
chapterWordNumber: number,//章节单词数量
|
||||
chapterWords: Word[][],
|
||||
chapterIndex: number,//章节下标
|
||||
wordIndex: number,//单词下标
|
||||
articles: Article[],
|
||||
statistics: Statistics[],
|
||||
resourceId: string,
|
||||
type: DictType,
|
||||
translateLanguage: TranslateLanguageType
|
||||
language: LanguageType
|
||||
url: string,
|
||||
}
|
||||
|
||||
|
||||
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[]
|
||||
wrongWords: Word[]
|
||||
}
|
||||
|
||||
export const DefaultDisplayStatistics: DisplayStatistics = {
|
||||
startDate: Date.now(),
|
||||
endDate: -1,
|
||||
spend: -1,
|
||||
total: -1,
|
||||
correctRate: -1,
|
||||
wrongWordNumber: -1,
|
||||
wrongWords: [],
|
||||
startDate: Date.now(),
|
||||
endDate: -1,
|
||||
spend: -1,
|
||||
total: -1,
|
||||
correctRate: -1,
|
||||
wrongWordNumber: -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 DefaultShortcutKeyMap = {
|
||||
Show: 'Escape',
|
||||
Ignore: 'Tab',
|
||||
Remove: '`',
|
||||
Collect: 'Enter',
|
||||
Show: 'Escape',
|
||||
Skip: 'Tab',
|
||||
SetEasy: '`',
|
||||
SetCollect: 'Enter',
|
||||
NextChapter: 'Ctrl+➡',
|
||||
ReplayChapter: 'Ctrl+Enter',
|
||||
DictationChapter: 'Alt+Enter',
|
||||
PlaySound: 'Ctrl+P',
|
||||
ToggleShowTranslate:'Ctrl+T',
|
||||
ToggleDictation:'Ctrl+I',
|
||||
}
|
||||
|
||||
|
||||
|
||||
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: '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},
|
||||
]
|
||||
|
||||
export const DefaultDict: Dict = {
|
||||
id: '',
|
||||
name: '',
|
||||
sort: Sort.normal,
|
||||
originWords: [],//原始单词
|
||||
words: [],
|
||||
chapterWordNumber: 30,//章节单词数量
|
||||
chapterWords: [],
|
||||
chapterIndex: 0,//章节下标
|
||||
wordIndex: 0,//单词下标
|
||||
articles: [],
|
||||
statistics: [],
|
||||
resourceId: '',
|
||||
type: DictType.word,
|
||||
translateLanguage: 'common',
|
||||
language: 'en',
|
||||
url: '',
|
||||
id: '',
|
||||
name: '',
|
||||
sort: Sort.normal,
|
||||
originWords: [],//原始单词
|
||||
words: [],
|
||||
chapterWordNumber: 30,//章节单词数量
|
||||
chapterWords: [],
|
||||
chapterIndex: 0,//章节下标
|
||||
wordIndex: 0,//单词下标
|
||||
articles: [],
|
||||
statistics: [],
|
||||
resourceId: '',
|
||||
type: DictType.word,
|
||||
translateLanguage: 'common',
|
||||
language: 'en',
|
||||
url: '',
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
export function getRandom(a: number, b: number): number {
|
||||
return Math.random() * (b - a) + a;
|
||||
}
|
||||
return Math.random() * (b - a) + a;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user