fix(all): debug

This commit is contained in:
zyronon
2023-09-21 00:01:36 +08:00
parent 1b2f8a2d45
commit a262f1ec49
14 changed files with 692 additions and 567 deletions

1
auto-imports.d.ts vendored
View File

@@ -5,5 +5,6 @@
// Generated by unplugin-auto-import
export {}
declare global {
const ElMessage: typeof import('element-plus/es')['ElMessage']
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
}

View File

@@ -2,6 +2,7 @@
import {onMounted} from "vue";
import Tooltip from "@/components/Tooltip.vue";
import {Icon} from '@iconify/vue';
import {useEsc} from "@/hooks/event.ts";
interface IProps {
modelValue: boolean,
@@ -25,13 +26,8 @@ function close() {
emit('close',)
}
onMounted(() => {
window.addEventListener('keyup', (e: KeyboardEvent) => {
if (e.key === 'Escape' && props.modelValue) {
close()
}
})
})
useEsc(close)
</script>
<template>

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import {onMounted, reactive, watch} from "vue";
import {Article, Sentence, TranslateEngine} from "@/types.ts";
import {Article, DefaultArticle, Sentence, TranslateEngine, TranslateType} from "@/types.ts";
import BaseButton from "@/components/BaseButton.vue";
import {
getNetworkTranslate,
@@ -13,6 +13,9 @@ import * as copy from "copy-to-clipboard";
import {getSplitTranslateText, splitArticle} from "@/hooks/article.ts";
import EditAbleText from "@/components/EditAbleText.vue";
import {Icon} from "@iconify/vue";
import {cloneDeep} from "lodash-es";
import {useRuntimeStore} from "@/stores/runtime.ts";
import {useDisableEventListener, useEsc} from "@/hooks/event.ts";
let article1 = `How does the older investor differ in his approach to investment from the younger investor?
There is no shortage of tipsters around offering 'get-rich-quick' opportunities. But if you are a serious private investor, leave the Las Vegas mentality to those with money to fritter. The serious investor needs a proper 'portfolio' -- a well-planned selection of investments, with a definite structure and a clear aim. But exactly how does a newcomer to the stock market go about achieving that?
@@ -40,27 +43,27 @@ NIGEL BUXTON The Great Escape from The Weekend Telegraph`
// article2 = `Economy is one powerful motive for camping? since after the initial outlay upon equipment, or through hiring it, the total expense can be far less than the cost of hotels. But, contrary to a popular assumption, it is far from being the only one, or even the greatest. The man who manoeuvres carelessly into his twenty pounds' worth of space at one of Europe's myriad permanent sites may find himself bumping a Bentley. More likely, Ford Escort will be hub to hub with Renault or Mercedes, but rarely with bicycles made for two.`
interface IProps {
article?: Article
}
let article = reactive<Article>({
title: 'A private conversation!',
titleTranslate: '',
article: article1,
customTranslate: ``,
networkTranslate: ``,
newWords: [],
articleAllWords: [],
sections: [],
isTranslated: false,
translateType: 0,
const props = withDefaults(defineProps<IProps>(), {
article: () => cloneDeep(DefaultArticle)
})
let article = reactive<Article>(props.article)
let networkTranslateEngine = $ref('baidu')
let progress = $ref(0)
const TranslateEngineOptions = [
{value: 'baidu', label: '百度'},
{value: 'youdao', label: '有道'},
]
defineEmits(['close'])
const emit = defineEmits(['close'])
useDisableEventListener()
useEsc(() => {
emit('close')
})
onMounted(() => {
updateSentenceTranslate()
@@ -71,6 +74,12 @@ function updateSections() {
}
async function startNetworkTranslate() {
if (!article.title.trim()) {
return ElMessage.error('请填写标题!')
}
if (!article.article.trim()) {
return ElMessage.error('请填写正文!')
}
updateSections()
article.networkTranslate = ''
//注意!!!
@@ -87,7 +96,7 @@ async function startNetworkTranslate() {
function saveSentenceTranslate(sentence: Sentence, val: string) {
sentence.translate = val
if (article.translateType) {
if (article.translateType === TranslateType.custom) {
article.customTranslate = getSentenceAllTranslateText(article)
} else {
article.networkTranslate = getSentenceAllTranslateText(article)
@@ -103,7 +112,7 @@ function saveSentenceText(sentence: Sentence, val: string) {
function updateSentenceTranslate() {
if (article.article.trim()) {
updateSections()
if (article.translateType) {
if (article.translateType === TranslateType.custom) {
updateLocalSentenceTranslate(article, article.customTranslate)
} else {
updateLocalSentenceTranslate(article, article.networkTranslate)
@@ -112,7 +121,7 @@ function updateSentenceTranslate() {
}
function appendTranslate(str: string) {
if (article.translateType) {
if (article.translateType === TranslateType.custom) {
article.customTranslate += str
} else {
article.networkTranslate += str
@@ -144,7 +153,7 @@ function onFocus() {
}
function save() {
console.log('article',article )
console.log('article', article)
copy(JSON.stringify(article))
}
@@ -158,7 +167,7 @@ watch(() => article.networkTranslate, (str: string) => {
watch(() => article.translateType, () => {
if (article.article.trim()) {
if (article.translateType) {
if (article.translateType === TranslateType.custom) {
if (article.customTranslate.trim()) {
updateLocalSentenceTranslate(article, article.customTranslate)
} else {
@@ -211,8 +220,8 @@ watch(() => article.translateType, () => {
<div class="label">
<span>标题</span>
<el-radio-group v-model="article.translateType">
<el-radio-button :label="0">网络翻译</el-radio-button>
<el-radio-button :label="1">本地翻译</el-radio-button>
<el-radio-button :label="TranslateType.custom">本地翻译</el-radio-button>
<el-radio-button :label="TranslateType.network">网络翻译</el-radio-button>
</el-radio-group>
</div>
<textarea
@@ -226,7 +235,7 @@ watch(() => article.translateType, () => {
<div class="item basic">
<div class="label">
<span>正文</span>
<div class="translate-item" v-if="!article.translateType">
<div class="translate-item" v-if="article.translateType === TranslateType.network">
<el-progress :percentage="progress"
:duration="30"
:striped="progress !== 100"
@@ -245,14 +254,13 @@ watch(() => article.translateType, () => {
</el-select>
<BaseButton
size="small"
@click="startNetworkTranslate"
:disabled="!article.article.trim()">开始翻译
@click="startNetworkTranslate">开始翻译
</BaseButton>
</div>
</div>
<textarea
v-if="article.translateType"
v-if="article.translateType === TranslateType.custom"
v-model="article.customTranslate"
:readonly="![100,0].includes(progress)"
@blur="onBlur"

View File

@@ -12,10 +12,18 @@ import Statistics from "@/components/Practice/Statistics.vue";
import {emitter, EventKey} from "@/utils/eventBus";
import {useSettingStore} from "@/stores/setting";
import {cloneDeep} from "lodash-es";
import {Article, DefaultArticle} from "@/types.ts";
import AddArticle from "@/components/Practice/AddArticle.vue";
import {useEventListener, useStartKeyboardEventListener} from "@/hooks/event.ts";
import {useRuntimeStore} from "@/stores/runtime.ts";
const practiceStore = usePracticeStore()
const store = useBaseStore()
const settingStore = useSettingStore()
const runtimeStore = useRuntimeStore()
let showEditArticle = $ref(false)
let editArticle = $ref(cloneDeep(DefaultArticle))
watch(practiceStore, () => {
if (practiceStore.inputNumber < 1) {
@@ -1139,24 +1147,30 @@ let articleData = $ref({
watch(() => store.load, n => {
if (n) {
getCurrentWords()
getCurrentPractice()
}
})
function getCurrentWords() {
wordData.words = cloneDeep(store.chapter)
wordData.index = 0
}
function getCurrentPractice() {
if (store.isArticle) {
let article: Article = cloneDeep(store.currentDict.articles[store.currentDict.chapterIndex])
if (article?.isTranslated) {
articleData.article = article
} else {
function getCurrentArticle() {
wordData.words = cloneDeep(store.chapter)
wordData.index = 0
}
} else {
wordData.words = cloneDeep(store.chapter)
wordData.index = 0
}
}
onMounted(() => {
})
useStartKeyboardEventListener()
function write() {
console.log('write')
settingStore.dictation = true
@@ -1166,7 +1180,7 @@ function write() {
//TODO 需要判断是否已忽略
function repeat() {
console.log('repeat')
getCurrentWords()
getCurrentPractice()
emitter.emit(EventKey.resetWord)
}
@@ -1183,7 +1197,7 @@ function next() {
<div class="practice">
<Toolbar/>
<TypeArticle
v-if="practiceStore.type === 'article'"
v-if="store.isArticle"
:article="articleData.article"
:sectionIndex="articleData.sectionIndex"
:sentenceIndex="articleData.sentenceIndex"
@@ -1201,6 +1215,9 @@ function next() {
@repeat="repeat"
@next="next"
/>
<AddArticle v-if="showEditArticle"
@close="showEditArticle = false"
/>
</template>
<style scoped lang="scss">

View File

@@ -7,7 +7,7 @@ import {usePracticeStore} from "@/stores/practice.ts";
import TypeWord from "@/components/Practice/TypeWord.vue";
import {useSettingStore} from "@/stores/setting.ts";
import {usePlayBeep, usePlayCorrect, usePlayKeyboardAudio, usePlayWordAudio} from "@/hooks/sound.ts";
import {useEventListener} from "@/hooks/event.ts";
import {useEventListener, useOnKeyboardEventListener} from "@/hooks/event.ts";
let article1 = `How does the older investor differ in his approach to investment from the younger investor?
There is no shortage of tipsters around offering 'get-rich-quick' opportunities. But if you are a serious private investor, leave the Las Vegas mentality to those with money to fritter. The serious investor needs a proper 'portfolio' -- a well-planned selection of investments, with a definite structure and a clear aim. But exactly how does a newcomer to the stock market go about achieving that?
@@ -304,6 +304,10 @@ function onKeyUp() {
}
}
useOnKeyboardEventListener(onKeyDown, onKeyUp)
// useEventListener('keydown', onKeyDown)
// useEventListener('keyup', onKeyUp)
function playWord(word: ArticleWord) {
playWordAudio(word.name)
@@ -355,8 +359,6 @@ function otherWord(word: ArticleWord, i: number, i2: number, i3: number) {
return str
}
useEventListener('keydown', onKeyDown)
useEventListener('keyup', onKeyUp)
</script>
<template>

View File

@@ -9,7 +9,7 @@ import {cloneDeep} from "lodash-es"
import {usePracticeStore} from "@/stores/practice.ts"
import {useSettingStore} from "@/stores/setting.ts";
import {usePlayBeep, usePlayCorrect, usePlayKeyboardAudio, usePlayWordAudio} from "@/hooks/sound.ts";
import {useEventListener} from "@/hooks/event.ts";
import {useEventListener, useOnKeyboardEventListener} from "@/hooks/event.ts";
interface IProps {
words: Word[],
@@ -75,9 +75,6 @@ onMounted(() => {
})
})
useEventListener('keydown', onKeyDown)
useEventListener('keyup', onKeyUp)
function next() {
if (data.index === data.words.length - 1) {
if (data.wrongWords.length) {
@@ -201,6 +198,11 @@ async function onKeyDown(e: KeyboardEvent) {
}, 200)
}
}
useOnKeyboardEventListener(onKeyDown, onKeyUp)
// useEventListener('keydown', onKeyDown)
// useEventListener('keyup', onKeyUp)
</script>
<template>

View File

@@ -5,6 +5,7 @@ import {Icon} from '@iconify/vue';
import {watch, ref} from "vue";
import {useSettingStore} from "@/stores/setting.ts";
import {useChangeAllSound, useWatchAllSound} from "@/hooks/sound.ts";
import {useDisableEventListener} from "@/hooks/event.ts";
const tabIndex = $ref(0)
const settingStore = useSettingStore()
@@ -21,6 +22,7 @@ const emit = defineEmits([
'update:modelValue',
])
// useDisableEventListener()
useWatchAllSound()
</script>

View File

@@ -310,3 +310,4 @@ export function getSplitTranslateText(article: string) {
}
return str
}

View File

@@ -1,5 +1,6 @@
import {onMounted, onUnmounted} from "vue";
import {emitter, EventKey} from "@/utils/eventBus.ts";
import {useRuntimeStore} from "@/stores/runtime.ts";
export function useWindowClick(cb: () => void) {
onMounted(() => {
@@ -16,13 +17,49 @@ export function useEventListener(type: string, listener: EventListenerOrEventLis
onUnmounted(() => window.removeEventListener(type, listener))
}
export function useEsc(can: boolean) {
export function useStartKeyboardEventListener() {
const runtimeStore = useRuntimeStore()
useEventListener('keydown', (e: KeyboardEvent) => {
if (!runtimeStore.disableEventListener) {
emitter.emit(EventKey.keydown, e)
}
})
useEventListener('keyup', (e: KeyboardEvent) => {
if (!runtimeStore.disableEventListener) {
emitter.emit(EventKey.keyup, e)
}
})
}
export function useOnKeyboardEventListener(onKeyDown: (e: KeyboardEvent) => void, onKeyUp: (e: KeyboardEvent) => void) {
onMounted(() => {
emitter.on(EventKey.keydown, onKeyDown)
emitter.on(EventKey.keyup, onKeyUp)
})
onUnmounted(() => {
emitter.off(EventKey.keydown, onKeyDown)
emitter.off(EventKey.keyup, onKeyUp)
})
}
export function useDisableEventListener() {
const runtimeStore = useRuntimeStore()
onMounted(() => {
runtimeStore.disableEventListener = true
})
onUnmounted(() => {
runtimeStore.disableEventListener = false
})
}
export function useEsc(close: () => void) {
onMounted(() => {
window.addEventListener('keyup', (e: KeyboardEvent) => {
if (e.key === 'Escape' && can) {
if (e.key === 'Escape') {
close()
}
})
})
return []
}
}

View File

@@ -1,53 +1,52 @@
import {Article, Sentence, TranslateEngine} from "@/types.ts";
import {Article, Sentence, TranslateEngine, TranslateType} from "@/types.ts";
import Baidu from "@opentranslate/baidu";
import {axiosInstance} from "@/utils/http.ts";
import {CnKeyboardMap, EnKeyboardMap, splitCNArticle} from "@/hooks/article.ts";
import {getSplitTranslateText, splitArticle} from "@/hooks/article.ts";
import {Translator} from "@opentranslate/translator/src/translator.ts";
import {cloneDeep} from "lodash-es";
export function updateLocalSentenceTranslate(article: Article, translate: string) {
if (translate.trim()) {
let articleTranslate = translate.split('\n')
// console.log('articleTranslate', articleTranslate)
let count = 0
for (let i = 0; i < article.sections.length; i++) {
let v = article.sections[i]
for (let j = 0; j < v.length; j++) {
let sentence = v[j]
try {
sentence.translate = articleTranslate[count]
} catch (e) {
console.log('没有对应的翻译', sentence.text)
if (translate.trim()) {
let articleTranslate = translate.split('\n')
// console.log('articleTranslate', articleTranslate)
let count = 0
for (let i = 0; i < article.sections.length; i++) {
let v = article.sections[i]
for (let j = 0; j < v.length; j++) {
let sentence = v[j]
try {
sentence.translate = articleTranslate[count]
} catch (e) {
console.log('没有对应的翻译', sentence.text)
}
count++
}
count++
}
count++
}
count++
}
}
}
export function getSentenceAllTranslateText(article: Article) {
let str = ''
article.sections.map((v: Sentence[]) => {
v.map((w: Sentence, j, arr) => {
if (w.translate) {
str += w.translate + '\n'
}
let str = ''
article.sections.map((v: Sentence[]) => {
v.map((w: Sentence, j, arr) => {
if (w.translate) {
str += w.translate + '\n'
}
})
str += '\n'
})
str += '\n'
})
return str
return str
}
export function getSentenceAllText(article: Article) {
let str = ''
article.sections.map((v: Sentence[]) => {
v.map((w: Sentence, j, arr) => {
str += w.text
let str = ''
article.sections.map((v: Sentence[]) => {
v.map((w: Sentence, j, arr) => {
str += w.text
})
str += '\n'
})
str += '\n'
})
return str
return str
}
/***
@@ -58,135 +57,162 @@ export function getSentenceAllText(article: Article) {
* @param progressCb 进度回调
* */
export async function getNetworkTranslate(
article: Article,
translateEngine: TranslateEngine,
allShow: boolean = false,
progressCb?: (val: number) => void
article: Article,
translateEngine: TranslateEngine,
allShow: boolean = false,
progressCb?: (val: number) => void
) {
if (article.networkTranslate) {
updateLocalSentenceTranslate(article, article.networkTranslate)
} else {
let translator: Translator
if (translateEngine === TranslateEngine.Baidu) {
translator = new Baidu({
axios: axiosInstance as any,
config: {
appid: "20230910001811857",
key: "Xxe_yftQR3K3Ue43NQMC"
if (article.networkTranslate) {
updateLocalSentenceTranslate(article, article.networkTranslate)
} else {
let translator: Translator
if (translateEngine === TranslateEngine.Baidu) {
translator = new Baidu({
axios: axiosInstance as any,
config: {
appid: "20230910001811857",
key: "Xxe_yftQR3K3Ue43NQMC"
}
}) as any
}
if (translator) {
if (!article.titleTranslate) {
translator.translate(article.title, 'en', 'zh-CN').then(r => {
article.titleTranslate = r.trans.paragraphs[0]
})
}
let promiseList = []
let retryCount = 0
let retryCountMap = new Map()
const translate = async (sentence: Sentence) => {
try {
let r = await translator.translate(sentence.text, 'en', 'zh-CN')
if (r) {
const cb = () => {
sentence.translate = r.trans.paragraphs[0]
if (!allShow) {
//一次显示所有,顺序会乱
article.networkTranslate += sentence.translate + '\n'
}
}
return Promise.resolve(cb)
} else {
return Promise.reject(() => translate(sentence))
}
} catch (e) {
return Promise.reject(() => translate(sentence))
}
}
let total = 0
let index = 0
article.sections.map(v => total += v.length)
for (let i = 0; i < article.sections.length; i++) {
let v = article.sections[i]
for (let j = 0; j < v.length; j++) {
let sentence = v[j]
let promise = translate(sentence)
if (allShow) {
promiseList.push(promise)
} else {
retryCountMap.set(sentence.text, 0)
let errResult: any
let cb = await promise.catch(err => {
errResult = err
})
while (errResult) {
let count = retryCountMap.get(sentence.text)
if (count > 2) break
cb = await errResult().catch(err => {
errResult = err
})
retryCountMap.set(sentence.text, count + 1)
}
if (cb) cb()
index++
if (progressCb) {
progressCb(Math.floor((index / total) * 100))
}
}
}
}
if (promiseList.length) {
let timer = -1
let progress = 0
if (progressCb) {
timer = setInterval(() => {
progress++
if (progress > 90) {
return clearInterval(timer)
}
progressCb(progress)
}, 100)
}
return new Promise(async resolve => {
let cbs = []
do {
if (retryCount > 2) {
return resolve(true)
}
let results = await Promise.allSettled(promiseList)
promiseList = []
results.map(results => {
if (results.status === 'fulfilled') {
cbs.push(results.value)
} else {
promiseList.push(results.reason())
}
})
retryCount++
} while (promiseList.length)
cbs.map(v => v())
article.networkTranslate = getSentenceAllTranslateText(article)
if (progressCb) {
clearInterval(timer)
progress = 100
progressCb(100)
}
resolve(true)
})
} else {
article.networkTranslate = getSentenceAllTranslateText(article)
}
}
}) as any
}
}
export function test(article: Article) {
if (article?.isTranslated) {
if (!article.sections?.length) {
if (translator) {
if (!article.titleTranslate) {
translator.translate(article.title, 'en', 'zh-CN').then(r => {
article.titleTranslate = r.trans.paragraphs[0]
})
}
let promiseList = []
let retryCount = 0
let retryCountMap = new Map()
const translate = async (sentence: Sentence) => {
try {
let r = await translator.translate(sentence.text, 'en', 'zh-CN')
if (r) {
const cb = () => {
sentence.translate = r.trans.paragraphs[0]
if (!allShow) {
//一次显示所有,顺序会乱
article.networkTranslate += sentence.translate + '\n'
}
}
return Promise.resolve(cb)
} else {
return Promise.reject(() => translate(sentence))
}
} catch (e) {
return Promise.reject(() => translate(sentence))
}
}
let total = 0
let index = 0
article.sections.map(v => total += v.length)
for (let i = 0; i < article.sections.length; i++) {
let v = article.sections[i]
for (let j = 0; j < v.length; j++) {
let sentence = v[j]
let promise = translate(sentence)
if (allShow) {
promiseList.push(promise)
} else {
retryCountMap.set(sentence.text, 0)
let errResult: any
let cb = await promise.catch(err => {
errResult = err
})
while (errResult) {
let count = retryCountMap.get(sentence.text)
if (count > 2) break
cb = await errResult().catch(err => {
errResult = err
})
retryCountMap.set(sentence.text, count + 1)
} else {
if (article.translateType !== undefined) {
if (article.translateType) {
updateLocalSentenceTranslate(article, article.customTranslate)
} else {
updateLocalSentenceTranslate(article, article.networkTranslate)
}
if (cb) cb()
index++
if (progressCb) {
progressCb(Math.floor((index / total) * 100))
} else {
article.sections = splitArticle(article.article)
if (article.customTranslate) {
article.customTranslate = getSplitTranslateText(article.customTranslate)
updateLocalSentenceTranslate(article, article.customTranslate)
article.translateType = TranslateType.custom
} else {
article.networkTranslate = getSplitTranslateText(article.networkTranslate)
updateLocalSentenceTranslate(article, article.customTranslate)
article.translateType = TranslateType.network
}
}
}
}
if (promiseList.length) {
let timer = -1
let progress = 0
if (progressCb) {
timer = setInterval(() => {
progress++
if (progress > 90) {
return clearInterval(timer)
}
progressCb(progress)
}, 100)
}
return new Promise(async resolve => {
let cbs = []
do {
if (retryCount > 2) {
return resolve(true)
}
let results = await Promise.allSettled(promiseList)
promiseList = []
results.map(results => {
if (results.status === 'fulfilled') {
cbs.push(results.value)
} else {
promiseList.push(results.reason())
}
})
retryCount++
} while (promiseList.length)
cbs.map(v => v())
article.networkTranslate = getSentenceAllTranslateText(article)
if (progressCb) {
clearInterval(timer)
progress = 100
progressCb(100)
}
resolve(true)
})
} else {
article.networkTranslate = getSentenceAllTranslateText(article)
}
}
}
}

View File

@@ -4,238 +4,238 @@ import {chunk, cloneDeep} from "lodash-es";
import {emitter, EventKey} from "@/utils/eventBus.ts"
export const useBaseStore = defineStore('base', {
state: (): State => {
return {
newWordDict: {
name: '生词本',
sort: Sort.normal,
type: DictType.newDict,
originWords: [],
articles: [],
words: [],
chapterWordNumber: 15,
chapterWords: [],
chapterIndex: 0,
chapterWordIndex: 0,
statistics: [],
url: '',
},
skipWordDict: {
name: '简单词',
sort: Sort.normal,
type: DictType.skipDict,
originWords: [],
articles: [],
words: [],
chapterWordNumber: 15,
chapterWords: [],
chapterIndex: 0,
chapterWordIndex: 0,
statistics: [],
url: '',
},
wrongWordDict: {
name: '错词本',
sort: Sort.normal,
type: DictType.wrongDict,
originWords: [],
articles: [],
words: [],
chapterWordNumber: 15,
chapterWords: [],
chapterIndex: 0,
chapterWordIndex: 0,
statistics: [],
url: '',
},
// dict: {
// name: '新概念英语-2',
// sort: Sort.normal,
// type: DictType.innerDict,
// originWords: [],
// articles: [],
// words: [],
// chapterWordNumber: 15,
// chapterWords: [],
// chapterIndex: 0,
// chapterWordIndex: 0,
// statistics: [],
// url: '/dicts/NCE_2.json',
// },
dict: {
name: '新概念英语-2',
sort: Sort.normal,
type: DictType.publicArticle,
originWords: [],
articles: [],
words: [],
chapterWordNumber: 15,
chapterWords: [],
chapterIndex: 0,
chapterWordIndex: 0,
statistics: [],
url: '/articles/NCE_2.json',
},
oldDicts: [],
current: {
dictType: DictType.publicDict,
words: [],
index: -1,
wrongWords: [],
originWrongWords: [],
repeatNumber: 0,
statistics: {
startDate: -1,
endDate: -1,
spend: -1,
total: -1,
correctRate: -1,
wrongWordNumber: -1,
}
},
sideIsOpen: false,
isDictation: true,
simpleWords: [
'a', 'an', 'of', 'and',
'i', 'my', 'you', 'your',
'me', 'am', 'is', 'do', 'are',
'what', 'who', 'where', 'how', 'no', 'yes',
'not', 'did', 'were', 'can', 'could', 'it',
'the', 'to'
],
theme: 'auto',
load: false
state: (): State => {
return {
newWordDict: {
name: '生词本',
sort: Sort.normal,
type: DictType.newDict,
originWords: [],
articles: [],
words: [],
chapterWordNumber: 15,
chapterWords: [],
chapterIndex: 0,
chapterWordIndex: 0,
statistics: [],
url: '',
},
skipWordDict: {
name: '简单词',
sort: Sort.normal,
type: DictType.skipDict,
originWords: [],
articles: [],
words: [],
chapterWordNumber: 15,
chapterWords: [],
chapterIndex: 0,
chapterWordIndex: 0,
statistics: [],
url: '',
},
wrongWordDict: {
name: '错词本',
sort: Sort.normal,
type: DictType.wrongDict,
originWords: [],
articles: [],
words: [],
chapterWordNumber: 15,
chapterWords: [],
chapterIndex: 0,
chapterWordIndex: 0,
statistics: [],
url: '',
},
// dict: {
// name: '新概念英语-2',
// sort: Sort.normal,
// type: DictType.innerDict,
// originWords: [],
// articles: [],
// words: [],
// chapterWordNumber: 15,
// chapterWords: [],
// chapterIndex: 0,
// chapterWordIndex: 0,
// statistics: [],
// url: '/dicts/NCE_2.json',
// },
dict: {
name: '新概念英语-2',
sort: Sort.normal,
type: DictType.publicArticle,
originWords: [],
articles: [],
words: [],
chapterWordNumber: 15,
chapterWords: [],
chapterIndex: 0,
chapterWordIndex: 0,
statistics: [],
url: '/articles/NCE_2.json',
},
oldDicts: [],
current: {
dictType: DictType.publicArticle,
words: [],
index: -1,
wrongWords: [],
originWrongWords: [],
repeatNumber: 0,
statistics: {
startDate: -1,
endDate: -1,
spend: -1,
total: -1,
correctRate: -1,
wrongWordNumber: -1,
}
},
sideIsOpen: false,
isDictation: true,
simpleWords: [
'a', 'an', 'of', 'and',
'i', 'my', 'you', 'your',
'me', 'am', 'is', 'do', 'are',
'what', 'who', 'where', 'how', 'no', 'yes',
'not', 'did', 'were', 'can', 'could', 'it',
'the', 'to'
],
theme: 'auto',
load: false
}
},
getters: {
skipWordNames: (state: State) => {
return state.skipWordDict.originWords.map(v => v.name.toLowerCase())
},
getters: {
skipWordNames: (state: State) => {
return state.skipWordDict.originWords.map(v => v.name.toLowerCase())
},
skipWordNamesWithSimpleWords: (state: State) => {
return state.skipWordDict.originWords.map(v => v.name.toLowerCase()).concat(state.simpleWords)
},
currentDict(state: State): Dict {
switch (state.current.dictType) {
case DictType.newDict:
return state.newWordDict
case DictType.skipDict:
return state.skipWordDict
case DictType.wrongDict:
return state.wrongWordDict
case DictType.publicDict:
case DictType.publicArticle:
case DictType.customDict:
return state.dict
}
},
wordIndex(state: State): number {
return this.currentDict.wordIndex
},
chapter(state: State): Word[] {
return this.currentDict.chapterWords[this.currentDict.chapterIndex] ?? []
},
word(state: State): Word {
return state.current.words[state.current.index] ?? {
trans: [],
name: '',
usphone: '',
ukphone: '',
}
},
dictTitle(state: State) {
let title = this.currentDict.name
if ([DictType.publicDict, DictType.customDict].includes(this.current.dictType)) {
title += `${this.currentDict.chapterIndex + 1}`
}
return title
skipWordNamesWithSimpleWords: (state: State) => {
return state.skipWordDict.originWords.map(v => v.name.toLowerCase()).concat(state.simpleWords)
},
isArticle(state: State): boolean {
return [DictType.publicArticle, DictType.customArticle].includes(state.current.dictType)
},
currentDict(state: State): Dict {
switch (state.current.dictType) {
case DictType.newDict:
return state.newWordDict
case DictType.skipDict:
return state.skipWordDict
case DictType.wrongDict:
return state.wrongWordDict
case DictType.publicDict:
case DictType.publicArticle:
case DictType.customDict:
return state.dict
}
},
wordIndex(state: State): number {
return this.currentDict.wordIndex
},
chapter(state: State): Word[] {
return this.currentDict.chapterWords[this.currentDict.chapterIndex] ?? []
},
word(state: State): Word {
return state.current.words[state.current.index] ?? {
trans: [],
name: '',
usphone: '',
ukphone: '',
}
},
dictTitle(state: State) {
let title = this.currentDict.name
if ([DictType.publicDict, DictType.customDict].includes(this.current.dictType)) {
title += `${this.currentDict.chapterIndex + 1}`
}
return title
}
},
actions: {
setState(obj: any) {
for (const [key, value] of Object.entries(obj)) {
this[key] = value
}
// console.log('this/', this)
},
setCurrentWord(words: Word[], restart: boolean = false, index: number = 0) {
this.current.words = cloneDeep(words)
if (restart) {
this.current.repeatNumber = 0
this.current.originWrongWords = []
this.current.statistics = {
startDate: Date.now(),
endDate: -1,
spend: -1,
wordNumber: words.length,
correctRate: -1,
wrongWordNumber: -1,
}
},
actions: {
setState(obj: any) {
for (const [key, value] of Object.entries(obj)) {
this[key] = value
}
// console.log('this/', this)
},
setCurrentWord(words: Word[], restart: boolean = false, index: number = 0) {
this.current.words = cloneDeep(words)
if (restart) {
this.current.repeatNumber = 0
this.current.originWrongWords = []
this.current.statistics = {
startDate: Date.now(),
endDate: -1,
spend: -1,
wordNumber: words.length,
correctRate: -1,
wrongWordNumber: -1,
}
} else {
this.current.repeatNumber++
if (!this.current.originWrongWords.length) {
this.current.originWrongWords = cloneDeep(this.current.wrongWords)
}
this.current.statistics.correctRate = -1
this.current.statistics.wrongWordNumber = -1
}
this.current.index = index
this.current.wrongWords = []
},
async init() {
// let configStr = localStorage.getItem(SaveKey)
// if (configStr) {
// let obj: Config = JSON.parse(configStr)
// this.setState(obj)
// }
if (this.current.dictType === DictType.publicDict) {
let r = await fetch(`/public/${this.dict.url}`)
r.json().then(v => {
this.dict.originWords = cloneDeep(v)
this.dict.words = cloneDeep(v)
this.dict.chapterWords = chunk(this.dict.words, this.dict.chapterWordNumber)
this.setCurrentWord(this.chapter, true)
this.load = true
})
}
if (this.current.dictType === DictType.publicArticle) {
let r = await fetch(`/public/${this.dict.url}`)
r.json().then(v => {
this.dict.originWords = cloneDeep(v)
this.dict.words = cloneDeep(v)
this.dict.chapterWords = chunk(this.dict.words, this.dict.chapterWordNumber)
this.setCurrentWord(this.chapter, true)
this.load = true
})
}
},
saveStatistics(statistics: Statistics) {
if (statistics.spend > 1000 * 10) {
this.currentDict.statistics.push(statistics)
}
},
async changeDict(dict: Dict, chapterIndex: number = dict.chapterIndex, chapterWordIndex: number = dict.chapterWordNumber) {
this.saveStatistics()
console.log('changeDict', cloneDeep(dict), chapterIndex, chapterWordIndex)
this.current.dictType = dict.type
if ([DictType.newDict,
DictType.skipDict,
DictType.wrongDict].includes(dict.type)) {
this[dict.type].chapterIndex = chapterIndex
this[dict.type].chapterWordIndex = chapterWordIndex
} else {
this.dict = cloneDeep(dict)
if (dict.originWords.length) {
let r = await fetch(`/public/${this.dict.url}`)
let v = await r.json()
this.dict.originWords = cloneDeep(v)
this.dict.words = cloneDeep(v)
this.dict.chapters = chunk(this.dict.words, this.dict.chapterWordNumber)
}
this.dict.chapterIndex = chapterIndex
this.dict.chapterWordIndex = chapterWordIndex
}
this.setCurrentWord(this.chapter, true, chapterWordIndex)
emitter.emit(EventKey.resetWord)
} else {
this.current.repeatNumber++
if (!this.current.originWrongWords.length) {
this.current.originWrongWords = cloneDeep(this.current.wrongWords)
}
this.current.statistics.correctRate = -1
this.current.statistics.wrongWordNumber = -1
}
this.current.index = index
this.current.wrongWords = []
},
async init() {
// let configStr = localStorage.getItem(SaveKey)
// if (configStr) {
// let obj: Config = JSON.parse(configStr)
// this.setState(obj)
// }
if (this.current.dictType === DictType.publicDict) {
let r = await fetch(`/public/${this.dict.url}`)
r.json().then(v => {
this.dict.originWords = cloneDeep(v)
this.dict.words = cloneDeep(v)
this.dict.chapterWords = chunk(this.dict.words, this.dict.chapterWordNumber)
this.setCurrentWord(this.chapter, true)
this.load = true
})
}
if (this.current.dictType === DictType.publicArticle) {
let r = await fetch(`/public/${this.dict.url}`)
r.json().then(v => {
this.dict.articles = cloneDeep(v)
this.load = true
})
}
},
saveStatistics(statistics: Statistics) {
if (statistics.spend > 1000 * 10) {
this.currentDict.statistics.push(statistics)
}
},
async changeDict(dict: Dict, chapterIndex: number = dict.chapterIndex, chapterWordIndex: number = dict.chapterWordNumber) {
this.saveStatistics()
console.log('changeDict', cloneDeep(dict), chapterIndex, chapterWordIndex)
this.current.dictType = dict.type
if ([DictType.newDict,
DictType.skipDict,
DictType.wrongDict].includes(dict.type)) {
this[dict.type].chapterIndex = chapterIndex
this[dict.type].chapterWordIndex = chapterWordIndex
} else {
this.dict = cloneDeep(dict)
if (dict.originWords.length) {
let r = await fetch(`/public/${this.dict.url}`)
let v = await r.json()
this.dict.originWords = cloneDeep(v)
this.dict.words = cloneDeep(v)
this.dict.chapters = chunk(this.dict.words, this.dict.chapterWordNumber)
}
this.dict.chapterIndex = chapterIndex
this.dict.chapterWordIndex = chapterWordIndex
}
this.setCurrentWord(this.chapter, true, chapterWordIndex)
emitter.emit(EventKey.resetWord)
}
},
})

13
src/stores/runtime.ts Normal file
View File

@@ -0,0 +1,13 @@
import {defineStore} from "pinia"
export interface RuntimeState {
disableEventListener: boolean
}
export const useRuntimeStore = defineStore('runtime', {
state: (): RuntimeState => {
return {
disableEventListener: false
}
},
})

View File

@@ -1,15 +1,15 @@
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 SaveKey = 'type-word-config'
@@ -23,183 +23,201 @@ export type LanguageCategoryType = 'en' | 'ja' | 'de' | 'code'
export type DictionaryResource = {
id: string
name: string
description: string
category: string
tags: string[]
url: string
length: number
language: LanguageType
languageCategory: LanguageCategoryType
//override default pronunciation when not undefined
defaultPronIndex?: number
id: string
name: string
description: string
category: string
tags: string[]
url: string
length: number
language: LanguageType
languageCategory: LanguageCategoryType
//override default pronunciation when not undefined
defaultPronIndex?: number
}
export type Dictionary = {
id: string
name: string
description: string
category: string
tags: string[]
url: string
length: number
language: LanguageType
languageCategory: LanguageCategoryType
// calculated in the store
chapterCount: number
//override default pronunciation when not undefined
defaultPronIndex?: number
id: string
name: string
description: string
category: string
tags: string[]
url: string
length: number
language: LanguageType
languageCategory: LanguageCategoryType
// calculated in the store
chapterCount: number
//override default pronunciation when not undefined
defaultPronIndex?: number
}
export type PronunciationConfig = {
name: string
pron: PronunciationType
name: string
pron: PronunciationType
}
export type LanguagePronunciationMapConfig = {
defaultPronIndex: number
pronunciation: PronunciationConfig[]
defaultPronIndex: number
pronunciation: PronunciationConfig[]
}
export type LanguagePronunciationMap = {
[key in LanguageType]: LanguagePronunciationMapConfig
[key in LanguageType]: LanguagePronunciationMapConfig
}
export type SoundResource = {
key: string
name: string
filename: string
key: string
name: string
filename: string
}
export interface DictJson {
description: string,
category: string,
tags: string[],
url: string,
length: number,
language: string,
languageCategory: string,
description: string,
category: string,
tags: string[],
url: string,
length: number,
language: string,
languageCategory: string,
}
export enum DictType {
newDict = 'newDict',
skipDict = 'skipDict',
wrongDict = 'wrongDict',
publicDict = 'publicDict',
customDict = 'customDict',
publicArticle = 'publicArticle',
customArticle = 'customArticle'
newDict = 'newDict',
skipDict = 'skipDict',
wrongDict = 'wrongDict',
publicDict = 'publicDict',
customDict = 'customDict',
publicArticle = 'publicArticle',
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 = 0,
network = 1
}
export interface Article {
title: string,
titleTranslate: string,
article: string,
customTranslate: string,
networkTranslate: string,
isTranslated: boolean,
newWords: Word[],
articleAllWords: string[],
sections: Sentence[][],
translateType: number
title: string,
titleTranslate: string,
article: string,
customTranslate: string,
networkTranslate: string,
isTranslated: boolean,
newWords: Word[],
articleAllWords: string[],
sections: Sentence[][],
translateType: TranslateType
}
export const DefaultArticle: Article = {
title: '',
titleTranslate: '',
article: '',
customTranslate: '',
networkTranslate: '',
isTranslated: false,
newWords: [],
articleAllWords: [],
sections: [],
translateType: TranslateType.network
}
export interface Dict {
name: string,
sort: Sort,
type: DictType,
originWords: Word[],//原始单词
words: Word[],
chapterWordNumber: number,//章节单词数量
chapterWords: Word[][],
articles: Article[],
chapterIndex: number,
chapterWordIndex: number,
statistics: Statistics[],
url: string,
name: string,
sort: Sort,
type: DictType,
originWords: Word[],//原始单词
words: Word[],
chapterWordNumber: number,//章节单词数量
chapterWords: Word[][],
articles: Article[],
chapterIndex: number,
chapterWordIndex: number,
statistics: Statistics[],
url: string,
}
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 interface State {
newWordDict: Dict,
skipWordDict: Dict,
wrongWordDict: Dict,
dict: Dict,
oldDicts: Dict[],
current: {
dictType: DictType,
words: Word[],
index: number,
wrongWords: Word[],
originWrongWords: Word[],
repeatNumber: number,
statistics: Statistics
},
simpleWords: string[],
sideIsOpen: boolean,
isDictation: boolean,
theme: string,
load: boolean
newWordDict: Dict,
skipWordDict: Dict,
wrongWordDict: Dict,
dict: Dict,
oldDicts: Dict[],
current: {
dictType: DictType,
words: Word[],
index: number,
wrongWords: Word[],
originWrongWords: Word[],
repeatNumber: number,
statistics: Statistics
},
simpleWords: string[],
sideIsOpen: boolean,
isDictation: boolean,
theme: string,
load: boolean
}
export const ShortKeyMap = {
Show: 'Escape',
Ignore: 'Tab',
Remove: '`',
Collect: 'Enter',
Show: 'Escape',
Ignore: 'Tab',
Remove: '`',
Collect: 'Enter',
}
export enum TranslateEngine {
Baidu = 0,
Baidu = 0,
}

View File

@@ -6,4 +6,6 @@ export const EventKey = {
openSide: 'openSide',
openStatModal: 'openStatModal',
closeOther: 'closeOther',
keydown: 'keydown',
keyup: 'keyup',
}