Modify the name field of word

This commit is contained in:
zyronon
2023-12-13 17:17:59 +08:00
parent 998c1196b5
commit 4179bfaf5b
22 changed files with 115759 additions and 886 deletions

View File

@@ -22,7 +22,7 @@ en2zh_CN.map(v => {
if (rIndex === -1) {
// let data = {
// id: allNew.length,
// word: v.name,
// word: v.word,
// phonetic0: v.usphone,
// phonetic1: v.ukphone,
// trans: []
@@ -46,7 +46,7 @@ en2zh_CN.map(v => {
// }
// allNew.push()
// minNew.push(v.name)
// minNew.push(v.word)
if (!v.name.includes(' ')){
notContain.push(v.name)

View File

@@ -28,7 +28,7 @@ onMounted(() => {
if (!w.trans.length) {
requestIdleCallback(() => {
if (list.length) {
let res = runtimeStore.translateWordList.find(a => a.name === w.name)
let res = runtimeStore.translateWordList.find(a => a.word === w.word)
if (res) w = Object.assign(w, res)
count++
if (count === list.length) {

View File

@@ -48,7 +48,7 @@ defineExpose({scrollToBottom, scrollToItem})
</template>
<template v-slot="{ item, index }">
<div class="item-title">
<span class="word" :class="!showWord && 'text-shadow'">{{ item.name }}</span>
<span class="word" :class="!showWord && 'text-shadow'">{{ item.word }}</span>
<span class="phonetic">{{ item.usphone }}</span>
<VolumeIcon class="volume" @click="playWordAudio(item.name)"></VolumeIcon>
</div>

View File

@@ -74,7 +74,7 @@ export function splitEnArticle(text: string): { sections: Sentence[][], newText:
let word3: ArticleWord = {
...DefaultArticleWord,
name: pre,
word: pre,
nextSpace: false,
isSymbol: true,
symbolPosition: ''
@@ -194,7 +194,7 @@ export function splitEnArticle(text: string): { sections: Sentence[][], newText:
})
//去除空格占位符
sentence.words = sentence.words.filter(v => v.name !== 'placeholder')
sentence.words = sentence.words.filter(v => v.word !== 'placeholder')
})
})
@@ -202,7 +202,7 @@ export function splitEnArticle(text: string): { sections: Sentence[][], newText:
sections.map((sectionItem, a) => {
sectionItem.map((sentenceItem, b) => {
sentenceItem.text = sentenceItem.words.reduce((previousValue: string, currentValue) => {
previousValue += currentValue.name + (currentValue.nextSpace ? ' ' : '')
previousValue += currentValue.word + (currentValue.nextSpace ? ' ' : '')
return previousValue
}, '')
})

View File

@@ -11,15 +11,15 @@ export function useWordOptions() {
const store = useBaseStore()
function isWordCollect(val: Word) {
return !!store.collect.originWords.find(v => v.name.toLowerCase() === val.name.toLowerCase())
return !!store.collect.originWords.find(v => v.word.toLowerCase() === val.word.toLowerCase())
}
function toggleWordCollect(val: Word) {
let rIndex = store.collect.originWords.findIndex(v => v.name.toLowerCase() === val.name.toLowerCase())
let rIndex = store.collect.originWords.findIndex(v => v.word.toLowerCase() === val.word.toLowerCase())
if (rIndex > -1) {
store.collect.originWords.splice(rIndex, 1)
} else {
let rIndex = store.simple.originWords.findIndex(v => v.name.toLowerCase() === val.name.toLowerCase())
let rIndex = store.simple.originWords.findIndex(v => v.word.toLowerCase() === val.word.toLowerCase())
if (rIndex > -1) {
store.simple.originWords.splice(rIndex, 1)
}
@@ -30,15 +30,15 @@ export function useWordOptions() {
}
function isWordSimple(val: Word) {
return !!store.simple.originWords.find(v => v.name.toLowerCase() === val.name.toLowerCase())
return !!store.simple.originWords.find(v => v.word.toLowerCase() === val.word.toLowerCase())
}
function toggleWordSimple(val: Word) {
let rIndex = store.simple.originWords.findIndex(v => v.name.toLowerCase() === val.name.toLowerCase())
let rIndex = store.simple.originWords.findIndex(v => v.word.toLowerCase() === val.word.toLowerCase())
if (rIndex > -1) {
store.simple.originWords.splice(rIndex, 1)
} else {
let rIndex = store.collect.originWords.findIndex(v => v.name.toLowerCase() === val.name.toLowerCase())
let rIndex = store.collect.originWords.findIndex(v => v.word.toLowerCase() === val.word.toLowerCase())
if (rIndex > -1) {
store.collect.originWords.splice(rIndex, 1)
}
@@ -49,7 +49,7 @@ export function useWordOptions() {
}
function delWrongWord(val: Word) {
let rIndex = store.wrong.originWords.findIndex(v => v.name.toLowerCase() === val.name.toLowerCase())
let rIndex = store.wrong.originWords.findIndex(v => v.word.toLowerCase() === val.word.toLowerCase())
if (rIndex > -1) {
store.wrong.originWords.splice(rIndex, 1)
}
@@ -57,7 +57,7 @@ export function useWordOptions() {
}
function delSimpleWord(val: Word) {
let rIndex = store.simple.originWords.findIndex(v => v.name.toLowerCase() === val.name.toLowerCase())
let rIndex = store.simple.originWords.findIndex(v => v.word.toLowerCase() === val.word.toLowerCase())
if (rIndex > -1) {
store.simple.originWords.splice(rIndex, 1)
}
@@ -117,7 +117,7 @@ export async function checkDictHasTranslate(dict: Dict) {
dict.words = cloneDeep(v)
dict.chapterWords = chunk(dict.words, dict.chapterWordNumber)
dict.chapterWords[dict.chapterIndex].map((w: Word) => {
let res = list.find(a => a.name === w.name)
let res = list.find(a => a.word === w.word)
if (res) w = Object.assign(w, res)
})
} else {

View File

@@ -34,7 +34,7 @@ let data = $ref({
const word: Word = $computed(() => {
return data.words[data.index] ?? {
trans: [],
name: '',
word: '',
usphone: '',
ukphone: '',
}
@@ -47,7 +47,7 @@ function getCurrentPractice() {
store.chapter.map((w: Word) => {
if (!w.trans.length) {
let res = runtimeStore.translateWordList.find(a => a.name === w.name)
let res = runtimeStore.translateWordList.find(a => a.word === w.word)
if (res) w = Object.assign(w, res)
}
})
@@ -118,7 +118,7 @@ function next(isTyping: boolean = true) {
isTyping && practiceStore.inputWordNumber++
console.log('这个词完了')
if ([DictType.word].includes(store.currentDict.type)
&& store.skipWordNames.includes(word.name.toLowerCase())) {
&& store.skipWordNames.includes(word.word.toLowerCase())) {
next()
}
}

View File

@@ -141,17 +141,17 @@ function next(isTyping: boolean = true) {
isTyping && practiceStore.inputWordNumber++
console.log('这个词完了')
if ([DictType.word].includes(store.currentDict.type)
&& store.skipWordNames.includes(word.name.toLowerCase())) {
&& store.skipWordNames.includes(word.word.toLowerCase())) {
next()
}
}
}
function wordWrong() {
if (!store.wrong.originWords.find((v: Word) => v.name.toLowerCase() === word.name.toLowerCase())) {
if (!store.wrong.originWords.find((v: Word) => v.word.toLowerCase() === word.word.toLowerCase())) {
store.wrong.originWords.push(word)
}
if (!data.wrongWords.find((v: Word) => v.name.toLowerCase() === word.name.toLowerCase())) {
if (!data.wrongWords.find((v: Word) => v.word.toLowerCase() === word.word.toLowerCase())) {
data.wrongWords.push(word)
practiceStore.wrongWordNumber++
}

View File

@@ -1,467 +0,0 @@
<script setup lang="ts">
import {onMounted, onUnmounted, watch} from "vue"
import {$computed, $ref} from "vue/macros"
import {useBaseStore} from "@/stores/base.ts"
import {DefaultDisplayStatistics, DictType, ShortcutKey, Sort, Word} from "@/types.ts";
import {emitter, EventKey} from "@/utils/eventBus.ts"
import {cloneDeep, reverse, shuffle} from "lodash-es"
import {usePracticeStore} from "@/stores/practice.ts"
import {useSettingStore} from "@/stores/setting.ts";
import {useOnKeyboardEventListener, useWindowClick} from "@/hooks/event.ts";
import Typing from "@/pages/mobile/practice/practice-word/Typing.vue";
import {useRuntimeStore} from "@/stores/runtime.ts";
import {useWordOptions} from "@/hooks/dict.ts";
import BaseIcon from "@/components/BaseIcon.vue";
import WordList from "@/components/list/WordList.vue";
import Empty from "@/components/Empty.vue";
import MiniDialog from "@/components/dialog/MiniDialog.vue";
import BaseButton from "@/components/BaseButton.vue";
import SlideHorizontal from "@/components/slide/SlideHorizontal.vue";
import SlideItem from "@/components/slide/SlideItem.vue";
import MobilePanel from "@/pages/mobile/components/MobilePanel.vue";
import router from "@/router.ts";
import {Icon} from "@iconify/vue";
interface IProps {
words: Word[],
index: number,
}
const props = withDefaults(defineProps<IProps>(), {
words: [],
index: -1
})
const emit = defineEmits<{
'update:words': [val: Word[]],
sort: [val: Word[]]
}>()
const typingRef: any = $ref()
const store = useBaseStore()
const runtimeStore = useRuntimeStore()
const practiceStore = usePracticeStore()
const settingStore = useSettingStore()
const {
isWordCollect,
toggleWordCollect,
isWordSimple,
toggleWordSimple
} = useWordOptions()
let data = $ref({
index: props.index,
words: props.words,
wrongWords: [],
})
let stat = cloneDeep(DefaultDisplayStatistics)
let showSortOption = $ref(false)
useWindowClick(() => showSortOption = false)
watch(() => props.words, () => {
data.words = props.words
data.index = props.index
data.wrongWords = []
practiceStore.wrongWords = []
practiceStore.repeatNumber = 0
practiceStore.startDate = Date.now()
practiceStore.correctRate = -1
practiceStore.inputWordNumber = 0
practiceStore.wrongWordNumber = 0
stat = cloneDeep(DefaultDisplayStatistics)
}, {immediate: true})
watch(data, () => {
practiceStore.total = data.words.length
practiceStore.index = data.index
})
const word = $computed(() => {
return data.words[data.index] ?? {
trans: [],
name: '',
usphone: '',
ukphone: '',
}
})
const prevWord: Word = $computed(() => {
return data.words?.[data.index - 1] ?? undefined
})
const nextWord: Word = $computed(() => {
return data.words?.[data.index + 1] ?? undefined
})
function next(isTyping: boolean = true) {
if (data.index === data.words.length - 1) {
//复制当前错词,因为第一遍错词是最多的,后续的练习都是从错词中练习
if (stat.total === -1) {
let now = Date.now()
stat = {
startDate: practiceStore.startDate,
endDate: now,
spend: now - practiceStore.startDate,
total: props.words.length,
correctRate: -1,
inputWordNumber: practiceStore.inputWordNumber,
wrongWordNumber: data.wrongWords.length,
wrongWords: data.wrongWords,
}
stat.correctRate = 100 - Math.trunc(((stat.wrongWordNumber) / (stat.total)) * 100)
}
if (data.wrongWords.length) {
console.log('当前背完了,但还有错词')
data.words = cloneDeep(data.wrongWords)
practiceStore.total = data.words.length
practiceStore.index = data.index = 0
practiceStore.inputWordNumber = 0
practiceStore.wrongWordNumber = 0
practiceStore.repeatNumber++
data.wrongWords = []
} else {
console.log('这章节完了')
isTyping && practiceStore.inputWordNumber++
let now = Date.now()
stat.endDate = now
stat.spend = now - stat.startDate
emitter.emit(EventKey.openStatModal, stat)
}
} else {
data.index++
isTyping && practiceStore.inputWordNumber++
console.log('这个词完了')
if ([DictType.word].includes(store.currentDict.type)
&& store.skipWordNames.includes(word.name.toLowerCase())) {
next()
}
}
}
function wordWrong() {
if (!store.wrong.originWords.find((v: Word) => v.name.toLowerCase() === word.name.toLowerCase())) {
store.wrong.originWords.push(word)
}
if (!data.wrongWords.find((v: Word) => v.name.toLowerCase() === word.name.toLowerCase())) {
data.wrongWords.push(word)
practiceStore.wrongWordNumber++
}
}
function onKeyUp(e: KeyboardEvent) {
typingRef.hideWord()
}
async function onKeyDown(e: KeyboardEvent) {
// console.log('e', e)
switch (e.key) {
case 'Backspace':
typingRef.del()
break
}
}
useOnKeyboardEventListener(onKeyDown, onKeyUp)
//TODO 略过忽略的单词上
function prev() {
if (data.index === 0) {
ElMessage.warning('已经是第一个了~')
} else {
data.index--
}
}
function skip(e: KeyboardEvent) {
next(false)
// e.preventDefault()
}
function show(e: KeyboardEvent) {
typingRef.showWord()
}
function collect(e: KeyboardEvent) {
toggleWordCollect(word)
}
function toggleWordSimpleWrapper() {
if (!isWordSimple(word)) {
toggleWordSimple(word)
//延迟一下,不知道为什么不延迟会导致当前条目不自动定位到列表中间
setTimeout(() => next(false))
} else {
toggleWordSimple(word)
}
}
function play() {
typingRef.play()
}
function sort(type: Sort) {
if (type === Sort.reverse) {
ElMessage.success('已翻转排序')
emit('sort', reverse(cloneDeep(data.words)))
}
if (type === Sort.random) {
ElMessage.success('已随机排序')
emit('sort', shuffle(data.words))
}
}
onMounted(() => {
emitter.on(ShortcutKey.ShowWord, show)
emitter.on(ShortcutKey.Previous, prev)
emitter.on(ShortcutKey.Next, skip)
emitter.on(ShortcutKey.ToggleCollect, collect)
emitter.on(ShortcutKey.ToggleSimple, toggleWordSimpleWrapper)
emitter.on(ShortcutKey.PlayWordPronunciation, play)
})
onUnmounted(() => {
emitter.off(ShortcutKey.ShowWord, show)
emitter.off(ShortcutKey.Previous, prev)
emitter.off(ShortcutKey.Next, skip)
emitter.off(ShortcutKey.ToggleCollect, collect)
emitter.off(ShortcutKey.ToggleSimple, toggleWordSimpleWrapper)
emitter.off(ShortcutKey.PlayWordPronunciation, play)
})
let index = $ref(0)
watch(() => index, n => {
settingStore.showPanel = index === 1
})
let inputRef = $ref<HTMLInputElement>()
function change(e) {
console.log('e', e)
e.key = e.data
emitter.emit(EventKey.onTyping, e)
inputRef.value = ''
}
function know() {
settingStore.translate = false
setTimeout(() => {
data.index++
}, 300)
}
function unknow() {
settingStore.translate = true
inputRef.focus()
}
let bodyHeight = $ref('100vh')
onMounted(() => {
bodyHeight = document.body.clientHeight + 'px'
})
</script>
<template>
<div class="practice-word" :style="{height:bodyHeight}">
<SlideHorizontal v-model:index="index">
<SlideItem>
<div class="practice-body" @click.stop="index = 0">
<div class="tool-bar">
<div class="left">
<Icon icon="octicon:arrow-left-24" width="22"
@click="router.back()"
/>
</div>
<div class="right">
<BaseIcon
v-if="!isWordCollect(word)"
class="collect"
@click="toggleWordCollect(word)"
icon="ph:star"/>
<BaseIcon
v-else
class="fill"
@click="toggleWordCollect(word)"
icon="ph:star-fill"/>
<BaseIcon
@click="index = 1"
icon="tdesign:menu-unfold"/>
</div>
</div>
<input ref="inputRef"
style="position:fixed;top:-200vh;"
@input="change"
type="text">
<Typing
style="width: 90%;"
v-loading="!store.load"
ref="typingRef"
:word="word"
@next="next"
/>
<div class="options">
<div class="wrapper">
<BaseButton @click="unknow">不认识</BaseButton>
<BaseButton @click="know">认识</BaseButton>
</div>
</div>
</div>
</SlideItem>
<SlideItem style="width: 80vw;">
<MobilePanel>
<template v-slot="{active}">
<div class="panel-page-item"
v-loading="!store.load"
>
<div class="list-header">
<div class="left">
<div class="title">
{{ store.chapterName }}
</div>
<BaseIcon title="切换词典"
@click="emitter.emit(EventKey.openDictModal,'list')"
icon="carbon:change-catalog"/>
<div style="position:relative;"
@click.stop="null">
<BaseIcon
title="改变顺序"
icon="icon-park-outline:sort-two"
@click="showSortOption = !showSortOption"
/>
<MiniDialog
v-model="showSortOption"
style="width: 130rem;"
>
<div class="mini-row-title">
列表循环设置
</div>
<div class="mini-row">
<BaseButton size="small" @click="sort(Sort.reverse)">翻转</BaseButton>
<BaseButton size="small" @click="sort(Sort.random)">随机</BaseButton>
</div>
</MiniDialog>
</div>
<BaseIcon icon="bi:arrow-right"
@click="next"
v-if="store.currentDict.chapterIndex < store.currentDict.chapterWords.length - 1"/>
</div>
<div class="right">
{{ data.words.length }}个单词
</div>
</div>
<WordList
v-if="data.words.length"
:is-active="active"
:static="false"
:show-word="!settingStore.dictation"
:show-translate="settingStore.translate"
:list="data.words"
:activeIndex="data.index"
@click="(val:any) => data.index = val.index"
>
<template v-slot:suffix="{item,index}">
<BaseIcon
v-if="!isWordCollect(item)"
class="collect"
@click="toggleWordCollect(item)"
title="收藏" icon="ph:star"/>
<BaseIcon
v-else
class="fill"
@click="toggleWordCollect(item)"
title="取消收藏" icon="ph:star-fill"/>
<BaseIcon
v-if="!isWordSimple(item)"
class="easy"
@click="toggleWordSimple(item)"
title="标记为简单词"
icon="material-symbols:check-circle-outline-rounded"/>
<BaseIcon
v-else
class="fill"
@click="toggleWordSimple(item)"
title="取消标记简单词"
icon="material-symbols:check-circle-rounded"/>
</template>
</WordList>
<Empty v-else/>
</div>
</template>
</MobilePanel>
</SlideItem>
</SlideHorizontal>
</div>
</template>
<style scoped lang="scss">
@import "@/assets/css/variable";
.practice-word {
position: fixed;
top: 0;
left: 0;
height: 100vh;
min-height: 100vh;
width: 100vw;
font-size: 14rem;
.practice-body {
width: 100%;
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 10rem;
padding: 10rem;
box-sizing: border-box;
.tool-bar {
width: 100%;
height: 50rem;
display: flex;
padding: 0 10rem;
align-items: center;
justify-content: space-between;
gap: 10rem;
}
:deep(.word) {
letter-spacing: 0;
font-size: 40rem !important;
}
.options {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
padding-bottom: 20rem;
.wrapper {
width: 80%;
display: flex;
flex-direction: column;
gap: 10rem;
}
.base-button {
width: 100%;
}
}
}
}
</style>

View File

@@ -27,7 +27,7 @@ function getCurrentPractice() {
store.chapter.map((w: Word) => {
if (!w.trans.length) {
let res = runtimeStore.translateWordList.find(a => a.name === w.name)
let res = runtimeStore.translateWordList.find(a => a.word === w.word)
if (res) w = Object.assign(w, res)
}
})

View File

@@ -159,7 +159,7 @@ function handleChangeCurrentChapter(val: {
v.checked = false
//TODO 可能会存在卡的问题
if (!v.trans.length && runtimeStore.translateWordList.length) {
let res = runtimeStore.translateWordList.find(a => a.name === v.name)
let res = runtimeStore.translateWordList.find(a => a.word === v.word)
if (res) v = Object.assign(v, res)
}
})
@@ -178,7 +178,7 @@ function checkRepeatWord(
let repeatWords = []
let noRepeatWords = []
words.map((v: any) => {
let rIndex = targetList.findIndex(s => s.name === v.name)
let rIndex = targetList.findIndex(s => s.word === v.word)
if (rIndex > -1) {
v.index = rIndex
repeatWords.push(v)
@@ -189,7 +189,7 @@ function checkRepeatWord(
concatNoRepeat(noRepeatWords)
if (repeatWords.length) {
MessageBox.confirm(
'单词"' + repeatWords.map(v => v.name).join(', ') + '" 已存在,继续将会覆盖原有单词,是否继续?',
'单词"' + repeatWords.map(v => v.word).join(', ') + '" 已存在,继续将会覆盖原有单词,是否继续?',
'检测到重复单词',
() => concatRepeat(repeatWords),
null,
@@ -206,7 +206,7 @@ function toResidueWordList() {
checkRepeatWord(list, residueWordList,
noRepeatWords => {
if (wordFormData.type === FormMode.Edit && wordFormData.where === 'chapter') {
if (noRepeatWords.find(v => v.name === wordForm.name)) {
if (noRepeatWords.find(v => v.word === wordForm.word)) {
wordFormData.where = 'residue'
}
}
@@ -220,7 +220,7 @@ function toResidueWordList() {
},
repeatWords => {
if (wordFormData.type === FormMode.Edit && wordFormData.where === 'chapter') {
if (repeatWords.find(v => v.name === wordForm.name)) {
if (repeatWords.find(v => v.word === wordForm.word)) {
wordFormData.where = 'residue'
}
}
@@ -244,7 +244,7 @@ function toChapterWordList() {
checkRepeatWord(list, chapterWordList,
noRepeatWords => {
if (wordFormData.type === FormMode.Edit && wordFormData.where !== 'chapter') {
if (noRepeatWords.find(v => v.name === wordForm.name)) {
if (noRepeatWords.find(v => v.word === wordForm.word)) {
wordFormData.where = 'chapter'
}
}
@@ -258,7 +258,7 @@ function toChapterWordList() {
},
repeatWords => {
if (wordFormData.type === FormMode.Edit && wordFormData.where !== 'chapter') {
if (repeatWords.find(v => v.name === wordForm.name)) {
if (repeatWords.find(v => v.word === wordForm.word)) {
wordFormData.where = 'chapter'
}
}
@@ -330,7 +330,7 @@ async function onSubmitWord() {
if (wordFormData.type === FormMode.Add) {
data.id = nanoid(6)
data.checked = false
let r = list.find(v => v.name === wordForm.name)
let r = list.find(v => v.word === wordForm.word)
if (r) return ElMessage.warning('已有相同名称单词!')
else list.push(data)
runtimeStore.editDict.originWords.push(data)
@@ -367,7 +367,7 @@ function delWord(val: {
runtimeStore.editDict.words.splice(rIndex2, 1)
}
if (wordFormData.type === FormMode.Edit && wordForm.name === val.item.name) {
if (wordFormData.type === FormMode.Edit && wordForm.word === val.item.word) {
closeWordForm()
}
syncEditDict2MyDictList()
@@ -377,7 +377,7 @@ function editWord(word: Word, index: number, where: string) {
wordFormData.type = FormMode.Edit
wordFormData.id = word.id
wordFormData.where = where
wordForm.name = word.name
wordForm.word = word.word
wordForm.ukphone = word.ukphone
wordForm.usphone = word.usphone
wordForm.trans = word.trans.join('\n')
@@ -472,7 +472,7 @@ function exportData(type: string) {
let wb = XLSX.utils.book_new()
let sheetData = list.map(v => {
return {
单词: v.name,
单词: v.word,
'音标①': v.usphone,
'音标②': v.ukphone,
'释义(一行一个释义)': v.trans.join('\n')
@@ -501,7 +501,7 @@ function importData(e: any) {
let word: Word = {
id: nanoid(6),
checked: false,
name: String(v['单词']),
word: String(v['单词']),
usphone: String(v['音标①'] ?? ''),
ukphone: String(v['音标②'] ?? ''),
trans: String(v['释义(一行一个释义)'] ?? '').split('\n')
@@ -563,7 +563,7 @@ defineExpose({getDictDetail, add: addWord, editDict})
<div class="left">
<div class="top">
<div class="title">
{{ runtimeStore.editDict.name }}
{{ runtimeStore.editDict.word }}
</div>
<template v-if="!isPinDict">
<BaseIcon icon="tabler:edit" @click='editDict'/>
@@ -695,8 +695,8 @@ defineExpose({getDictDetail, add: addWord, editDict})
:rules="wordRules"
:model="wordForm"
label-width="100rem">
<el-form-item label="单词" prop="name">
<el-input v-model="wordForm.name"/>
<el-form-item label="单词" prop="word">
<el-input v-model="wordForm.word"/>
</el-form-item>
<el-form-item label="翻译">
<el-input v-model="wordForm.trans"

View File

@@ -11,7 +11,6 @@ import {onMounted, reactive} from "vue";
import {cloneDeep} from "lodash-es";
import {Icon} from '@iconify/vue';
import {$computed, $ref} from "vue/macros";
import BaseIcon from "@/components/BaseIcon.vue";
import {useSettingStore} from "@/stores/setting.ts";
const store = useBaseStore()
@@ -85,7 +84,7 @@ const isEnd = $computed(() => {
<div class="result">
<div class="wrong-words-wrapper">
<div class="wrong-words">
<div class="word" v-for="i in currentStat.wrongWords">{{ i.name }}</div>
<div class="word" v-for="i in currentStat.wrongWords">{{ i.word }}</div>
<!-- <div class="word" v-for="i in 100">{{ i }}</div>-->
</div>
</div>

View File

@@ -84,8 +84,8 @@ watch(() => settingStore.dictation, () => {
function nextSentence() {
// 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"}
// {"word": "pharmacy", "trans": ["药房;配药学,药剂学;制药业;一批备用药品"], "usphone": "'fɑrməsi", "ukphone": "'fɑːməsɪ"},
// // {"word": "foregone", "trans": ["过去的;先前的;预知的;预先决定的", "发生在…之前forego的过去分词"], "usphone": "'fɔrɡɔn", "ukphone": "fɔː'gɒn"}, {"word": "president", "trans": ["总统;董事长;校长;主席"], "usphone": "'prɛzɪdənt", "ukphone": "'prezɪd(ə)nt"}, {"word": "plastic", "trans": ["塑料的;(外科)造型的;可塑的", "塑料制品;整形;可塑体"], "usphone": "'plæstɪk", "ukphone": "'plæstɪk"}, {"word": "provisionally", "trans": ["临时地,暂时地"], "usphone": "", "ukphone": ""}, {"word": "incentive", "trans": ["动机;刺激", "激励的;刺激的"], "usphone": "ɪn'sɛntɪv", "ukphone": "ɪn'sentɪv"}, {"word": "calculate", "trans": ["计算;以为;作打算"], "usphone": "'kælkjulet", "ukphone": "'kælkjʊleɪt"}
// ]
// return
@@ -97,7 +97,7 @@ function nextSentence() {
input = wrong = ''
//todo 计得把略过的单词加上统计里面去
// if (!store.skipWordNamesWithSimpleWords.includes(currentWord.name.toLowerCase()) && !currentWord.isSymbol) {
// if (!store.skipWordNamesWithSimpleWords.includes(currentWord.word.toLowerCase()) && !currentWord.isSymbol) {
// practiceStore.inputNumber++
// }
@@ -168,7 +168,7 @@ function onTyping(e: KeyboardEvent) {
} else {
let letter = e.key
let key = currentWord.name[stringIndex]
let key = currentWord.word[stringIndex]
// console.log('key', key,)
let isRight = false
@@ -183,7 +183,7 @@ function onTyping(e: KeyboardEvent) {
// console.log('匹配上了')
stringIndex++
//如果当前词没有index说明这个词完了下一个是空格
if (!currentWord.name[stringIndex]) {
if (!currentWord.word[stringIndex]) {
input = wrong = ''
if (!currentWord.isSymbol) {
playCorrect()
@@ -260,11 +260,11 @@ function del() {
}
function playWord(word: ArticleWord) {
playWordAudio(word.name)
playWordAudio(word.word)
}
function currentWordInput(word: ArticleWord, i: number, i2: number,) {
let str = word.name.slice(input.length + wrong.length, input.length + wrong.length + 1)
let str = word.word.slice(input.length + wrong.length, input.length + wrong.length + 1)
if (word.isSymbol) {
return str
}
@@ -279,7 +279,7 @@ function currentWordInput(word: ArticleWord, i: number, i2: number,) {
}
function currentWordEnd(word: ArticleWord, i: number, i2: number,) {
let str = word.name.slice(input.length + wrong.length + (wrong ? 0 : 1))
let str = word.word.slice(input.length + wrong.length + (wrong ? 0 : 1))
if (hoverIndex.sectionIndex === i && hoverIndex.sentenceIndex === i2) {
return str
}
@@ -291,7 +291,7 @@ function currentWordEnd(word: ArticleWord, i: number, i2: number,) {
}
function otherWord(word: ArticleWord, i: number, i2: number, i3: number) {
let str = word.name
let str = word.word
if (word.isSymbol) {
return str
}
@@ -393,7 +393,7 @@ defineExpose({showSentence, play, del,hideSentence,nextSentence})
?'wrote' :
(sectionIndex>=indexI &&sentenceIndex>=indexJ && wordIndex>indexW)
?'wrote':
(sectionIndex>=indexI &&sentenceIndex>=indexJ && wordIndex>=indexW && stringIndex>=word.name.length)
(sectionIndex>=indexI &&sentenceIndex>=indexJ && wordIndex>=indexW && stringIndex>=word.word.length)
?'wrote':
''),
(`${indexI}${indexJ}${indexW}` === currentIndex && !isSpace && wrong )?'word-wrong':'',

View File

@@ -177,7 +177,7 @@ function edit(val: Article = articleData.article) {
// wordData.words = [
// {
// ...cloneDeep(DefaultWord),
// name: 'test'
// word: 'test'
// }
// ]
// wordData.index = 0
@@ -187,12 +187,12 @@ function edit(val: Article = articleData.article) {
}
function wrong(word: Word) {
let lowerName = word.name.toLowerCase();
if (!store.wrong.originWords.find((v: Word) => v.name.toLowerCase() === lowerName)) {
let lowerName = word.word.toLowerCase();
if (!store.wrong.originWords.find((v: Word) => v.word.toLowerCase() === lowerName)) {
store.wrong.originWords.push(word)
}
if (!store.skipWordNamesWithSimpleWords.includes(lowerName)) {
if (!practiceStore.wrongWords.find((v) => v.name.toLowerCase() === lowerName)) {
if (!practiceStore.wrongWords.find((v) => v.word.toLowerCase() === lowerName)) {
practiceStore.wrongWords.push(word)
practiceStore.wrongWordNumber++
}
@@ -223,7 +223,7 @@ function over() {
}
function nextWord(word: ArticleWord) {
if (!store.skipWordNamesWithSimpleWords.includes(word.name.toLowerCase()) && !word.isSymbol) {
if (!store.skipWordNamesWithSimpleWords.includes(word.word.toLowerCase()) && !word.isSymbol) {
practiceStore.inputWordNumber++
}
}

View File

@@ -41,7 +41,7 @@ const volumeIconRef: any = $ref()
const volumeTranslateIconRef: any = $ref()
let displayWord = $computed(() => {
return props.word.name.slice(input.length + wrong.length)
return props.word.word.slice(input.length + wrong.length)
})
watch(() => props.word, () => {
@@ -85,11 +85,11 @@ async function onTyping(e: KeyboardEvent) {
let isTypingRight = false
let isWordRight = false
if (settingStore.ignoreCase) {
isTypingRight = letter.toLowerCase() === props.word.name[input.length].toLowerCase()
isWordRight = (input + letter).toLowerCase() === props.word.name.toLowerCase()
isTypingRight = letter.toLowerCase() === props.word.word[input.length].toLowerCase()
isWordRight = (input + letter).toLowerCase() === props.word.word.toLowerCase()
} else {
isTypingRight = letter === props.word.name[input.length]
isWordRight = (input + letter) === props.word.name
isTypingRight = letter === props.word.word[input.length]
isWordRight = (input + letter) === props.word.word
}
if (isTypingRight) {
input += letter
@@ -195,7 +195,7 @@ defineExpose({del, showWord, hideWord, play})
<Tooltip
:title="`发音(快捷键:${settingStore.shortcutKeyMap[ShortcutKey.PlayWordPronunciation]})`"
>
<VolumeIcon ref="volumeIconRef" :simple="true" :cb="() => playWordAudio(word.name)"/>
<VolumeIcon ref="volumeIconRef" :simple="true" :cb="() => playWordAudio(word.word)"/>
</Tooltip>
</div>
<div class="phonetic" v-if="settingStore.wordSoundType === 'us' && word.usphone">[{{ word.usphone}}]</div>

View File

@@ -83,7 +83,7 @@ watch(data, () => {
const word = $computed(() => {
return data.words[data.index] ?? {
trans: [],
name: '',
word: '',
usphone: '',
ukphone: '',
}
@@ -141,17 +141,17 @@ function next(isTyping: boolean = true) {
isTyping && practiceStore.inputWordNumber++
console.log('这个词完了')
if ([DictType.word].includes(store.currentDict.type)
&& store.skipWordNames.includes(word.name.toLowerCase())) {
&& store.skipWordNames.includes(word.word.toLowerCase())) {
next()
}
}
}
function wordWrong() {
if (!store.wrong.originWords.find((v: Word) => v.name.toLowerCase() === word.name.toLowerCase())) {
if (!store.wrong.originWords.find((v: Word) => v.word.toLowerCase() === word.word.toLowerCase())) {
store.wrong.originWords.push(word)
}
if (!data.wrongWords.find((v: Word) => v.name.toLowerCase() === word.name.toLowerCase())) {
if (!data.wrongWords.find((v: Word) => v.word.toLowerCase() === word.word.toLowerCase())) {
data.wrongWords.push(word)
practiceStore.wrongWordNumber++
}
@@ -249,7 +249,7 @@ onUnmounted(() => {
<Tooltip
:title="`上一个(快捷键:${settingStore.shortcutKeyMap[ShortcutKey.Previous]})`"
>
<div class="word">{{ prevWord.name }}</div>
<div class="word">{{ prevWord.word }}</div>
</Tooltip>
</div>
<div class="next"
@@ -258,7 +258,7 @@ onUnmounted(() => {
<Tooltip
:title="`下一个(快捷键:${settingStore.shortcutKeyMap[ShortcutKey.Next]})`"
>
<div class="word" :class="settingStore.dictation && 'text-shadow'">{{ nextWord.name }}</div>
<div class="word" :class="settingStore.dictation && 'text-shadow'">{{ nextWord.word }}</div>
</Tooltip>
<Icon class="arrow" icon="bi:arrow-right" width="22"/>
</div>

View File

@@ -27,7 +27,7 @@ function getCurrentPractice() {
store.chapter.map((w: Word) => {
if (!w.trans.length) {
let res = runtimeStore.translateWordList.find(a => a.name === w.name)
let res = runtimeStore.translateWordList.find(a => a.word === w.word)
if (res) w = Object.assign(w, res)
}
})

File diff suppressed because one or more lines are too long

View File

@@ -1,8 +1,7 @@
<script setup lang="ts">
import {splitEnArticle} from "@/hooks/article.ts";
import origin from './data.json'
import BaseButton from "@/components/BaseButton.vue";
import {useSettingStore} from "@/stores/setting.ts";
import {checkAndUpgradeSaveDict, shakeCommonDict} from "@/utils";
import localforage from "localforage";
import {SAVE_DICT_KEY} from "@/utils/const.ts";
@@ -28,17 +27,37 @@ let data = {
// "newWords": [],
// "id": "TdAAqD"
// }
splitEnArticle(data.text)
const settingStore = useSettingStore()
async function test(){
async function look() {
let configStr: string = await localforage.getItem(SAVE_DICT_KEY.key)
console.log(configStr)
let obj = JSON.parse(configStr)
console.log('local', obj)
}
function set() {
localforage.setItem(SAVE_DICT_KEY.key, JSON.stringify({val: shakeCommonDict(origin.val as any), version: 3}))
}
async function check() {
// let configStr: string = await localforage.getItem(SAVE_DICT_KEY.key)
// console.log('local', configStr)
// console.log('or',origin)
let configStr: string = await localforage.getItem(SAVE_DICT_KEY.key)
let data = checkAndUpgradeSaveDict(configStr)
console.log('data',data)
// this.setState(data)
}
</script>
<template>
<div class="page">
<BaseButton @click="test">test</BaseButton>
<div class="data">
<p>数据升级检测</p>
<BaseButton @click="look">获取保存到localforage的数据</BaseButton>
<BaseButton @click="set">设置data.json的数据到localforage</BaseButton>
<BaseButton @click="check">检测升级逻辑</BaseButton>
</div>
</div>
</template>
@@ -48,5 +67,12 @@ async function test(){
z-index: 1;
font-size: 14rem;
color: black;
.data{
display: flex;
flex-direction: column;
gap: 10rem;
width: 300rem;
}
}
</style>

View File

@@ -9,348 +9,303 @@ import {SAVE_DICT_KEY, SAVE_SETTING_KEY} from "@/utils/const.ts";
import {checkAndUpgradeSaveDict} from "@/utils";
export interface BaseState {
myDictList: Dict[],
collectDictIds: string[],
current: {
index: number,
practiceType: DictType,//练习类型目前仅词典为collect时判断是练单词还是文章使用
},
simpleWords: string[],
load: boolean
myDictList: Dict[],
collectDictIds: string[],
current: {
index: number,
practiceType: DictType,//练习类型目前仅词典为collect时判断是练单词还是文章使用
},
simpleWords: string[],
load: boolean
}
export const DefaultBaseState = (): BaseState => ({
myDictList: [
{
...cloneDeep(DefaultDict),
id: 'collect',
name: '收藏',
type: DictType.collect,
category: '自带字典',
tags: ['自带'],
isCustom: true,
},
{
...cloneDeep(DefaultDict),
id: 'skip',
name: '简单词',
type: DictType.simple,
category: '自带字典',
isCustom: true,
},
{
...cloneDeep(DefaultDict),
id: 'wrong',
name: '错词本',
type: DictType.wrong,
category: '自带字典',
isCustom: true,
},
{
...cloneDeep(DefaultDict),
id: 'cet4',
name: 'CET-4',
description: '大学英语四级词库',
category: '中国考试',
tags: ['大学英语'],
url: 'CET4_T.json',
length: 2607,
translateLanguage: 'common',
language: 'en',
type: DictType.word
},
// {
// ...cloneDeep(DefaultDict),
// id: 'article_nce2',
// name: "新概念英语2-课文",
// description: '新概念英语2-课文',
// category: '英语学习',
// tags: ['新概念英语'],
// url: 'NCE_2.json',
// translateLanguage: 'common',
// language: 'en',
// type: DictType.article,
// resourceId: 'article_nce2',
// length: 96
// },
// {
// ...cloneDeep(DefaultDict),
// id: 'nce-new-2',
// name: '新概念英语(新版)-2',
// description: '新概念英语新版第二册',
// category: '青少年英语',
// tags: ['新概念英语'],
// url: 'nce-new-2.json',
// translateLanguage: 'common',
// language: 'en',
// type: DictType.word,
// resourceId: 'nce-new-2',
// length: 862
// },
],
collectDictIds: [],
current: {
index: 3,
// dictType: DictType.article,
// index: 0,
practiceType: DictType.word,
myDictList: [
{
...cloneDeep(DefaultDict),
id: 'collect',
name: '收藏',
type: DictType.collect,
category: '自带字典',
tags: ['自带'],
isCustom: true,
},
simpleWords: [
'a', 'an',
'i', 'my', 'you', 'your', 'me', 'it',
'what', 'who', 'where', 'how', 'when', 'which',
'be', 'am', 'is', 'do', 'are', 'did', 'were', 'was', 'can', 'could', 'will', 'would',
'the', 'that', 'this', 'to', 'of', 'for', 'and', 'at', 'not', 'no', 'yes',
],
load: false
{
...cloneDeep(DefaultDict),
id: 'skip',
name: '简单词',
type: DictType.simple,
category: '自带字典',
isCustom: true,
},
{
...cloneDeep(DefaultDict),
id: 'wrong',
name: '错词本',
type: DictType.wrong,
category: '自带字典',
isCustom: true,
},
{
...cloneDeep(DefaultDict),
id: 'cet4',
name: 'CET-4',
description: '大学英语四级词库',
category: '中国考试',
tags: ['大学英语'],
url: 'CET4_T.json',
length: 2607,
translateLanguage: 'common',
language: 'en',
type: DictType.word
},
// {
// ...cloneDeep(DefaultDict),
// id: 'article_nce2',
// name: "新概念英语2-课文",
// description: '新概念英语2-课文',
// category: '英语学习',
// tags: ['新概念英语'],
// url: 'NCE_2.json',
// translateLanguage: 'common',
// language: 'en',
// type: DictType.article,
// resourceId: 'article_nce2',
// length: 96
// },
// {
// ...cloneDeep(DefaultDict),
// id: 'nce-new-2',
// name: '新概念英语(新版)-2',
// description: '新概念英语新版第二册',
// category: '青少年英语',
// tags: ['新概念英语'],
// url: 'nce-new-2.json',
// translateLanguage: 'common',
// language: 'en',
// type: DictType.word,
// resourceId: 'nce-new-2',
// length: 862
// },
],
collectDictIds: [],
current: {
index: 3,
// dictType: DictType.article,
// index: 0,
practiceType: DictType.word,
},
simpleWords: [
'a', 'an',
'i', 'my', 'you', 'your', 'me', 'it',
'what', 'who', 'where', 'how', 'when', 'which',
'be', 'am', 'is', 'do', 'are', 'did', 'were', 'was', 'can', 'could', 'will', 'would',
'the', 'that', 'this', 'to', 'of', 'for', 'and', 'at', 'not', 'no', 'yes',
],
load: false
})
// words: [
// {
// "name": "cancelcancelcancelcancelcancelcancelcancelcancel",
// "trans": ['取消取消取消取消取消取消取消取消取消取消取消取消取消取消取消取消'],
// "usphone": "",
// "ukphone": ""
// },
// {
// "name": "prepare",
// "trans": [],
// "usphone": "",
// "ukphone": ""
// },
// {
// "name": "half",
// "trans": [],
// "usphone": "",
// "ukphone": ""
// },
// {
// "name": "spacious",
// "trans": [],
// "usphone": "",
// "ukphone": ""
// },
// {
// "name": "analyse",
// "trans": [],
// "usphone": "",
// "ukphone": ""
// },
// {
// "name": "costing",
// "trans": [],
// "usphone": "",
// "ukphone": ""
// },
// {
// "name": "nowadays",
// "trans": [],
// "usphone": "",
// "ukphone": ""
// },
// ],
export const useBaseStore = defineStore('base', {
state: (): BaseState => {
return DefaultBaseState()
state: (): BaseState => {
return DefaultBaseState()
},
getters: {
collect(): Dict {
return this.myDictList[0]
},
getters: {
collect(): Dict {
return this.myDictList[0]
},
simple(): Dict {
return this.myDictList[1]
},
wrong(): Dict {
return this.myDictList[2]
},
skipWordNames() {
return this.simple.originWords.map(v => v.name.toLowerCase())
},
skipWordNamesWithSimpleWords() {
return this.simple.originWords.map(v => v.name.toLowerCase()).concat(this.simpleWords)
},
isArticle(state: BaseState): boolean {
//如果是收藏时,特殊判断
if (this.currentDict.type === DictType.collect) {
return state.current.practiceType === DictType.article
}
return [
DictType.article,
].includes(this.currentDict.type)
},
currentDict(): Dict {
return this.myDictList[this.current.index]
},
chapter(state: BaseState): Word[] {
return this.currentDict.chapterWords[this.currentDict.chapterIndex] ?? []
},
chapterName(state: BaseState) {
let title = ''
switch (this.currentDict.type) {
case DictType.collect:
if (state.current.practiceType === DictType.article) {
return `${this.currentDict.chapterIndex + 1}`
}
case DictType.wrong:
case DictType.simple:
return this.currentDict.name
case DictType.word:
return `${this.currentDict.chapterIndex + 1}`
}
return title
simple(): Dict {
return this.myDictList[1]
},
wrong(): Dict {
return this.myDictList[2]
},
skipWordNames() {
return this.simple.originWords.map(v => v.name.toLowerCase())
},
skipWordNamesWithSimpleWords() {
return this.simple.originWords.map(v => v.name.toLowerCase()).concat(this.simpleWords)
},
isArticle(state: BaseState): boolean {
//如果是收藏时,特殊判断
if (this.currentDict.type === DictType.collect) {
return state.current.practiceType === DictType.article
}
return [
DictType.article,
].includes(this.currentDict.type)
},
currentDict(): Dict {
return this.myDictList[this.current.index]
},
chapter(state: BaseState): Word[] {
return this.currentDict.chapterWords[this.currentDict.chapterIndex] ?? []
},
chapterName(state: BaseState) {
let title = ''
switch (this.currentDict.type) {
case DictType.collect:
if (state.current.practiceType === DictType.article) {
return `${this.currentDict.chapterIndex + 1}`
}
case DictType.wrong:
case DictType.simple:
return this.currentDict.name
case DictType.word:
return `${this.currentDict.chapterIndex + 1}`
}
return title
}
},
actions: {
setState(obj: any) {
//这样不会丢失watch的值的引用
merge(this, obj)
},
async init(outData?: any) {
return new Promise(async resolve => {
try {
if (outData) {
this.setState(outData)
} else {
let configStr: string = await localforage.getItem(SAVE_DICT_KEY.key)
let data = checkAndUpgradeSaveDict(configStr)
this.setState(data)
}
localforage.setItem(SAVE_DICT_KEY.key, JSON.stringify({val: this.$state, version: SAVE_DICT_KEY.version}))
} catch (e) {
console.error('读取本地dict数据失败', e)
}
},
actions: {
setState(obj: any) {
//这样不会丢失watch的值的引用
merge(this, obj)
},
async init(outData?: any) {
return new Promise(async resolve => {
try {
if (outData) {
this.setState(outData)
} else {
let configStr: string = await localforage.getItem(SAVE_DICT_KEY.key)
let data = checkAndUpgradeSaveDict(configStr)
this.setState(data)
}
localforage.setItem(SAVE_DICT_KEY.key, JSON.stringify({val: this.$state, version: SAVE_DICT_KEY.version}))
} catch (e) {
console.error('读取本地dict数据失败', e)
}
const runtimeStore = useRuntimeStore()
const runtimeStore = useRuntimeStore()
if (location.href.includes('?mode=article')) {
console.log('文章')
let dict = {
...cloneDeep(DefaultDict),
id: 'article_nce2',
name: "新概念英语2-课文",
description: '新概念英语2-课文',
category: '英语学习',
tags: ['新概念英语'],
url: 'NCE_2.json',
translateLanguage: 'common',
language: 'en',
type: DictType.article,
resourceId: 'article_nce2',
length: 96
}
let rIndex = this.myDictList.findIndex((v: Dict) => v.id === dict.id)
if (rIndex > -1) {
this.myDictList[rIndex] = dict
this.current.index = rIndex
} else {
this.myDictList.push(cloneDeep(dict))
this.current.index = this.myDictList.length - 1
}
}
if (this.current.index < 3) {
store.currentDict.words = cloneDeep(n)
store.currentDict.chapterWords = [store.currentDict.words]
} else {
//自定义的词典文章只删除了sections单词并未做删除所以这里不需要处理
if (this.currentDict.isCustom) {
} else {
//处理非自定义的情况。
let dictResourceUrl = `./dicts/${this.currentDict.language}/${this.currentDict.type}/${this.currentDict.translateLanguage}/${this.currentDict.url}`;
if ([DictType.word].includes(this.currentDict.type)) {
if (!this.currentDict.originWords.length) {
let r = await fetch(dictResourceUrl)
let v = await r.json()
v.map(s => {
s.id = nanoid(6)
})
if (this.currentDict.translateLanguage === 'common') {
let r2 = await fetch('./translate/en2zh_CN-min.json')
// fetch('http://sc.ttentau.top/en2zh_CN-min.json').then(r2 => {
let list: Word[] = await r2.json()
if (list && list.length) {
runtimeStore.translateWordList = list
}
}
this.currentDict.originWords = cloneDeep(v)
this.currentDict.words = cloneDeep(v)
this.currentDict.chapterWords = chunk(this.currentDict.words, this.currentDict.chapterWordNumber)
}
}
if ([DictType.article].includes(this.currentDict.type)) {
if (!this.currentDict.articles.length) {
let r = await fetch(dictResourceUrl)
let s: any[] = await r.json()
this.currentDict.articles = cloneDeep(s.map(v => {
v.id = nanoid(6)
return v
}))
}
}
}
}
//TODO 先这样,默认加载
if (!runtimeStore.translateWordList.length) {
setTimeout(async () => {
let r2 = await fetch('./translate/en2zh_CN-min.json')
// fetch('http://sc.ttentau.top/en2zh_CN-min.json').then(r2 => {
let list: Word[] = await r2.json()
if (list && list.length) {
runtimeStore.translateWordList = list
}
})
}
emitter.emit(EventKey.changeDict)
resolve(true)
})
},
saveStatistics(statistics: DisplayStatistics) {
if (statistics.spend > 1000 * 10) {
delete statistics.wrongWords
this.currentDict.statistics.push(statistics)
}
},
async changeDict(dict: Dict, practiceType?: DictType, chapterIndex?: number, wordIndex?: number) {
//TODO 保存统计
// this.saveStatistics()
console.log('changeDict', cloneDeep(dict), chapterIndex, wordIndex)
if (chapterIndex === undefined) chapterIndex = dict.chapterIndex
if (wordIndex === undefined) wordIndex = dict.wordIndex
if (practiceType === undefined) this.current.practiceType = practiceType
if ([DictType.collect,
DictType.simple,
DictType.wrong].includes(dict.type)) {
dict.chapterIndex = 0
dict.wordIndex = wordIndex
dict.chapterWordNumber = dict.words.length
dict.chapterWords = [dict.words]
} else {
if (dict.type === DictType.article) {
if (chapterIndex > dict.articles.length) {
dict.chapterIndex = 0
dict.wordIndex = 0
}
} else {
if (chapterIndex > dict.chapterWords.length) {
dict.chapterIndex = 0
dict.wordIndex = 0
}
}
}
// await checkDictHasTranslate(dict)
let rIndex = this.myDictList.findIndex((v: Dict) => v.id === dict.id)
if (rIndex > -1) {
this.myDictList[rIndex] = dict
this.current.index = rIndex
} else {
this.myDictList.push(cloneDeep(dict))
this.current.index = this.myDictList.length - 1
}
emitter.emit(EventKey.changeDict)
if (location.href.includes('?mode=article')) {
console.log('文章')
//TODO
let dict = {
...cloneDeep(DefaultDict),
id: 'article_nce2',
name: "新概念英语2-课文",
description: '新概念英语2-课文',
category: '英语学习',
tags: ['新概念英语'],
url: 'NCE_2.json',
translateLanguage: 'common',
language: 'en',
type: DictType.article,
resourceId: 'article_nce2',
length: 96
}
let rIndex = this.myDictList.findIndex((v: Dict) => v.id === dict.id)
if (rIndex > -1) {
this.myDictList[rIndex] = dict
this.current.index = rIndex
} else {
this.myDictList.push(cloneDeep(dict))
this.current.index = this.myDictList.length - 1
}
}
if (this.current.index < 3) {
//前三本词典的isCustom为true。数据全都保存了不需要处理了
} else {
//自定义的词典文章只删除了sections单词并未做删除所以这里不需要处理
if (this.currentDict.isCustom) {
} else {
//处理非自定义的情况。
let dictResourceUrl = `./dicts/${this.currentDict.language}/${this.currentDict.type}/${this.currentDict.translateLanguage}/${this.currentDict.url}`;
if ([DictType.word].includes(this.currentDict.type)) {
if (!this.currentDict.originWords.length) {
let r = await fetch(dictResourceUrl)
let v = await r.json()
v.map(s => {
s.id = nanoid(6)
})
if (this.currentDict.translateLanguage === 'common') {
let r2 = await fetch('./translate/en2zh_CN-min.json')
// fetch('http://sc.ttentau.top/en2zh_CN-min.json').then(r2 => {
let list: Word[] = await r2.json()
if (list && list.length) {
runtimeStore.translateWordList = list
}
}
this.currentDict.originWords = cloneDeep(v)
this.currentDict.words = cloneDeep(v)
this.currentDict.chapterWords = chunk(this.currentDict.words, this.currentDict.chapterWordNumber)
}
}
if ([DictType.article].includes(this.currentDict.type)) {
if (!this.currentDict.articles.length) {
let r = await fetch(dictResourceUrl)
let s: any[] = await r.json()
this.currentDict.articles = cloneDeep(s.map(v => {
v.id = nanoid(6)
return v
}))
}
}
}
}
//TODO 先这样,默认加载
if (!runtimeStore.translateWordList.length) {
setTimeout(async () => {
let r2 = await fetch('./translate/en2zh_CN-min.json')
// fetch('http://sc.ttentau.top/en2zh_CN-min.json').then(r2 => {
let list: Word[] = await r2.json()
if (list && list.length) {
runtimeStore.translateWordList = list
}
})
}
emitter.emit(EventKey.changeDict)
resolve(true)
})
},
saveStatistics(statistics: DisplayStatistics) {
if (statistics.spend > 1000 * 10) {
delete statistics.wrongWords
this.currentDict.statistics.push(statistics)
}
},
async changeDict(dict: Dict, practiceType?: DictType, chapterIndex?: number, wordIndex?: number) {
//TODO 保存统计
// this.saveStatistics()
console.log('changeDict', cloneDeep(dict), chapterIndex, wordIndex)
if (chapterIndex === undefined) chapterIndex = dict.chapterIndex
if (wordIndex === undefined) wordIndex = dict.wordIndex
if (practiceType === undefined) this.current.practiceType = practiceType
if ([DictType.collect,
DictType.simple,
DictType.wrong].includes(dict.type)) {
dict.chapterIndex = 0
dict.wordIndex = wordIndex
dict.chapterWordNumber = dict.words.length
dict.chapterWords = [dict.words]
} else {
if (dict.type === DictType.article) {
if (chapterIndex > dict.articles.length) {
dict.chapterIndex = 0
dict.wordIndex = 0
}
} else {
if (chapterIndex > dict.chapterWords.length) {
dict.chapterIndex = 0
dict.wordIndex = 0
}
}
}
// await checkDictHasTranslate(dict)
let rIndex = this.myDictList.findIndex((v: Dict) => v.id === dict.id)
if (rIndex > -1) {
this.myDictList[rIndex] = dict
this.current.index = rIndex
} else {
this.myDictList.push(cloneDeep(dict))
this.current.index = this.myDictList.length - 1
}
emitter.emit(EventKey.changeDict)
}
},
})

View File

@@ -5,7 +5,7 @@ import myFlag from "@/assets/img/flags/my.png";
import {DefaultChapterWordNumber} from "@/stores/setting.ts";
export type Word = {
"name": string,
"word": string,
"usphone": string,
"ukphone": string,
"trans": string[]
@@ -14,7 +14,7 @@ export type Word = {
}
export const DefaultWord: Word = {
name: '',
word: '',
usphone: '',
ukphone: '',
trans: []
@@ -48,7 +48,7 @@ export enum DictType {
}
export const DefaultArticleWord: ArticleWord = {
name: '',
word: '',
usphone: '',
ukphone: '',
trans: [],
@@ -194,8 +194,8 @@ export enum TranslateEngine {
export const languageCategoryOptions = [
{id: 'article', name: '文章', flag: bookFlag},
{id: 'en', name: '英语', flag: enFlag},
// {id: 'ja', name: '日语', flag: jpFlag},
// {id: 'de', name: '德语', flag: deFlag},
// {id: 'ja', word: '日语', flag: jpFlag},
// {id: 'de', word: '德语', flag: deFlag},
{id: 'code', name: 'Code', flag: codeFlag},
{id: 'my', name: '我的', flag: myFlag},
]

View File

@@ -10,7 +10,7 @@ export const APP_NAME = 'Typing Word'
export const SAVE_DICT_KEY = {
key: 'typing-word-dict',
version: 3
version: 4
}
export const SAVE_SETTING_KEY = {
key: 'typing-word-setting',

View File

@@ -1,4 +1,3 @@
import localforage from "localforage";
import {SAVE_DICT_KEY, SAVE_SETTING_KEY} from "@/utils/const.ts";
import {BaseState, DefaultBaseState} from "@/stores/base.ts";
import {DefaultSettingState, SettingState} from "@/stores/setting.ts";
@@ -13,7 +12,7 @@ export function no() {
ElMessage.warning('未现实')
}
export function checkAndUpgradeSaveDict(val: string) {
export function checkAndUpgradeSaveDict(val: any) {
// console.log(configStr)
// console.log('s', new Blob([val]).size)
// val = ''
@@ -43,6 +42,42 @@ export function checkAndUpgradeSaveDict(val: string) {
}
return defaultBaseState
} else {
if (version <= 3) {
// if (false) {
let temp = (list: any[]): any[] => {
return list.map(a => {
return {
word: a.name,
trans: a.trans.map(b => {
return {
cn: b,
}
}),
phonetic0: a.usphone,
phonetic1: a.ukphone,
}
})
}
state.myDictList.map(v => {
if ([DictType.collect, DictType.simple, DictType.wrong].includes(v.type)) {
v.originWords = temp(v.originWords)
if (v.words) v.words = temp(v.words)
v.chapterWords.map((s, i) => {
v.chapterWords[i] = temp(s)
})
} else {
if (v.isCustom) {
if (v.type === DictType.word) {
v.originWords = temp(v.originWords)
if (v.words) v.words = temp(v.words)
v.chapterWords.map((s, i) => {
v.chapterWords[i] = temp(s)
})
}
}
}
})
}
//防止人为删除数据,导致数据不完整报错
for (const [key, value] of Object.entries(defaultBaseState)) {
if (state[key] !== undefined) defaultBaseState[key] = state[key]
@@ -56,7 +91,7 @@ export function checkAndUpgradeSaveDict(val: string) {
return {}
}
export function checkAndUpgradeSaveSetting(val: string) {
export function checkAndUpgradeSaveSetting(val: any) {
// console.log(configStr)
// console.log('s', new Blob([val]).size)
// val = ''
@@ -124,6 +159,6 @@ export function shakeCommonDict(n: BaseState): BaseState {
return data
}
export function isMobile():boolean {
export function isMobile(): boolean {
return /Mobi|Android|iPhone/i.test(navigator.userAgent)
}