diff --git a/package.json b/package.json index 2f9b4bd7..a6b1d0b6 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,6 @@ "dependencies": { "@opentranslate/baidu": "^1.4.2", "@opentranslate/translator": "^1.4.2", - "@types/uuid": "^9.0.4", "axios": "^1.5.0", "compromise": "^14.10.0", "copy-to-clipboard": "^3.3.3", @@ -29,6 +28,7 @@ "localforage": "^1.10.0", "lodash-es": "^4.17.21", "mitt": "^3.0.1", + "nanoid": "^5.0.3", "pinia": "^2.1.6", "sentence-splitter": "^4.2.1", "tesseract.js": "^4.1.1", @@ -44,6 +44,7 @@ "@iconify/vue": "^4.1.1", "@types/file-saver": "^2.0.5", "@types/lodash-es": "^4.17.9", + "@types/uuid": "^9.0.4", "@vitejs/plugin-vue": "^4.2.3", "@vitejs/plugin-vue-jsx": "^3.0.1", "@vue/compiler-sfc": "^3.3.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 44ae7ac5..bf85b5e6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,9 +11,6 @@ dependencies: '@opentranslate/translator': specifier: ^1.4.2 version: 1.4.2 - '@types/uuid': - specifier: ^9.0.4 - version: 9.0.4 axios: specifier: ^1.5.0 version: 1.5.1 @@ -44,6 +41,9 @@ dependencies: mitt: specifier: ^3.0.1 version: 3.0.1 + nanoid: + specifier: ^5.0.3 + version: 5.0.3 pinia: specifier: ^2.1.6 version: 2.1.6(typescript@5.2.2)(vue@3.3.4) @@ -85,6 +85,9 @@ devDependencies: '@types/lodash-es': specifier: ^4.17.9 version: 4.17.9 + '@types/uuid': + specifier: ^9.0.4 + version: 9.0.4 '@vitejs/plugin-vue': specifier: ^4.2.3 version: 4.3.4(vite@4.4.9)(vue@3.3.4) @@ -939,7 +942,7 @@ packages: /@types/uuid@9.0.4: resolution: {integrity: sha512-zAuJWQflfx6dYJM62vna+Sn5aeSWhh3OB+wfUEACNcqUSc0AGc5JKl+ycL1vrH7frGTXhJchYjE1Hak8L819dA==} - dev: false + dev: true /@types/web-bluetooth@0.0.16: resolution: {integrity: sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==} @@ -3586,6 +3589,12 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + /nanoid@5.0.3: + resolution: {integrity: sha512-I7X2b22cxA4LIHXPSqbBCEQSL+1wv8TuoefejsX4HFWyC6jc5JG7CEaxOltiKjc1M+YCS2YkrZZcj4+dytw9GA==} + engines: {node: ^18 || >=20} + hasBin: true + dev: false + /nanomatch@1.2.13: resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} engines: {node: '>=0.10.0'} diff --git a/src/assets/css/style.scss b/src/assets/css/style.scss index ea0db548..a79011f8 100644 --- a/src/assets/css/style.scss +++ b/src/assets/css/style.scss @@ -380,7 +380,7 @@ footer { .common-title { height: 40rem; - font-size: 20rem; + font-size: 18rem; color: var(--color-font-1); display: flex; justify-content: center; diff --git a/src/pages/dict/DictManage.vue b/src/pages/dict/DictManage.vue index 598287dd..4bfa0c0d 100644 --- a/src/pages/dict/DictManage.vue +++ b/src/pages/dict/DictManage.vue @@ -3,7 +3,7 @@ import {dictionaryResources} from '@/assets/dictionary.ts' import {useBaseStore} from "@/stores/base.ts" import {onMounted, reactive, watch} from "vue" import {DefaultDict, Dict, DictResource, DictType, languageCategoryOptions, Sort, Word} from "@/types.ts" -import {chunk, cloneDeep, groupBy, reverse, shuffle} from "lodash-es"; +import {assign, chunk, cloneDeep, groupBy, merge, reverse, shuffle} from "lodash-es"; import {$computed, $ref} from "vue/macros"; import {Icon} from '@iconify/vue'; import DictGroup from "@/components/toolbar/DictGroup.vue"; @@ -25,6 +25,8 @@ import {usePlayWordAudio} from "@/hooks/sound.ts"; import BaseButton from "@/components/BaseButton.vue"; import VirtualWordList from "@/components/list/VirtualWordList.vue"; import Dialog from "@/components/dialog/Dialog.vue"; +import {nanoid} from "nanoid"; +import {no} from "@/utils"; const store = useBaseStore() const settingStore = useSettingStore() @@ -35,7 +37,7 @@ let groupByLanguage = groupBy(dictionaryResources, 'language') let translateLanguageList = $ref([]) let wordList = $ref([]) -let step = $ref(0) +let step = $ref(1) let loading = $ref(false) let chapterList2 = $ref([]) let chapterWordNumber = $ref(settingStore.chapterWordNumber) @@ -78,10 +80,10 @@ async function selectDict(val: { if (!runtimeStore.editDict.originWords.length) { let r = await fetch(url) let v = await r.json() + v.map(s => s.id = nanoid(6)) runtimeStore.editDict.originWords = cloneDeep(v) changeSort(runtimeStore.editDict.sort) } - wordList = cloneDeep(runtimeStore.editDict.words) } if (runtimeStore.editDict.type === DictType.customWord) { @@ -266,6 +268,8 @@ async function onSubmit() { let wordFormData = $ref({ where: '', type: '', + name: '', + id: '', index: 0 }) @@ -279,7 +283,7 @@ const DefaultFormWord = { name: '', usphone: '', ukphone: '', - trans: '' + trans: '', } let wordFormMode = $ref(FormMode.None) @@ -317,47 +321,46 @@ async function onSubmitWord() { data.trans = [] } if (wordFormData.type === FormMode.Add) { - if (wordList.find(v => v.name === wordForm.name)) { - return ElMessage.warning('已有相同名称单词!') + data.id = nanoid(6) + data.checked = false + let r + if (wordFormData.where === 'chapter') { + r = currentChapterWordList.find(v => v.name === wordForm.name) + if (r) return ElMessage.warning('已有相同名称单词!') + else { + currentChapterWordList.push(data) + } } else { - runtimeStore.editDict.originWords.push(data) - runtimeStore.editDict.words.push(data) - - if (wordFormData.where === 'chapter') { - runtimeStore.editDict.chapterWords[chapterIndex].push(data) - } else { + r = residueWordList.find(v => v.name === wordForm.name) + if (r) return ElMessage.warning('已有相同名称单词!') + else { residueWordList.push(data) } - - ElMessage.success('添加成功') - wordForm = cloneDeep(DefaultFormWord) - setTimeout(wordListRef?.scrollToBottom, 100) } + + runtimeStore.editDict.originWords.push(data) + runtimeStore.editDict.words.push(data) + ElMessage.success('添加成功') + wordForm = cloneDeep(DefaultFormWord) + setTimeout(wordListRef?.scrollToBottom, 100) + console.log('runtimeStore.editDict', runtimeStore.editDict) } else { - let oldData + //直接使用引用修改 + let r if (wordFormData.where === 'chapter') { - oldData = cloneDeep(currentChapterWordList[wordFormData.index]) - }else { - oldData = cloneDeep(residueWordList[wordFormData.index]) - } - runtimeStore.editDict.words[wordFormData.index] = data - //因为虚拟列表,必须重新赋值才能检测到更新 - wordList = cloneDeep(runtimeStore.editDict.words) - //同步到原始列表,因为word可能是随机的,所以需要自己寻找index去修改原始列表 - let rIndex = runtimeStore.editDict.originWords.findIndex(v => v.name === oldData.name) - if (rIndex > -1) { - runtimeStore.editDict.originWords[rIndex] = data + r = currentChapterWordList.find(v => v.id === wordFormData.id) + if (r) assign(r, data) + } else { + r = residueWordList.find(v => v.id === wordFormData.id) + if (r) assign(r, data) } + //同步修改到列表 + r = runtimeStore.editDict.originWords.find(v => v.id === wordFormData.id) + if (r) assign(r, data) + r = runtimeStore.editDict.words.find(v => v.id === wordFormData.id) + if (r) assign(r, data) - runtimeStore.editDict.chapterWords = runtimeStore.editDict.chapterWords.map(list => { - let rIndex2 = list.findIndex(v => v.name === oldData.name) - if (rIndex2 > -1) { - list[rIndex2] = data - } - return list - }) - console.log('runtimeStore.editDict.chapterWords', runtimeStore.editDict.chapterWords) ElMessage.success('修改成功') } syncMyDictList() @@ -367,65 +370,50 @@ async function onSubmitWord() { }) } -function delWord(word: Word, index: number) { - //同步到原始列表,因为word可能是随机的,所以需要自己寻找index去修改原始列表 - let rIndex = runtimeStore.editDict.originWords.findIndex(v => v.name === word.name) +function addWord(where: string) { + // setTimeout(wordListRef?.scrollToBottom, 100) + wordFormData.type = FormMode.Add + wordFormData.where = where + wordForm = cloneDeep(DefaultFormWord) +} + +function delWord(word: Word, index: number, where: string) { + let rIndex = runtimeStore.editDict.originWords.findIndex(v => v.id === word.id) if (rIndex > -1) { runtimeStore.editDict.originWords.splice(rIndex, 1) } - - runtimeStore.editDict.chapterWords.map(list => { - let rIndex2 = list.findIndex(v => v.name === word.name) - if (rIndex2 > -1) { - list.splice(rIndex2, 1) - } - }) - - runtimeStore.editDict.chapterWords = runtimeStore.editDict.chapterWords.filter(v => v.length) - if (runtimeStore.editDict.chapterWords.length === 0) runtimeStore.editDict.chapterIndex = -1 - else { - if (runtimeStore.editDict.chapterIndex >= runtimeStore.editDict.chapterWords.length) { - runtimeStore.editDict.chapterIndex = runtimeStore.editDict.chapterWords.length - 1 - } + let rIndex2 = runtimeStore.editDict.words.findIndex(v => v.id === word.id) + if (rIndex2 > -1) { + runtimeStore.editDict.words.splice(rIndex2, 1) } - runtimeStore.editDict.words.splice(index, 1) - wordList = cloneDeep(runtimeStore.editDict.words) - syncMyDictList() + if (where === 'chapter') { + currentChapterWordList.splice(index, 1) + } else { + residueWordList.splice(index, 1) + } - closeWordForm() + if (wordFormData.type === FormMode.Edit && wordForm.name === word.name) { + closeWordForm() + } + syncMyDictList() } -function editWord(val: { - word: Word, - index: number -}) { - wordFormMode = val.index - wordForm.name = val.word.name - wordForm.ukphone = val.word.ukphone - wordForm.usphone = val.word.usphone - wordForm.trans = val.word.trans.join('\n') +function editWord(word: Word, index: number, where: string) { + wordFormData.type = FormMode.Edit + wordFormData.id = word.id + wordFormData.where = where + wordForm.name = word.name + wordForm.ukphone = word.ukphone + wordForm.usphone = word.usphone + wordForm.trans = word.trans.join('\n') } function closeWordForm() { - wordFormMode = FormMode.None + wordFormData.type = FormMode.None wordForm = cloneDeep(DefaultFormWord) } -function addWord() { - // setTimeout(wordListRef?.scrollToBottom, 100) - wordFormMode = FormMode.Add - wordForm = cloneDeep(DefaultFormWord) -} - -function add() { - if (dictIsArticle) { - - } else { - addWord() - } -} - /**/ /* 单词修改相关*/ /**/ @@ -438,7 +426,14 @@ watch(() => step, v => { } }) +watch(() => store.load, v => { + if (v) { + selectDict({dict: store.currentDict, index: 0}) + } +}) + const playWordAudio = usePlayWordAudio() +let showAllocationChapterDialog = $ref(false) onMounted(() => { dictionaryResources.map(v => { @@ -456,6 +451,8 @@ onMounted(() => { } }) + selectDict({dict: store.currentDict, index: 0}) + emitter.on(EventKey.openDictModal, (type: 'detail' | 'list' | 'my' | 'collect' | 'simple') => { if (type === "detail") { selectDict({dict: store.currentDict, index: 0}) @@ -496,8 +493,20 @@ let residueWordListCheckedTotal = $computed(() => { return residueWordList.filter(v => v.checked).length }) +function handleChangeCurrentChapter(index: number) { + currentChapterWordList.map(v => v.checked = false) + currentChapterWordListCheckAll = currentChapterWordListIsIndeterminate = false + chapterIndex = index + closeWordForm() +} + function toResidueWordList() { let list = currentChapterWordList.filter(v => v.checked) + if (wordFormData.type === FormMode.Edit && wordFormData.where === 'chapter') { + if (list.find(v => v.name === wordForm.name)) { + wordFormData.where = 'residue' + } + } runtimeStore.editDict.chapterWords[chapterIndex] = currentChapterWordList.filter(v => !v.checked) list.map(v => v.checked = false) residueWordList = residueWordList.concat(list) @@ -506,6 +515,11 @@ function toResidueWordList() { function toChapterWordList() { let list = residueWordList.filter(v => v.checked) + if (wordFormData.type === FormMode.Edit && wordFormData.where !== 'chapter') { + if (list.find(v => v.name === wordForm.name)) { + wordFormData.where = 'chapter' + } + } residueWordList = residueWordList.filter(v => !v.checked) list.map(v => v.checked = false) runtimeStore.editDict.chapterWords[chapterIndex] = runtimeStore.editDict.chapterWords[chapterIndex].concat(list) @@ -528,8 +542,6 @@ function delWordChapter(index: number) { syncMyDictList() } -let showAllocationChapterDialog = $ref(false) - function resetChapterList() { residueWordList = [] chapterIndex = -1 @@ -568,6 +580,18 @@ function handleCurrentResidueWordListCheckAll() { residueWordListIsIndeterminate = false } +function exportData() { + no() +} + +function importData() { + no() +} + +const isPinDict = $computed(() => { + return [DictType.collect, DictType.wrong, DictType.simple].includes(runtimeStore.editDict.type) +}) + @@ -995,7 +1032,7 @@ $header-height: 60rem; top: 50%; transform: translate(-50%, -50%); z-index: 1; - width: 90vw; + width: 80vw; height: 75vh; } @@ -1072,20 +1109,44 @@ $header-height: 60rem; flex-direction: column; header { - cursor: pointer; width: 100%; display: flex; box-sizing: border-box; - height: $header-height; align-items: center; - justify-content: space-between; - color: var(--color-font-3); + color: var(--color-font-1); padding: 0 var(--space); + gap: 20rem; + margin-bottom: 20rem; + + svg { + cursor: pointer + } .left { display: flex; gap: 10rem; - align-items: center; + flex-direction: column; + color: var(--color-font-2); + + .top { + color: var(--color-font-1); + display: flex; + gap: 10rem; + font-size: 20rem; + align-items: center; + } + + .import { + display: inline-flex; + position: relative; + + input { + position: absolute; + height: 100%; + width: 100%; + opacity: 0; + } + } } } @@ -1180,7 +1241,7 @@ $header-height: 60rem; justify-content: center; .wrapper { - width: 50%; + width: 500rem; } .el-select { diff --git a/src/stores/base.ts b/src/stores/base.ts index daa1a3a6..dca559f5 100644 --- a/src/stores/base.ts +++ b/src/stores/base.ts @@ -6,6 +6,7 @@ import {v4 as uuidv4} from 'uuid'; import {useRuntimeStore} from "@/stores/runtime.ts"; import * as localforage from "localforage"; import {checkDictHasTranslate} from "@/hooks/dict.ts"; +import {nanoid} from "nanoid"; export interface BaseState { myDictList: Dict[], @@ -88,18 +89,18 @@ export const useBaseStore = defineStore('base', { type: DictType.wrong, category: '自带字典' }, - { - ...cloneDeep(DefaultDict), - id: 'article_nce2', - name: "新概念英语2-课文", - description: '新概念英语2-课文', - category: '英语学习', - tags: ['新概念英语'], - url: 'NCE_2.json', - translateLanguage: 'common', - language: 'en', - type: DictType.article - }, + // { + // ...cloneDeep(DefaultDict), + // id: 'article_nce2', + // name: "新概念英语2-课文", + // description: '新概念英语2-课文', + // category: '英语学习', + // tags: ['新概念英语'], + // url: 'NCE_2.json', + // translateLanguage: 'common', + // language: 'en', + // type: DictType.article + // }, { ...cloneDeep(DefaultDict), id: 'nce-new-2', @@ -190,7 +191,7 @@ export const useBaseStore = defineStore('base', { return new Promise(async resolve => { try { let configStr: string = await localforage.getItem(SaveDict.key) - console.log(configStr) + // console.log(configStr) console.log('s', new Blob([configStr]).size) configStr = '' if (configStr) { @@ -214,12 +215,12 @@ export const useBaseStore = defineStore('base', { let dictResourceUrl = `./dicts/${this.currentDict.language}/${this.currentDict.type}/${this.currentDict.translateLanguage}/${this.currentDict.url}`; if ([ DictType.word, - DictType.customWord, ].includes(this.currentDict.type)) { if (!this.currentDict.originWords.length) { let r = await fetch(dictResourceUrl) // let r = await fetch(`.${this.currentDict.url}`) let v = await r.json() + v.map(s => s.id = nanoid(6)) if (this.currentDict.translateLanguage === 'common') { const runtimeStore = useRuntimeStore() let r2 = await fetch('./translate/en2zh_CN-min.json') diff --git a/src/types.ts b/src/types.ts index 8a8d7baf..6174285b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -10,6 +10,8 @@ export type Word = { "usphone": string, "ukphone": string, "trans": string[] + checked?: boolean, + id?: any, } export const DefaultWord: Word = { diff --git a/src/utils/index.ts b/src/utils/index.ts index 227a5154..2591c482 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,3 +1,7 @@ export function getRandom(a: number, b: number): number { return Math.random() * (b - a) + a; } + +export function no(){ + ElMessage.warning('未现实') +} \ No newline at end of file