This commit is contained in:
zyronon
2023-09-23 01:53:11 +08:00
parent 6c09b695a5
commit 56133b58c9
8 changed files with 317 additions and 281 deletions

View File

@@ -2,7 +2,7 @@
import {onMounted, watch} from "vue";
import {useBaseStore} from "@/stores/base.ts";
import {SaveKey} from "@/types.ts"
import {SaveDictKey} from "@/types.ts"
import Practice from "@/components/Practice/Practice.vue"
import AddArticle from "@/components/Practice/AddArticle.vue";
import {useEventListener, useStartKeyboardEventListener} from "@/hooks/event.ts";
@@ -26,7 +26,8 @@ function followSystem() {
watch(store.$state, (n) => {
// console.log('state', JSON.stringify(n.current, null, 2))
localStorage.setItem(SaveKey, JSON.stringify(n))
// console.log('state', n)
localStorage.setItem(SaveDictKey, JSON.stringify(n))
})
useStartKeyboardEventListener()

View File

@@ -134,29 +134,29 @@ onMounted(() => {
})
function write() {
console.log('write')
// console.log('write')
settingStore.dictation = true
repeat()
}
//TODO 需要判断是否已忽略
function repeat() {
console.log('repeat')
// console.log('repeat')
getCurrentPractice()
emitter.emit(EventKey.resetWord)
}
//TODO 能否下一章
function next() {
console.log('next')
// console.log('next')
store.currentDict.chapterIndex++
repeat()
}
function saveArticle(article: Article) {
console.log('a', article)
console.log('saveArticle', article)
showEditArticle = false
articleData.article = article
store.currentDict.articles[store.currentDict.chapterIndex] = articleData.article = article
}
function test() {

View File

@@ -82,6 +82,10 @@ watch(() => props.article, () => {
calcTranslateLocation()
}, {immediate: true})
watch(() => settingStore.dictation, () => {
calcTranslateLocation()
})
onMounted(() => {
emitter.on(EventKey.resetWord, () => {
wrong = input = ''
@@ -167,14 +171,14 @@ function onKeyDown(e: KeyboardEvent) {
}
const nextSentence = () => {
tabIndex = 1
// wordData.words = practiceStore.wrongWords
wordData.words = [
{"name": "pharmacy", "trans": ["药房;配药学,药剂学;制药业;一批备用药品"], "usphone": "'fɑrməsi", "ukphone": "'fɑːməsɪ"},
// {"name": "foregone", "trans": ["过去的;先前的;预知的;预先决定的", "发生在…之前forego的过去分词"], "usphone": "'fɔrɡɔn", "ukphone": "fɔː'gɒn"}, {"name": "president", "trans": ["总统;董事长;校长;主席"], "usphone": "'prɛzɪdənt", "ukphone": "'prezɪd(ə)nt"}, {"name": "plastic", "trans": ["塑料的;(外科)造型的;可塑的", "塑料制品;整形;可塑体"], "usphone": "'plæstɪk", "ukphone": "'plæstɪk"}, {"name": "provisionally", "trans": ["临时地,暂时地"], "usphone": "", "ukphone": ""}, {"name": "incentive", "trans": ["动机;刺激", "激励的;刺激的"], "usphone": "ɪn'sɛntɪv", "ukphone": "ɪn'sentɪv"}, {"name": "calculate", "trans": ["计算;以为;作打算"], "usphone": "'kælkjulet", "ukphone": "'kælkjʊleɪt"}
]
// tabIndex = 1
// // wordData.words = practiceStore.wrongWords
// wordData.words = [
// {"name": "pharmacy", "trans": ["药房;配药学,药剂学;制药业;一批备用药品"], "usphone": "'fɑrməsi", "ukphone": "'fɑːməsɪ"},
// // {"name": "foregone", "trans": ["过去的;先前的;预知的;预先决定的", "发生在…之前forego的过去分词"], "usphone": "'fɔrɡɔn", "ukphone": "fɔː'gɒn"}, {"name": "president", "trans": ["总统;董事长;校长;主席"], "usphone": "'prɛzɪdənt", "ukphone": "'prezɪd(ə)nt"}, {"name": "plastic", "trans": ["塑料的;(外科)造型的;可塑的", "塑料制品;整形;可塑体"], "usphone": "'plæstɪk", "ukphone": "'plæstɪk"}, {"name": "provisionally", "trans": ["临时地,暂时地"], "usphone": "", "ukphone": ""}, {"name": "incentive", "trans": ["动机;刺激", "激励的;刺激的"], "usphone": "ɪn'sɛntɪv", "ukphone": "ɪn'sentɪv"}, {"name": "calculate", "trans": ["计算;以为;作打算"], "usphone": "'kælkjulet", "ukphone": "'kælkjʊleɪt"}
// ]
// return
return
isSpace = false
stringIndex = 0
wordIndex = 0
@@ -191,8 +195,8 @@ function onKeyDown(e: KeyboardEvent) {
sectionIndex++
if (!props.article.sections[sectionIndex]) {
console.log('打完了')
// if (practiceStore.wrongWordNumber === 0) {
if (false) {
if (practiceStore.wrongWordNumber === 0) {
// if (false) {
console.log('这章节完了')
let now = Date.now()
let stat: DisplayStatistics = {
@@ -208,8 +212,7 @@ function onKeyDown(e: KeyboardEvent) {
emitter.emit(EventKey.openStatModal, stat)
} else {
tabIndex = 1
// wordData.words = practiceStore.wrongWords
wordData.words = [{"name": "pharmacy", "trans": ["药房;配药学,药剂学;制药业;一批备用药品"], "usphone": "'fɑrməsi", "ukphone": "'fɑːməsɪ"}, {"name": "foregone", "trans": ["过去的;先前的;预知的;预先决定的", "发生在…之前forego的过去分词"], "usphone": "'fɔrɡɔn", "ukphone": "fɔː'gɒn"}, {"name": "president", "trans": ["总统;董事长;校长;主席"], "usphone": "'prɛzɪdənt", "ukphone": "'prezɪd(ə)nt"}, {"name": "plastic", "trans": ["塑料的;(外科)造型的;可塑的", "塑料制品;整形;可塑体"], "usphone": "'plæstɪk", "ukphone": "'plæstɪk"}, {"name": "provisionally", "trans": ["临时地,暂时地"], "usphone": "", "ukphone": ""}, {"name": "incentive", "trans": ["动机;刺激", "激励的;刺激的"], "usphone": "ɪn'sɛntɪv", "ukphone": "ɪn'sentɪv"}, {"name": "calculate", "trans": ["计算;以为;作打算"], "usphone": "'kælkjulet", "ukphone": "'kælkjʊleɪt"}]
wordData.words = practiceStore.wrongWords
}
}
} else {
@@ -408,7 +411,8 @@ function otherWord(word: ArticleWord, i: number, i2: number, i3: number) {
<div class="swiper-item">
<div class="article-wrapper">
<header>
<div class="title">A private conversation!</div>
<div class="title">{{ props.article.title }}</div>
<div class="titleTranslate">{{ props.article.titleTranslate }}</div>
</header>
<div class="article-content" ref="articleWrapperRef">
<article>
@@ -517,7 +521,12 @@ function otherWord(word: ArticleWord, i: number, i2: number, i3: number) {
font-size: 36rem;
font-weight: 500;
word-spacing: 3rem;
opacity: 0;
//opacity: 0;
}
.titleTranslate {
@extend .title;
font-size: 20rem;
}
}

View File

@@ -47,17 +47,6 @@ watch(() => settingStore.showToolbar, n => {
{{ store.dictTitle }} {{ practiceStore.repeatNumber ? ' 复习错词' : '' }}
</div>
<div class="options">
<Tooltip title="切换主题">
<IconWrapper>
<Icon icon="ep:moon" v-if="store.theme === 'dark'"
@click="toggle"/>
<Icon icon="tabler:sun" v-else @click="toggle"/>
</IconWrapper>
</Tooltip>
<VolumeSetting/>
<RepeatSetting/>
<Tooltip title="开关默写模式">
<IconWrapper>
@@ -72,6 +61,10 @@ watch(() => settingStore.showToolbar, n => {
<TranslateSetting/>
<VolumeSetting/>
<RepeatSetting/>
<Add/>
<Tooltip title="反馈">
@@ -86,6 +79,14 @@ watch(() => settingStore.showToolbar, n => {
</Tooltip>
<div class="my-button" @click="emitter.emit(EventKey.openStatModal)">ok</div>
<Tooltip title="切换主题">
<IconWrapper>
<Icon icon="ep:moon" v-if="store.theme === 'dark'"
@click="toggle"/>
<Icon icon="tabler:sun" v-else @click="toggle"/>
</IconWrapper>
</Tooltip>
<Tooltip title="单词本">
<IconWrapper>
<Icon icon="tdesign:menu-unfold" class="menu" @click="emitter.emit(EventKey.openSide)"/>

View File

@@ -55,15 +55,16 @@ export function splitEnArticle(text: string, lang: string = 'en', keyboardMap: K
//将缩写词的双引号替换回单引号
text = text.replaceAll(`"t`, `'t`)
text = text.replaceAll(`"s`, `'s`)
text = text.replaceAll(`"S`, `'S`)
text = text.replaceAll(`"m`, `'m`)
text = text.replaceAll(`"d`, `'d`)
text = text.replaceAll(`"ve`, `'ve`)
text = text.replaceAll(`"clock`, `'clock`)
// console.log('splitEnArticle', text)
console.log('splitEnArticle', text)
// console.log('splitEnArticle length', text.length)
text.split('').map((v, i, arr) => {
// if (i > 355) debugger
if (i > 2306) debugger
switch (v) {
case ' ':
if (word.name) {
@@ -149,8 +150,14 @@ export function splitEnArticle(text: string, lang: string = 'en', keyboardMap: K
break
case '\n':
//如果是空行,就删除
if (!sentence.words.length) {
section.pop()
sentence = section[section.length - 1]
}
//判断name有没有值有值说明最后一句没有结束符正常来说一句话以句号或逗号结尾
if (word.name.length) {
sentence.words.push(word)
}
if (i !== arr.length - 1) {
sections.push([])
@@ -165,6 +172,7 @@ export function splitEnArticle(text: string, lang: string = 'en', keyboardMap: K
}
break
default:
// if (v === '2')debugger
word.name += v
break
}
@@ -281,8 +289,14 @@ export function splitCNArticle(article: string, lang: string = 'cn', keyboardMap
}
break
case '\n':
//如果是空行,就删除
if (!sentence.words.length) {
section.pop()
sentence = section[section.length - 1]
}
//判断name有没有值有值说明最后一句没有结束符正常来说一句话以句号或逗号结尾
if (word.name.length) {
sentence.words.push(word)
}
if (i !== arr.length - 1) {
sections.push([])

View File

@@ -1,237 +1,253 @@
import {defineStore} from 'pinia'
import {Dict, DictType, Sort, State, Statistics, Word} from "../types.ts"
import {Dict, DictType, SaveDictKey, Sort, Statistics, Word} from "../types.ts"
import {chunk, cloneDeep} from "lodash-es";
import {emitter, EventKey} from "@/utils/eventBus.ts"
export interface State {
newWordDict: Dict,
skipWordDict: Dict,
wrongWordDict: Dict,
dict: Dict,
myDicts: Dict[],
current: {
dictType: DictType,
index: number,
repeatNumber: number,
},
simpleWords: string[],
sideIsOpen: boolean,
load: boolean
}
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',
},
myDicts: [
{
name: '新概念英语-2',
sort: Sort.normal,
type: DictType.publicArticle,
originWords: [],
articles: [],
words: [],
chapterWordNumber: 15,
chapterWords: [],
chapterIndex: 0,
chapterWordIndex: 0,
statistics: [],
url: '/articles/NCE_2.json',
}
],
current: {
dictType: DictType.publicArticle,
index: 0,
repeatNumber: 0,
},
sideIsOpen: false,
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'
],
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',
},
myDicts: [
{
name: '新概念英语-2',
sort: Sort.normal,
type: DictType.publicArticle,
originWords: [],
articles: [],
words: [],
chapterWordNumber: 15,
chapterWords: [],
chapterIndex: 0,
chapterWordIndex: 0,
statistics: [],
url: '/articles/NCE_2.json',
}
],
current: {
dictType: DictType.publicArticle,
index: 0,
repeatNumber: 0,
},
sideIsOpen: false,
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'
],
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)
},
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:
case DictType.customArticle:
return this.myDicts[this.current.index]
}
},
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
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:
case DictType.customArticle:
return this.myDicts[this.current.index]
}
},
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
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)
},
async init() {
let configStr = localStorage.getItem(SaveDictKey)
if (configStr) {
let obj: State = JSON.parse(configStr)
this.setState(obj)
}
if ([
DictType.newDict,
DictType.wrongDict,
DictType.skipDict,
].includes(this.current.dictType)) {
} else {
if ([
DictType.publicDict,
DictType.customDict,
].includes(this.current.dictType)) {
if (!this.currentDict.originWords.length) {
let r = await fetch(`/public/${this.dict.url}`)
r.json().then(v => {
this.currentDict.originWords = cloneDeep(v)
this.currentDict.words = cloneDeep(v)
this.currentDict.chapterWords = chunk(this.dict.words, this.dict.chapterWordNumber)
this.load = true
})
}
}
},
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(SaveKey)
// if (configStr) {
// let obj: Config = JSON.parse(configStr)
// this.setState(obj)
// }
if ([
DictType.newDict,
DictType.wrongDict,
DictType.skipDict,
].includes(this.current.dictType)) {
} else {
if ([
DictType.publicDict,
DictType.customDict,
].includes(this.current.dictType)) {
if (!this.currentDict.originWords.length) {
let r = await fetch(`/public/${this.dict.url}`)
r.json().then(v => {
this.currentDict.originWords = cloneDeep(v)
this.currentDict.words = cloneDeep(v)
this.currentDict.chapterWords = chunk(this.dict.words, this.dict.chapterWordNumber)
this.load = true
})
}
}
if ([
DictType.publicArticle,
DictType.customArticle,
].includes(this.current.dictType)) {
if (!this.currentDict.articles.length) {
let r = await fetch(`/public/${this.dict.url}`)
r.json().then(v => {
this.currentDict.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
}
emitter.emit(EventKey.resetWord)
if ([
DictType.publicArticle,
DictType.customArticle,
].includes(this.current.dictType)) {
if (!this.currentDict.articles.length) {
let r = await fetch(`/public/${this.dict.url}`)
r.json().then(v => {
this.currentDict.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
}
emitter.emit(EventKey.resetWord)
}
},
})

View File

@@ -12,7 +12,8 @@ export const DefaultWord: Word = {
trans: []
}
export const SaveKey = 'type-word-config'
export const SaveDictKey = 'typing-word-dict'
export const SaveConfigKey = 'typing-word-config'
export const PronunciationApi = 'https://dict.youdao.com/dictvoice?audio='
@@ -190,21 +191,6 @@ export enum Sort {
reverse = 2
}
export interface State {
newWordDict: Dict,
skipWordDict: Dict,
wrongWordDict: Dict,
dict: Dict,
myDicts: Dict[],
current: {
dictType: DictType,
index: number,
repeatNumber: number,
},
simpleWords: string[],
sideIsOpen: boolean,
load: boolean
}
export const ShortKeyMap = {
Show: 'Escape',