From 36af50da1cf6a7941f16521c17e090d0ad02fa2b Mon Sep 17 00:00:00 2001 From: zyronon Date: Sun, 10 Aug 2025 01:54:32 +0800 Subject: [PATCH 01/92] =?UTF-8?q?fix:=E5=88=A0=E9=99=A4=E6=97=A0=E7=94=A8?= =?UTF-8?q?=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 +- pnpm-lock.yaml | 102 -------- src/assets/img/shotFire.html | 460 ----------------------------------- src/components/BaseIcon.vue | 1 - 4 files changed, 1 insertion(+), 565 deletions(-) delete mode 100644 src/assets/img/shotFire.html diff --git a/package.json b/package.json index 02f1653e..3eabf5d7 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,5 @@ "commitizen": { "path": "./node_modules/cz-conventional-changelog" } - }, - "packageManager": "pnpm@9.1.4+sha512.9df9cf27c91715646c7d675d1c9c8e41f6fce88246f1318c1aa6a1ed1aeb3c4f032fcdf4ba63cc69c4fe6d634279176b5358727d8f2cc1e65b65f43ce2f8bfb0" + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 92a77dbf..e435ac96 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -129,12 +129,6 @@ importers: unocss: specifier: ^66.4.0 version: 66.4.0(postcss@8.5.6)(vite@7.0.3(@types/node@24.0.11)(jiti@2.4.2)(sass@1.89.2)) - unplugin-auto-import: - specifier: '^19.3.0 ' - version: 19.3.0(@vueuse/core@9.13.0(vue@3.5.17(typescript@5.8.3))) - unplugin-vue-components: - specifier: ^28.8.0 - version: 28.8.0(@babel/parser@7.28.0)(vue@3.5.17(typescript@5.8.3)) unplugin-vue-macros: specifier: ^2.14.5 version: 2.14.5(@vueuse/core@9.13.0(vue@3.5.17(typescript@5.8.3)))(esbuild@0.25.6)(rollup@4.44.2)(typescript@5.8.3)(vite@7.0.3(@types/node@24.0.11)(jiti@2.4.2)(sass@1.89.2))(vue-tsc@3.0.1(typescript@5.8.3))(vue@3.5.17(typescript@5.8.3)) @@ -1869,10 +1863,6 @@ packages: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} - escape-string-regexp@5.0.0: - resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} - engines: {node: '>=12'} - esm@3.2.25: resolution: {integrity: sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==} engines: {node: '>=6'} @@ -2421,9 +2411,6 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-tokens@9.0.1: - resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} - js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true @@ -3092,9 +3079,6 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - scule@1.3.0: - resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} - semver-greatest-satisfied-range@1.1.0: resolution: {integrity: sha512-Ny/iyOzSSa8M5ML46IAx3iXc6tfOsYU2R4AXi2UpHk60Zrgyq6eqPj/xiOfS0rRl/iiQ/rdJkVjw/5cdUyCntQ==} engines: {node: '>= 0.10'} @@ -3259,9 +3243,6 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - strip-literal@3.0.0: - resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} - structured-source@4.0.0: resolution: {integrity: sha512-qGzRFNJDjFieQkl/sVOI2dUjHKRyL9dAJi2gCPGJLbJHBIkyOHxjuocpIEfbLioX+qSJpvbYdT49/YCdMznKxA==} @@ -3400,10 +3381,6 @@ packages: undici-types@7.8.0: resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==} - unimport@4.2.0: - resolution: {integrity: sha512-mYVtA0nmzrysnYnyb3ALMbByJ+Maosee2+WyE0puXl+Xm2bUwPorPaaeZt0ETfuroPOtG8jj1g/qeFZ6buFnag==} - engines: {node: '>=18.12.0'} - union-value@1.0.1: resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} engines: {node: '>=0.10.0'} @@ -3427,18 +3404,6 @@ packages: vite: optional: true - unplugin-auto-import@19.3.0: - resolution: {integrity: sha512-iIi0u4Gq2uGkAOGqlPJOAMI8vocvjh1clGTfSK4SOrJKrt+tirrixo/FjgBwXQNNdS7ofcr7OxzmOb/RjWxeEQ==} - engines: {node: '>=14'} - peerDependencies: - '@nuxt/kit': ^3.2.2 - '@vueuse/core': '*' - peerDependenciesMeta: - '@nuxt/kit': - optional: true - '@vueuse/core': - optional: true - unplugin-combine@1.2.1: resolution: {integrity: sha512-qGkXjQo8yTq5QknP8f8p8/Aw3BJKqclTbTe8de0pC6exHzpoPBnH69Eztf00G2oc50IaIlV7KX/g4cKgzCq9BA==} engines: {node: '>=16.14.0'} @@ -3474,19 +3439,6 @@ packages: resolution: {integrity: sha512-8U/MtpkPkkk3Atewj1+RcKIjb5WBimZ/WSLhhR3w6SsIj8XJuKTacSP8g+2JhfSGw0Cb125Y+2zA/IzJZDVbhA==} engines: {node: '>=18.12.0'} - unplugin-vue-components@28.8.0: - resolution: {integrity: sha512-2Q6ZongpoQzuXDK0ZsVzMoshH0MWZQ1pzVL538G7oIDKRTVzHjppBDS8aB99SADGHN3lpGU7frraCG6yWNoL5Q==} - engines: {node: '>=14'} - peerDependencies: - '@babel/parser': ^7.15.8 - '@nuxt/kit': ^3.2.2 || ^4.0.0 - vue: 2 || 3 - peerDependenciesMeta: - '@babel/parser': - optional: true - '@nuxt/kit': - optional: true - unplugin-vue-define-options@1.5.5: resolution: {integrity: sha512-V50sWbpoADsjyVgovxewoLo2IDW0zfgHJbKiAl2EdZT8OL3g3h1Mz3QKoAAu09i8+LnkDatIEQMgBVeHHxWXNg==} engines: {node: '>=16.14.0'} @@ -5652,8 +5604,6 @@ snapshots: escape-string-regexp@1.0.5: {} - escape-string-regexp@5.0.0: {} - esm@3.2.25: {} esniff@2.0.1: @@ -6251,8 +6201,6 @@ snapshots: js-tokens@4.0.0: {} - js-tokens@9.0.1: {} - js-yaml@4.1.0: dependencies: argparse: 2.0.1 @@ -6971,8 +6919,6 @@ snapshots: optionalDependencies: '@parcel/watcher': 2.5.1 - scule@1.3.0: {} - semver-greatest-satisfied-range@1.1.0: dependencies: sver-compat: 1.5.0 @@ -7156,10 +7102,6 @@ snapshots: strip-json-comments@3.1.1: {} - strip-literal@3.0.0: - dependencies: - js-tokens: 9.0.1 - structured-source@4.0.0: dependencies: boundary: 2.0.0 @@ -7313,23 +7255,6 @@ snapshots: undici-types@7.8.0: optional: true - unimport@4.2.0: - dependencies: - acorn: 8.15.0 - escape-string-regexp: 5.0.0 - estree-walker: 3.0.3 - local-pkg: 1.1.1 - magic-string: 0.30.17 - mlly: 1.7.4 - pathe: 2.0.3 - picomatch: 4.0.2 - pkg-types: 2.2.0 - scule: 1.3.0 - strip-literal: 3.0.0 - tinyglobby: 0.2.14 - unplugin: 2.3.5 - unplugin-utils: 0.2.4 - union-value@1.0.1: dependencies: arr-union: 3.1.0 @@ -7371,17 +7296,6 @@ snapshots: - postcss - supports-color - unplugin-auto-import@19.3.0(@vueuse/core@9.13.0(vue@3.5.17(typescript@5.8.3))): - dependencies: - local-pkg: 1.1.1 - magic-string: 0.30.17 - picomatch: 4.0.2 - unimport: 4.2.0 - unplugin: 2.3.5 - unplugin-utils: 0.2.4 - optionalDependencies: - '@vueuse/core': 9.13.0(vue@3.5.17(typescript@5.8.3)) - unplugin-combine@1.2.1(esbuild@0.25.6)(rollup@4.44.2)(unplugin@1.16.1)(vite@7.0.3(@types/node@24.0.11)(jiti@2.4.2)(sass@1.89.2)): optionalDependencies: esbuild: 0.25.6 @@ -7401,22 +7315,6 @@ snapshots: pathe: 2.0.3 picomatch: 4.0.2 - unplugin-vue-components@28.8.0(@babel/parser@7.28.0)(vue@3.5.17(typescript@5.8.3)): - dependencies: - chokidar: 3.6.0 - debug: 4.4.1 - local-pkg: 1.1.1 - magic-string: 0.30.17 - mlly: 1.7.4 - tinyglobby: 0.2.14 - unplugin: 2.3.5 - unplugin-utils: 0.2.4 - vue: 3.5.17(typescript@5.8.3) - optionalDependencies: - '@babel/parser': 7.28.0 - transitivePeerDependencies: - - supports-color - unplugin-vue-define-options@1.5.5(vue@3.5.17(typescript@5.8.3)): dependencies: '@vue-macros/common': 1.16.1(vue@3.5.17(typescript@5.8.3)) diff --git a/src/assets/img/shotFire.html b/src/assets/img/shotFire.html deleted file mode 100644 index 9af5c5ab..00000000 --- a/src/assets/img/shotFire.html +++ /dev/null @@ -1,460 +0,0 @@ - - - - - - 放烟花模拟 - - -浏览器不支持canvas - -
-
新年快乐
-
合家幸福
-
HAPPY
-
- - - - - - - - - - - - diff --git a/src/components/BaseIcon.vue b/src/components/BaseIcon.vue index 6a562957..e249d2a4 100644 --- a/src/components/BaseIcon.vue +++ b/src/components/BaseIcon.vue @@ -1,7 +1,6 @@ + - - + + +
diff --git a/src/assets/css/style.scss b/src/assets/css/style.scss index 0ff0b10d..5ab4b294 100644 --- a/src/assets/css/style.scss +++ b/src/assets/css/style.scss @@ -17,10 +17,11 @@ --practice-wrapper-translateX: 1px; --article-width: 50vw; + --article-toolbar-width: 50rem; --toolbar-width: 50rem; --panel-width: 24rem; --space: 1rem; - --stat-gap: 2rem; + --stat-gap: 1rem; --shadow: rgba(0, 0, 0, 0.08) 0px 4px 12px; --panel-margin-left: calc(50% + var(--toolbar-width) / 2 + 1rem); --article-panel-margin-left: calc(50% + var(--article-width) / 2 + 1rem); @@ -416,7 +417,7 @@ a { .book { @extend .anim; - @apply p-4 rounded-md relative cursor-pointer bg-third hover:bg-card-active flex flex-col justify-between; + @apply p-4 rounded-md relative cursor-pointer bg-third hover:bg-card-active flex flex-col justify-between shrink-0; $w: 6rem; width: $w; height: calc($w * 1.4); diff --git a/src/pages/pc/article/ArticleHomePage.vue b/src/pages/pc/article/ArticleHomePage.vue index 8e6fd056..52957e03 100644 --- a/src/pages/pc/article/ArticleHomePage.vue +++ b/src/pages/pc/article/ArticleHomePage.vue @@ -126,7 +126,7 @@ async function goBookDetail(val: DictResource) {
创建个人书籍
-
+
() +let editArticle = $ref
(getDefaultArticle()) + +useStartKeyboardEventListener() function write() { // console.log('write') @@ -27,81 +49,427 @@ function write() { } //TODO 需要判断是否已忽略 +//todo 使用场景是? function repeat() { // console.log('repeat') - emitter.emit(EventKey.resetWord) - practiceRef.getCurrentPractice() + getCurrentPractice() } function prev() { // console.log('next') - if (store.currentBook.chapterIndex === 0) { + if (store.sbook.lastLearnIndex === 0) { ElMessage.warning('已经在第一章了~') } else { - store.currentBook.chapterIndex-- - repeat() + store.sbook.lastLearnIndex-- + getCurrentPractice() } } -function toggleShowTranslate() { - settingStore.translate = !settingStore.translate -} - -function toggleDictation() { - settingStore.dictation = !settingStore.dictation -} +const toggleShowTranslate = () => settingStore.translate = !settingStore.translate +const toggleDictation = () => settingStore.dictation = !settingStore.dictation +const togglePanel = () => settingStore.showPanel = !settingStore.showPanel +const skip = () => typingArticleRef?.nextSentence() +const collect = () => toggleArticleCollect(articleData.article) +const shortcutKeyEdit = () => edit() function toggleConciseMode() { settingStore.showToolbar = !settingStore.showToolbar settingStore.showPanel = settingStore.showToolbar } -function togglePanel() { - settingStore.showPanel = !settingStore.showPanel +function next() { + if (store.sbook.lastLearnIndex >= articleData.list.length - 1) { + store.sbook.lastLearnIndex = 0 + //todo 这里应该弹窗 + } else store.sbook.lastLearnIndex++ + getCurrentPractice() } -function jumpSpecifiedChapter(val: number) { - store.currentBook.chapterIndex = val - repeat() +function init() { + if (!store.sbook?.articles?.length) { + router.push('/article') + return + } + articleData.list = cloneDeep(store.sbook.articles) + getCurrentPractice() + console.log('init', articleData.article) } +function setArticle(val: Article) { + statisticsStore.inputWordNumber = 0 + statisticsStore.wrong = 0 + statisticsStore.total = 0 + statisticsStore.startDate = Date.now() + + articleData.list[store.sbook.lastLearnIndex] = val + articleData.article = val + articleData.sectionIndex = 0 + articleData.sentenceIndex = 0 + articleData.wordIndex = 0 + articleData.stringIndex = 0 + articleData.article.sections.map((v, i) => { + v.map((w, j) => { + w.words.map(s => { + if (!store.knownWordsWithSimpleWords.includes(s.word.toLowerCase()) && !s.isSymbol) { + statisticsStore.total++ + } + }) + }) + }) +} + +function getCurrentPractice() { + emitter.emit(EventKey.resetWord) + let currentArticle = articleData.list[store.sbook.lastLearnIndex] + let article = getDefaultArticle(currentArticle) + // console.log('article', article) + if (article.sections.length) { + setArticle(article) + } else { + genArticleSectionData(article) + setArticle(article) + } +} + +function saveArticle(val: Article) { + console.log('saveArticle', val, JSON.stringify(val.lrcPosition)) + console.log('saveArticle', val.textTranslate) + showEditArticle = false + let rIndex = store.sbook.articles.findIndex(v => v.id === val.id) + if (rIndex > -1) { + store.sbook.articles[rIndex] = cloneDeep(val) + } + setArticle(val) +} + +function edit(val: Article = articleData.article) { + editArticle = val + showEditArticle = true +} + +function wrong(word: Word) { + let lowerName = word.word.toLowerCase(); + if (!store.wrong.words.find((v: Word) => v.word.toLowerCase() === lowerName)) { + store.wrong.words.push(word) + } + if (!store.knownWordsWithSimpleWords.includes(lowerName)) { + //todo + } +} + +function nextWord(word: ArticleWord) { + if (!store.knownWordsWithSimpleWords.includes(word.word.toLowerCase()) && !word.isSymbol) { + statisticsStore.inputWordNumber++ + } +} + +function changeArticle(val: ArticleItem) { + let rIndex = articleData.list.findIndex(v => v.id === val.item.id) + if (rIndex > -1) { + store.sbook.lastLearnIndex = rIndex + getCurrentPractice() + } +} + +const { + isArticleCollect, + toggleArticleCollect +} = useArticleOptions() + +function play() { + typingArticleRef?.play() +} + +function show() { + typingArticleRef?.showSentence() +} + + +function onKeyUp() { + typingArticleRef.hideSentence() +} + +async function onKeyDown(e: KeyboardEvent) { + // console.log('e', e) + switch (e.key) { + case 'Backspace': + typingArticleRef.del() + break + } +} + +useOnKeyboardEventListener(onKeyDown, onKeyUp) + + +onMounted(init) + +useEvents([ + [EventKey.write, write], + [EventKey.repeatStudy, repeat], + [EventKey.continueStudy, next], + + [ShortcutKey.PreviousChapter, prev], + [ShortcutKey.RepeatChapter, repeat], + [ShortcutKey.DictationChapter, write], + [ShortcutKey.ToggleShowTranslate, toggleShowTranslate], + [ShortcutKey.ToggleDictation, toggleDictation], + [ShortcutKey.ToggleTheme, toggleTheme], + [ShortcutKey.ToggleConciseMode, toggleConciseMode], + [ShortcutKey.TogglePanel, togglePanel], + [ShortcutKey.NextChapter, next], + [ShortcutKey.PlayWordPronunciation, play], + [ShortcutKey.ShowWord, show], + [ShortcutKey.Next, skip], + [ShortcutKey.ToggleCollect, collect], + [ShortcutKey.EditArticle, shortcutKeyEdit], +]) + +let speedMinute = $ref(0) +let timer = $ref(0) onMounted(() => { - emitter.on(EventKey.write, write) - emitter.on(EventKey.repeatStudy, repeat) - emitter.on(EventKey.jumpSpecifiedChapter, jumpSpecifiedChapter) - - emitter.on(ShortcutKey.PreviousChapter, prev) - emitter.on(ShortcutKey.RepeatChapter, repeat) - emitter.on(ShortcutKey.DictationChapter, write) - emitter.on(ShortcutKey.ToggleShowTranslate, toggleShowTranslate) - emitter.on(ShortcutKey.ToggleDictation, toggleDictation) - emitter.on(ShortcutKey.ToggleTheme, toggleTheme) - emitter.on(ShortcutKey.ToggleConciseMode, toggleConciseMode) - emitter.on(ShortcutKey.TogglePanel, togglePanel) + timer = setInterval(() => { + speedMinute = Math.floor((Date.now() - statisticsStore.startDate) / 1000 / 60) + }, 1000) }) onUnmounted(() => { - emitter.off(EventKey.write, write) - emitter.off(EventKey.repeatStudy, repeat) - emitter.off(EventKey.jumpSpecifiedChapter, jumpSpecifiedChapter) - - emitter.off(ShortcutKey.PreviousChapter, prev) - emitter.off(ShortcutKey.RepeatChapter, repeat) - emitter.off(ShortcutKey.DictationChapter, write) - emitter.off(ShortcutKey.ToggleShowTranslate, toggleShowTranslate) - emitter.off(ShortcutKey.ToggleDictation, toggleDictation) - emitter.off(ShortcutKey.ToggleTheme, toggleTheme) - emitter.off(ShortcutKey.ToggleConciseMode, toggleConciseMode) - emitter.off(ShortcutKey.TogglePanel, togglePanel) + timer && clearInterval(timer) }) -useStartKeyboardEventListener() +let audioRef = $ref() +const {playSentenceAudio} = usePlaySentenceAudio() diff --git a/src/pages/pc/article/practice-article/TypingArticle.vue b/src/pages/pc/article/components/TypingArticle.vue similarity index 99% rename from src/pages/pc/article/practice-article/TypingArticle.vue rename to src/pages/pc/article/components/TypingArticle.vue index 387ad98a..90f70c68 100644 --- a/src/pages/pc/article/practice-article/TypingArticle.vue +++ b/src/pages/pc/article/components/TypingArticle.vue @@ -21,7 +21,6 @@ interface IProps { sentenceIndex?: number, wordIndex?: number, stringIndex?: number, - active: boolean, } const props = withDefaults(defineProps(), { @@ -30,7 +29,6 @@ const props = withDefaults(defineProps(), { sentenceIndex: 0, wordIndex: 0, stringIndex: 0, - active: true, }) const emit = defineEmits<{ @@ -38,7 +36,8 @@ const emit = defineEmits<{ wrong: [val: Word], play: [val: Sentence], nextWord: [val: ArticleWord], - over: [], + complete: [], + next: [], edit: [val: Article] }>() @@ -175,7 +174,7 @@ function nextSentence() { if (!props.article.sections[sectionIndex]) { console.log('打完了') isEnd = true - emit('over') + emit('complete') } else { emit('play', props.article.sections[sectionIndex][0]) } @@ -186,7 +185,6 @@ function nextSentence() { } function onTyping(e: KeyboardEvent) { - if (!props.active) return if (!props.article.sections.length) return // console.log('keyDown', e.key, e.code, e.keyCode) wrong = '' @@ -458,7 +456,7 @@ let showQuestions = $ref(false)
下一章 + @click="emit('next')">下一章
diff --git a/src/pages/pc/article/practice-article/index.vue b/src/pages/pc/article/practice-article/index.vue deleted file mode 100644 index 689305f7..00000000 --- a/src/pages/pc/article/practice-article/index.vue +++ /dev/null @@ -1,520 +0,0 @@ - - - - - diff --git a/src/pages/pc/components/list/DictList.vue b/src/pages/pc/components/list/DictList.vue index a1330364..aefa5f7e 100644 --- a/src/pages/pc/components/list/DictList.vue +++ b/src/pages/pc/components/list/DictList.vue @@ -18,7 +18,7 @@ const emit = defineEmits<{ diff --git a/src/pages/pc/word/StudyWord.vue b/src/pages/pc/word/StudyWord.vue index 151af1c8..dc2ab7a1 100644 --- a/src/pages/pc/word/StudyWord.vue +++ b/src/pages/pc/word/StudyWord.vue @@ -25,6 +25,7 @@ import {usePracticeStore} from "@/stores/practice.ts"; import {dictionaryResources} from "@/assets/dictionary.ts"; import {ElMessage} from "element-plus"; import {getDefaultWord} from "@/types/func.ts"; +import ConflictNotice from "@/pages/pc/components/ConflictNotice.vue"; interface IProps { new: Word[], @@ -439,6 +440,7 @@ useEvents([
+ diff --git a/src/pages/pc/components/Toast/type.ts b/src/pages/pc/components/Toast/type.ts new file mode 100644 index 00000000..83035f5e --- /dev/null +++ b/src/pages/pc/components/Toast/type.ts @@ -0,0 +1,26 @@ +export type ToastType = 'success' | 'warning' | 'info' | 'error' + +export interface ToastOptions { + message: string + type?: ToastType + duration?: number + showClose?: boolean +} + +export interface ToastInstance { + close: () => void +} + +export interface ToastService { + (options: ToastOptions | string): ToastInstance + + success(message: string, options?: Omit): ToastInstance + + warning(message: string, options?: Omit): ToastInstance + + info(message: string, options?: Omit): ToastInstance + + error(message: string, options?: Omit): ToastInstance + + closeAll(): void +} diff --git a/src/pages/pc/word/WordHomePage.vue b/src/pages/pc/word/WordHomePage.vue index 6e1d1ab8..279412f3 100644 --- a/src/pages/pc/word/WordHomePage.vue +++ b/src/pages/pc/word/WordHomePage.vue @@ -12,10 +12,10 @@ import {getCurrentStudyWord} from "@/hooks/dict.ts"; import {useRuntimeStore} from "@/stores/runtime.ts"; import Book from "@/pages/pc/components/Book.vue"; import PopConfirm from "@/pages/pc/components/PopConfirm.vue"; -import {ElMessage, ElProgress, ElSlider} from 'element-plus'; +import {ElProgress, ElSlider} from 'element-plus'; +import Toast from '@/pages/pc/components/Toast/Toast.ts'; import BaseButton from "@/components/BaseButton.vue"; import {getDefaultDict} from "@/types/func.ts"; -import ConflictNotice from "@/pages/pc/components/ConflictNotice.vue"; const store = useBaseStore() const router = useRouter() @@ -47,7 +47,7 @@ async function init() { function startStudy() { if (store.sdict.id) { if (!store.sdict.words.length) { - return ElMessage.warning('没有单词可学习!') + return Toast.warning('没有单词可学习!') } window.umami?.track('startStudyDict', { name: store.sdict.name, @@ -59,7 +59,7 @@ function startStudy() { nav('study-word', {}, currentStudy) } else { window.umami?.track('no-dict') - ElMessage.warning('请先选择一本词典') + Toast.warning('请先选择一本词典') } } @@ -68,7 +68,7 @@ function setPerDayStudyNumber() { show = true tempPerDayStudyNumber = store.sdict.perDayStudyNumber } else { - ElMessage.warning('请先选择一本词典') + Toast.warning('请先选择一本词典') } } @@ -102,7 +102,7 @@ function handleBatchDel() { } }) selectIds = [] - ElMessage.success("删除成功!") + Toast.success("删除成功!") } function toggleSelect(item) { @@ -181,7 +181,8 @@ const progressTextRight = $computed(() => { 个单词 更改 - + +
开始学习 diff --git a/src/global.d.ts b/src/types/global.d.ts similarity index 92% rename from src/global.d.ts rename to src/types/global.d.ts index 1fc0180f..ce1821d0 100644 --- a/src/global.d.ts +++ b/src/types/global.d.ts @@ -1,5 +1,3 @@ -export {} - declare global { interface Console { parse(v: any): void @@ -9,10 +7,11 @@ declare global { interface Window { umami: { - track(name:string,data?:any):void + track(name: string, data?: any): void } } } + console.json = function (v: any, space = 0) { const json = JSON.stringify( v, @@ -30,3 +29,5 @@ console.json = function (v: any, space = 0) { console.parse = function (v: any) { console.log(JSON.parse(v)) } + +export {} diff --git a/tsconfig.json b/tsconfig.json index c9efcf51..f27711dd 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -47,9 +47,7 @@ "src/**/*.tsx", "src/**/*.d.ts", "src/**/*.vue", - "auto-imports.d.ts", "src/vite-env.d.ts", - "src/global.d.ts" ], "references": [ { diff --git a/vite.config.ts b/vite.config.ts index f46f1793..94d061f2 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -42,25 +42,25 @@ export default defineConfig(() => { open: true //如果存在本地服务端口,将在打包后自动展示 }) : null, SlidePlugin(), - // importToCDN({ - // modules: [ - // { - // name: 'vue', - // var: 'Vue', - // path: `https://cdn.jsdelivr.net/npm/vue@3.5.14/dist/vue.global.prod.min.js` - // }, - // { - // name: 'vue-router', - // var: 'VueRouter', - // path: `https://cdn.jsdelivr.net/npm/vue-router@4.5.1/dist/vue-router.global.prod.min.js` - // }, - // { - // name: 'axios', - // var: 'axios', - // path: 'https://cdn.jsdelivr.net/npm/axios@1.9.0/dist/axios.min.js' - // }, - // ] - // }) + importToCDN({ + modules: [ + { + name: 'vue', + var: 'Vue', + path: `https://type-words.oss-cn-shenzhen.aliyuncs.com/vue.global.prod.min.js` + }, + { + name: 'vue-router', + var: 'VueRouter', + path: `https://type-words.oss-cn-shenzhen.aliyuncs.com/vue-router.global.prod.min.js` + }, + { + name: 'axios', + var: 'axios', + path: 'https://type-words.oss-cn-shenzhen.aliyuncs.com/axios.min.js' + }, + ] + }) ], define: { LATEST_COMMIT_HASH: JSON.stringify(latestCommitHash + (process.env.NODE_ENV === 'production' ? '' : ' (dev)')), @@ -73,11 +73,11 @@ export default defineConfig(() => { }, extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'] }, - // build: { - // rollupOptions: { - // external: ['axios'],// 使用全局的 axios。因为百度翻译库内部用了0.19版本的axios,会被打包到代码里面 - // } - // }, + build: { + rollupOptions: { + external: ['axios'],// 使用全局的 axios。因为百度翻译库内部用了0.19版本的axios,会被打包到代码里面 + } + }, css: { preprocessorOptions: { scss: { From 4d012d330639cbf1baa914fca2acc27f8dad9674 Mon Sep 17 00:00:00 2001 From: zyronon Date: Tue, 12 Aug 2025 23:11:23 +0800 Subject: [PATCH 36/92] =?UTF-8?q?feat:=E7=A7=BB=E9=99=A4ElMessage=E7=BB=84?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/pc/Setting.vue | 13 +++++++------ src/pages/pc/article/ArticleHomePage.vue | 9 +++++---- src/pages/pc/article/BatchEditArticlePage.vue | 6 +++--- src/pages/pc/article/StudyArticle.vue | 4 ++-- src/pages/pc/article/components/EditArticle.vue | 13 +++++++------ src/pages/pc/article/components/EditBook.vue | 13 +++++++------ src/pages/pc/article/components/QuestionForm.vue | 3 ++- src/pages/pc/article/components/TypingArticle.vue | 13 +++---------- src/pages/pc/components/BaseTable.vue | 5 +++-- src/pages/pc/word/DictDetail.vue | 13 +++++++------ src/pages/pc/word/StudyWord.vue | 6 +++--- src/utils/index.ts | 11 +++++------ 12 files changed, 54 insertions(+), 55 deletions(-) diff --git a/src/pages/pc/Setting.vue b/src/pages/pc/Setting.vue index 50d67cc0..2779b888 100644 --- a/src/pages/pc/Setting.vue +++ b/src/pages/pc/Setting.vue @@ -15,7 +15,8 @@ import {checkAndUpgradeSaveDict, checkAndUpgradeSaveSetting, shakeCommonDict} fr import {GITHUB} from "@/config/ENV.ts"; import dayjs from "dayjs"; import BasePage from "@/pages/pc/components/BasePage.vue"; -import {ElSwitch, ElSelect, ElOption, ElSlider, ElRadioGroup, ElRadio, ElInputNumber,ElMessage} from 'element-plus' +import {ElSwitch, ElSelect, ElOption, ElSlider, ElRadioGroup, ElRadio, ElInputNumber} from 'element-plus' +import Toast from '@/pages/pc/components/Toast/Toast.ts' const emit = defineEmits<{ toggleDisabledDialogEscKey: [val: boolean] @@ -60,7 +61,7 @@ useEventListener('keydown', (e: KeyboardEvent) => { for (const [k, v] of Object.entries(settingStore.shortcutKeyMap)) { if (v === shortcutKey && k !== editShortcutKey) { settingStore.shortcutKeyMap[editShortcutKey] = DefaultShortcutKeyMap[editShortcutKey] - return ElMessage.warning('快捷键重复!') + return Toast.warning('快捷键重复!') } } settingStore.shortcutKeyMap[editShortcutKey] = shortcutKey @@ -71,7 +72,7 @@ useEventListener('keydown', (e: KeyboardEvent) => { function resetShortcutKeyMap() { editShortcutKey = '' settingStore.shortcutKeyMap = cloneDeep(DefaultShortcutKeyMap) - ElMessage.success('恢复成功') + Toast.success('恢复成功') } function exportData() { @@ -90,7 +91,7 @@ function exportData() { } let blob = new Blob([JSON.stringify(data)], {type: "text/plain;charset=utf-8"}); saveAs(blob, `${APP_NAME}-User-Data-${dayjs().format('YYYY-MM-DD HH-mm-ss')}.json`); - ElMessage.success('导出成功!') + Toast.success('导出成功!') } function importData(e) { @@ -115,9 +116,9 @@ function importData(e) { settingStore.setState(settingState) let baseState = checkAndUpgradeSaveDict(data.dict) store.setState(baseState) - ElMessage.success('导入成功!') + Toast.success('导入成功!') } catch (err) { - return ElMessage.error('导入失败!') + return Toast.error('导入失败!') } } } diff --git a/src/pages/pc/article/ArticleHomePage.vue b/src/pages/pc/article/ArticleHomePage.vue index 52957e03..0aad0c70 100644 --- a/src/pages/pc/article/ArticleHomePage.vue +++ b/src/pages/pc/article/ArticleHomePage.vue @@ -8,7 +8,8 @@ import {DictResource, DictType} from "@/types/types.ts"; import {useRuntimeStore} from "@/stores/runtime.ts"; import BaseIcon from "@/components/BaseIcon.vue"; import Book from "@/pages/pc/components/Book.vue"; -import {ElMessage, ElProgress} from 'element-plus'; +import {ElProgress} from 'element-plus'; +import Toast from '@/pages/pc/components/Toast/Toast.ts' import BaseButton from "@/components/BaseButton.vue"; import PopConfirm from "@/pages/pc/components/PopConfirm.vue"; import {onMounted, watch} from "vue"; @@ -34,7 +35,7 @@ async function init() { function startStudy() { if (base.sbook.id) { if (!base.sbook.articles.length) { - return ElMessage.warning('没有文章可学习!') + return Toast.warning('没有文章可学习!') } window.umami?.track('startStudyArticle', { name: base.sbook.name, @@ -45,7 +46,7 @@ function startStudy() { nav('/study-article') } else { window.umami?.track('no-book') - ElMessage.warning('请先选择一本书籍') + Toast.warning('请先选择一本书籍') } } @@ -66,7 +67,7 @@ function handleBatchDel() { } }) selectIds = [] - ElMessage.success("删除成功!") + Toast.success("删除成功!") } function toggleSelect(item) { diff --git a/src/pages/pc/article/BatchEditArticlePage.vue b/src/pages/pc/article/BatchEditArticlePage.vue index 46e22036..4c82384c 100644 --- a/src/pages/pc/article/BatchEditArticlePage.vue +++ b/src/pages/pc/article/BatchEditArticlePage.vue @@ -13,7 +13,7 @@ import {useRuntimeStore} from "@/stores/runtime.ts"; import {nanoid} from "nanoid"; import EditArticle from "@/pages/pc/article/components/EditArticle.vue"; import BaseIcon from "@/components/BaseIcon.vue"; -import {ElMessage} from "element-plus"; +import Toast from '@/pages/pc/components/Toast/Toast.ts' import {getDefaultArticle} from "@/types/func.ts"; const emit = defineEmits<{ @@ -111,7 +111,7 @@ function saveArticle(val: Article): boolean { } else { let has = runtimeStore.editDict.articles.find((item: Article) => item.title === val.title) if (has) { - ElMessage.error('已存在同名文章!') + Toast.error('已存在同名文章!') return false } val.id = nanoid(6) @@ -122,7 +122,7 @@ function saveArticle(val: Article): boolean { } article = cloneDeep(val) //TODO 保存完成后滚动到对应位置 - ElMessage.success('保存成功!') + Toast.success('保存成功!') syncBookInMyStudyList() return true } diff --git a/src/pages/pc/article/StudyArticle.vue b/src/pages/pc/article/StudyArticle.vue index 6ad5b7b8..0f29680d 100644 --- a/src/pages/pc/article/StudyArticle.vue +++ b/src/pages/pc/article/StudyArticle.vue @@ -7,7 +7,7 @@ import {useSettingStore} from "@/stores/setting.ts"; import {Article, ArticleItem, ArticleWord, ShortcutKey, Word} from "@/types/types.ts"; import {useOnKeyboardEventListener, useStartKeyboardEventListener} from "@/hooks/event.ts"; import useTheme from "@/hooks/theme.ts"; -import {ElMessage} from "element-plus"; +import Toast from '@/pages/pc/components/Toast/Toast.ts' import {cloneDeep} from "@/utils"; import {usePracticeStore} from "@/stores/practice.ts"; import {useArticleOptions} from "@/hooks/dict.ts"; @@ -58,7 +58,7 @@ function repeat() { function prev() { // console.log('next') if (store.sbook.lastLearnIndex === 0) { - ElMessage.warning('已经在第一章了~') + Toast.warning('已经在第一章了~') } else { store.sbook.lastLearnIndex-- getCurrentPractice() diff --git a/src/pages/pc/article/components/EditArticle.vue b/src/pages/pc/article/components/EditArticle.vue index 035edcfa..114862a2 100644 --- a/src/pages/pc/article/components/EditArticle.vue +++ b/src/pages/pc/article/components/EditArticle.vue @@ -9,7 +9,8 @@ import {genArticleSectionData, splitCNArticle2, splitEnArticle2, usePlaySentence import {_nextTick, _parseLRC, cloneDeep, last} from "@/utils"; import {watch} from "vue"; import Empty from "@/components/Empty.vue"; -import {ElInputNumber, ElMessage, ElOption, ElPopover, ElSelect, ElUpload, UploadProps} from "element-plus"; +import {ElInputNumber, ElOption, ElPopover, ElSelect, ElUpload, UploadProps} from "element-plus"; +import Toast from '@/pages/pc/components/Toast/Toast.ts' import * as Comparison from "string-comparison" import BaseIcon from "@/components/BaseIcon.vue"; import Dialog from "@/pages/pc/components/dialog/Dialog.vue"; @@ -62,7 +63,7 @@ function apply(isHandle: boolean = true) { // text = `While it is yet to be seen what direction the second Trump administration will take globally in its China policy, VOA traveled to the main island of Mahe in Seychelles to look at how China and the U.S. have impacted the country, and how each is fairing in that competition for influence there.` // text = "It was Sunday. I never get up early on Sundays. I sometimes stay in bed until lunchtime. Last Sunday I got up very late. I looked out of the window. It was dark outside. 'What a day!' I thought. 'It's raining again.' Just then, the telephone rang. It was my aunt Lucy. 'I've just arrived by train,' she said. 'I'm coming to see you.'\n\n 'But I'm still having breakfast,' I said.\n\n 'What are you doing?' she asked.\n\n 'I'm having breakfast,' I repeated.\n\n 'Dear me,' she said. 'Do you always get up so late? It's one o'clock!'" editArticle.sections = [] - ElMessage.error('请填写原文!') + Toast.error('请填写原文!') return } failCount = genArticleSectionData(editArticle) @@ -91,10 +92,10 @@ function splitTranslateText() { //TODO async function startNetworkTranslate() { if (!editArticle.title.trim()) { - return ElMessage.error('请填写标题!') + return Toast.error('请填写标题!') } if (!editArticle.text.trim()) { - return ElMessage.error('请填写正文!') + return Toast.error('请填写正文!') } apply() //注意!!! @@ -132,11 +133,11 @@ function save(option: 'save' | 'saveAndNext') { editArticle.textTranslate = editArticle.textTranslate.trim() if (!editArticle.title) { - ElMessage.error('请填写标题!') + Toast.error('请填写标题!') return resolve(false) } if (!editArticle.text) { - ElMessage.error('请填写正文!') + Toast.error('请填写正文!') return resolve(false) } diff --git a/src/pages/pc/article/components/EditBook.vue b/src/pages/pc/article/components/EditBook.vue index 71dc593c..405474ab 100644 --- a/src/pages/pc/article/components/EditBook.vue +++ b/src/pages/pc/article/components/EditBook.vue @@ -3,7 +3,8 @@ import {Dict, DictId, DictType} from "@/types/types.ts"; import {cloneDeep} from "@/utils"; -import {ElForm, ElFormItem, ElInput, ElSelect, ElOption, FormInstance, FormRules, ElMessage} from "element-plus"; +import {ElForm, ElFormItem, ElInput, ElSelect, ElOption, FormInstance, FormRules} from "element-plus"; +import Toast from '@/pages/pc/components/Toast/Toast.ts' import {onMounted, reactive} from "vue"; import {useRuntimeStore} from "@/stores/runtime.ts"; import {useBaseStore} from "@/stores/base.ts"; @@ -54,13 +55,13 @@ async function onSubmit() { if (props.isAdd) { data.id = 'custom-dict-' + Date.now() if (source.bookList.find(v => v.name === data.name)) { - ElMessage.warning('已有相同名称!') + Toast.warning('已有相同名称!') return } else { source.bookList.push(cloneDeep(data)) runtimeStore.editDict = data emit('submit') - ElMessage.success('添加成功') + Toast.success('添加成功') } } else { let rIndex = source.bookList.findIndex(v => v.id === data.id) @@ -68,15 +69,15 @@ async function onSubmit() { if (rIndex > -1) { source.bookList[rIndex] = cloneDeep(data) emit('submit') - ElMessage.success('修改成功') + Toast.success('修改成功') } else { source.bookList.push(cloneDeep(data)) - ElMessage.success('修改成功并加入我的词典') + Toast.success('修改成功并加入我的词典') } } console.log('submit!', data) } else { - ElMessage.warning('请填写完整') + Toast.warning('请填写完整') } }) } diff --git a/src/pages/pc/article/components/QuestionForm.vue b/src/pages/pc/article/components/QuestionForm.vue index 015b7985..ccb962a5 100644 --- a/src/pages/pc/article/components/QuestionForm.vue +++ b/src/pages/pc/article/components/QuestionForm.vue @@ -45,6 +45,7 @@ diff --git a/src/pages/pc/article/components/TypingArticle.vue b/src/pages/pc/article/components/TypingArticle.vue index 90f70c68..54c2e906 100644 --- a/src/pages/pc/article/components/TypingArticle.vue +++ b/src/pages/pc/article/components/TypingArticle.vue @@ -13,7 +13,7 @@ import {getTranslateText} from "@/hooks/article.ts"; import BaseButton from "@/components/BaseButton.vue"; import QuestionForm from "@/pages/pc/article/components/QuestionForm.vue"; import {getDefaultArticle} from "@/types/func.ts"; -import {ElMessage} from "element-plus"; +import Toast from '@/pages/pc/components/Toast/Toast.ts' interface IProps { article: Article, @@ -319,10 +319,7 @@ function onContextMenu(e: MouseEvent, sentence: Sentence, i, j) { label: "复制", onClick: () => { navigator.clipboard.writeText(sentence.text).then(r => { - ElMessage({ - message: '已复制', - type: 'success', - }) + Toast.success('已复制') }) } }, @@ -330,11 +327,7 @@ function onContextMenu(e: MouseEvent, sentence: Sentence, i, j) { label: "语法分析", onClick: () => { navigator.clipboard.writeText(sentence.text).then(r => { - ElMessage({ - message: '已复制!随后将打开语法分析网站!', - type: 'success', - duration: 3000 - }) + Toast.success('已复制!随后将打开语法分析网站!') setTimeout(() => { window.open('https://enpuz.com/') }, 1000) diff --git a/src/pages/pc/components/BaseTable.vue b/src/pages/pc/components/BaseTable.vue index ea6a49d0..6efbc47b 100644 --- a/src/pages/pc/components/BaseTable.vue +++ b/src/pages/pc/components/BaseTable.vue @@ -11,6 +11,7 @@ import PopConfirm from "@/pages/pc/components/PopConfirm.vue"; import Empty from "@/components/Empty.vue"; import {Icon} from "@iconify/vue"; import {ElCheckbox, ElPagination} from 'element-plus' +import Toast from '@/pages/pc/components/Toast/Toast.ts' let list = defineModel('list') @@ -94,11 +95,11 @@ let showSearchInput = $ref(false) function sort(type: Sort) { if (type === Sort.reverse) { - ElMessage.success('已翻转排序') + Toast.success('已翻转排序') list.value = reverse(cloneDeep(list.value)) } if (type === Sort.random) { - ElMessage.success('已随机排序') + Toast.success('已随机排序') list.value = shuffle(cloneDeep(list.value)) } showSortDialog = false diff --git a/src/pages/pc/word/DictDetail.vue b/src/pages/pc/word/DictDetail.vue index 742120ad..496db6a0 100644 --- a/src/pages/pc/word/DictDetail.vue +++ b/src/pages/pc/word/DictDetail.vue @@ -10,7 +10,8 @@ import BaseIcon from "@/components/BaseIcon.vue"; import BaseTable from "@/pages/pc/components/BaseTable.vue"; import WordItem from "@/pages/pc/components/WordItem.vue"; import type {FormInstance, FormRules} from "element-plus"; -import {ElForm, ElFormItem, ElInput, ElMessage} from "element-plus"; +import {ElForm, ElFormItem, ElInput} from "element-plus"; +import Toast from '@/pages/pc/components/Toast/Toast.ts' import PopConfirm from "@/pages/pc/components/PopConfirm.vue"; import BackIcon from "@/pages/pc/components/BackIcon.vue"; import BaseButton from "@/components/BaseButton.vue"; @@ -88,9 +89,9 @@ async function onSubmitWord() { let r = list.find(v => v.id === data.id) if (r) { Object.assign(r, data) - ElMessage.success('修改成功') + Toast.success('修改成功') } else { - ElMessage.success('修改失败,未找到单词') + Toast.success('修改失败,未找到单词') return } } else { @@ -98,15 +99,15 @@ async function onSubmitWord() { data.checked = false let r = list.find(v => v.word === wordForm.word) if (r) { - ElMessage.warning('已有相同名称单词!') + Toast.warning('已有相同名称单词!') return } else list.push(data) - ElMessage.success('添加成功') + Toast.success('添加成功') wordForm = getDefaultFormWord() } syncDictInMyStudyList() } else { - ElMessage.warning('请填写完整') + Toast.warning('请填写完整') } }) } diff --git a/src/pages/pc/word/StudyWord.vue b/src/pages/pc/word/StudyWord.vue index dc2ab7a1..9698267e 100644 --- a/src/pages/pc/word/StudyWord.vue +++ b/src/pages/pc/word/StudyWord.vue @@ -23,7 +23,7 @@ import Empty from "@/components/Empty.vue"; import {useBaseStore} from "@/stores/base.ts"; import {usePracticeStore} from "@/stores/practice.ts"; import {dictionaryResources} from "@/assets/dictionary.ts"; -import {ElMessage} from "element-plus"; +import Toast from '@/pages/pc/components/Toast/Toast.ts' import {getDefaultWord} from "@/types/func.ts"; import ConflictNotice from "@/pages/pc/components/ConflictNotice.vue"; @@ -100,7 +100,7 @@ watch(() => studyData, () => { data.words = studyData.write statStore.step = 4 } else { - ElMessage.warning('没有可学习的单词!') + Toast.warning('没有可学习的单词!') router.push('/word') } } @@ -275,7 +275,7 @@ function repeat() { function prev() { if (data.index === 0) { - ElMessage.warning('已经是第一个了~') + Toast.warning('已经是第一个了~') } else { data.index-- } diff --git a/src/utils/index.ts b/src/utils/index.ts index e7a41b9a..18128168 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -4,17 +4,16 @@ import {getDefaultSettingState} from "@/stores/setting.ts"; import {Dict, DictId, DictResource, DictType} from "@/types/types.ts"; import {useRouter} from "vue-router"; import {useRuntimeStore} from "@/stores/runtime.ts"; -import {nanoid} from "nanoid"; import dayjs from 'dayjs' import axios from "axios"; import {env} from "@/config/ENV.ts"; import {nextTick} from "vue"; import {dictionaryResources, enArticle} from "@/assets/dictionary.ts"; -import {ElMessage} from "element-plus"; +import Toast from '@/pages/pc/components/Toast/Toast.ts' import {getDefaultArticle, getDefaultDict, getDefaultWord} from "@/types/func.ts"; export function no() { - ElMessage.warning('未现实') + Toast.warning('未现实') } //检测多余字段,防止人为删除数据,导致数据不完整报错 @@ -52,7 +51,7 @@ export function checkAndUpgradeSaveDict(val: any) { } else { if (version === 3) { localStorage.setItem('type-word-dict-v3',JSON.stringify(state)) - + let studyDictId = '' if (state.current.index >= 0) { let dict = state.myDictList[state.current.index] @@ -151,7 +150,7 @@ export function checkAndUpgradeSaveDict(val: any) { if (r) { formatWord(v) let dict = getDefaultDict(r) - checkRiskKey(dict, v) + checkRiskKey(dict, v) dict.id = r.id defaultState.word.bookList.push(dict) if (currentDictId === studyDictId) defaultState.word.studyIndex = defaultState.word.bookList.length - 1 @@ -172,7 +171,7 @@ export function checkAndUpgradeSaveDict(val: any) { if (r) { formatWord(v) let dict = getDefaultDict(r) - checkRiskKey(dict, v) + checkRiskKey(dict, v) dict.id = r.id defaultState.article.bookList.push(dict) if (currentDictId === studyDictId) defaultState.article.studyIndex = defaultState.article.bookList.length - 1 From 85eb786e5954e2382fa6c83b97f53574a111ffc9 Mon Sep 17 00:00:00 2001 From: zyronon Date: Tue, 12 Aug 2025 23:36:43 +0800 Subject: [PATCH 37/92] =?UTF-8?q?feat:=E7=A7=BB=E9=99=A4ElProgress?= =?UTF-8?q?=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/css/style.scss | 8 +- src/pages/pc/article/ArticleHomePage.vue | 4 +- src/pages/pc/components/Book.vue | 9 +- src/pages/pc/components/Progress.vue | 103 +++++++++++++++++++++++ src/pages/pc/word/WordHomePage.vue | 5 +- src/pages/pc/word/components/Footer.vue | 25 ++---- src/vite-env.d.ts | 3 - 7 files changed, 126 insertions(+), 31 deletions(-) create mode 100644 src/pages/pc/components/Progress.vue diff --git a/src/assets/css/style.scss b/src/assets/css/style.scss index 5ab4b294..28e99401 100644 --- a/src/assets/css/style.scss +++ b/src/assets/css/style.scss @@ -61,12 +61,12 @@ //修改element-ui的进度条底色 - --el-border-color-lighter: #d1d5df !important; + --color-progress-bar: #d1d5df !important; } .footer { &.hide { - --el-border-color-lighter: #dbdbdb !important; + --color-progress-bar: #dbdbdb !important; } } @@ -104,11 +104,11 @@ html.dark { --color-textarea-bg: rgb(43, 45, 48); --color-article: white; - --el-border-color-lighter: rgb(73, 77, 82) !important; + --color-progress-bar: rgb(73, 77, 82) !important; .footer { &.hide { - --el-border-color-lighter: var(--color-third) !important; + --color-progress-bar: var(--color-third) !important; } } } diff --git a/src/pages/pc/article/ArticleHomePage.vue b/src/pages/pc/article/ArticleHomePage.vue index 0aad0c70..34ebef38 100644 --- a/src/pages/pc/article/ArticleHomePage.vue +++ b/src/pages/pc/article/ArticleHomePage.vue @@ -8,7 +8,7 @@ import {DictResource, DictType} from "@/types/types.ts"; import {useRuntimeStore} from "@/stores/runtime.ts"; import BaseIcon from "@/components/BaseIcon.vue"; import Book from "@/pages/pc/components/Book.vue"; -import {ElProgress} from 'element-plus'; +import Progress from '@/pages/pc/components/Progress.vue'; import Toast from '@/pages/pc/components/Toast/Toast.ts' import BaseButton from "@/components/BaseButton.vue"; import PopConfirm from "@/pages/pc/components/PopConfirm.vue"; @@ -110,7 +110,7 @@ async function goBookDetail(val: DictResource) {
已学习{{ base.currentBook.lastLearnIndex }}篇文章
- +
diff --git a/src/pages/pc/components/Book.vue b/src/pages/pc/components/Book.vue index 90172091..cff57a14 100644 --- a/src/pages/pc/components/Book.vue +++ b/src/pages/pc/components/Book.vue @@ -1,7 +1,8 @@ + + + + diff --git a/src/pages/pc/word/WordHomePage.vue b/src/pages/pc/word/WordHomePage.vue index 279412f3..c0dd4379 100644 --- a/src/pages/pc/word/WordHomePage.vue +++ b/src/pages/pc/word/WordHomePage.vue @@ -12,7 +12,8 @@ import {getCurrentStudyWord} from "@/hooks/dict.ts"; import {useRuntimeStore} from "@/stores/runtime.ts"; import Book from "@/pages/pc/components/Book.vue"; import PopConfirm from "@/pages/pc/components/PopConfirm.vue"; -import {ElProgress, ElSlider} from 'element-plus'; +import {ElSlider} from 'element-plus'; +import Progress from '@/pages/pc/components/Progress.vue'; import Toast from '@/pages/pc/components/Toast/Toast.ts'; import BaseButton from "@/components/BaseButton.vue"; import {getDefaultDict} from "@/types/func.ts"; @@ -146,7 +147,7 @@ const progressTextRight = $computed(() => { {{ progressTextLeft }} {{ progressTextRight }} / {{ store.sdict.words.length }}
- +
预计完成日期:{{ _getAccomplishDate(store.sdict.words.length, store.sdict.perDayStudyNumber) }} diff --git a/src/pages/pc/word/components/Footer.vue b/src/pages/pc/word/components/Footer.vue index d7e93e32..f2a43be3 100644 --- a/src/pages/pc/word/components/Footer.vue +++ b/src/pages/pc/word/components/Footer.vue @@ -1,13 +1,13 @@ + + + + diff --git a/src/pages/pc/components/Toast/Toast.ts b/src/pages/pc/components/Toast/Toast.ts index ff20c34d..12db21b6 100644 --- a/src/pages/pc/components/Toast/Toast.ts +++ b/src/pages/pc/components/Toast/Toast.ts @@ -87,7 +87,7 @@ const Toast: ToastService = (options: ToastOptions | string): ToastInstance => { instance, offset: 0 } - + toastContainers.push(toastContainer) updateToastPositions() diff --git a/src/pages/pc/components/Toast/Toast.vue b/src/pages/pc/components/Toast/Toast.vue index fd975be9..a82a3be9 100644 --- a/src/pages/pc/components/Toast/Toast.vue +++ b/src/pages/pc/components/Toast/Toast.vue @@ -1,19 +1,19 @@ + + + + diff --git a/src/pages/pc/components/Select/Select.vue b/src/pages/pc/components/Select/Select.vue new file mode 100644 index 00000000..048fa247 --- /dev/null +++ b/src/pages/pc/components/Select/Select.vue @@ -0,0 +1,311 @@ + + + + + diff --git a/src/pages/pc/components/Select/index.ts b/src/pages/pc/components/Select/index.ts new file mode 100644 index 00000000..7fb7d4b1 --- /dev/null +++ b/src/pages/pc/components/Select/index.ts @@ -0,0 +1,5 @@ +import Select from './Select.vue'; +import Option from './Option.vue'; + +export {Select, Option}; +export default Select; From b0a10d520c93d30d0665d87e2b713c2c5f00da31 Mon Sep 17 00:00:00 2001 From: zyronon Date: Wed, 13 Aug 2025 01:59:38 +0800 Subject: [PATCH 40/92] =?UTF-8?q?feat:=E7=A7=BB=E9=99=A4ElSwitch=E7=BB=84?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/pc/Setting.vue | 18 ++--- src/pages/pc/components/Switch.vue | 110 +++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 9 deletions(-) create mode 100644 src/pages/pc/components/Switch.vue diff --git a/src/pages/pc/Setting.vue b/src/pages/pc/Setting.vue index 2b7a7fd6..f26a852b 100644 --- a/src/pages/pc/Setting.vue +++ b/src/pages/pc/Setting.vue @@ -14,9 +14,10 @@ import {saveAs} from "file-saver"; import {GITHUB} from "@/config/ENV.ts"; import dayjs from "dayjs"; import BasePage from "@/pages/pc/components/BasePage.vue"; -import {ElInputNumber, ElRadio, ElRadioGroup, ElSlider, ElSwitch} from 'element-plus' +import {ElInputNumber, ElRadio, ElRadioGroup, ElSlider} from 'element-plus' import Toast from '@/pages/pc/components/Toast/Toast.ts' import {Option, Select} from "@/pages/pc/components/Select"; +import Switch from "@/pages/pc/components/Switch.vue"; const emit = defineEmits<{ toggleDisabledDialogEscKey: [val: boolean] @@ -163,9 +164,8 @@ function importData(e) {
- @@ -175,7 +175,7 @@ function importData(e) {
-
-
-
-
-
- +import {ref, computed, defineProps, defineEmits, watch} from 'vue'; + +const props = defineProps<{ + modelValue: boolean; + disabled?: boolean; + width?: number; // 开关宽度,默认 40px + activeText?: string; // 开启状态显示文字 + inactiveText?: string;// 关闭状态显示文字 +}>(); + +const emit = defineEmits(['update:modelValue']); + +const isChecked = ref(props.modelValue); + +watch(() => props.modelValue, (val) => { + isChecked.value = val; +}); + +const toggle = () => { + if (props.disabled) return; + isChecked.value = !isChecked.value; + emit('update:modelValue', isChecked.value); +}; + +const onKeydown = (e: KeyboardEvent) => { + if (e.code === 'Space' || e.key === ' ') { + e.preventDefault(); + toggle(); + } +}; + +const switchWidth = computed(() => props.width ?? 40); +const switchHeight = computed(() => (switchWidth.value / 2) | 0); +const ballSize = computed(() => switchHeight.value - 4); + + + + + From 47bc29adb79d6c1c6b65ecd8038aaac2e09a32ae Mon Sep 17 00:00:00 2001 From: zyronon Date: Wed, 13 Aug 2025 02:07:02 +0800 Subject: [PATCH 41/92] =?UTF-8?q?feat:=E7=A7=BB=E5=8A=A8=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/pc/Setting.vue | 6 +++--- src/pages/pc/article/ArticleHomePage.vue | 4 ++-- src/pages/pc/article/BatchEditArticlePage.vue | 2 +- src/pages/pc/article/StudyArticle.vue | 2 +- src/pages/pc/article/components/EditArticle.vue | 4 ++-- src/pages/pc/article/components/EditBook.vue | 4 ++-- src/pages/pc/article/components/QuestionForm.vue | 2 +- src/pages/pc/article/components/TypingArticle.vue | 2 +- src/pages/pc/components/BaseTable.vue | 4 ++-- src/pages/pc/components/Book.vue | 2 +- src/pages/pc/components/{ => base}/Pagination.vue | 0 src/pages/pc/components/{ => base}/Progress.vue | 0 src/pages/pc/components/{ => base}/Switch.vue | 0 src/pages/pc/components/{Select => base/select}/Option.vue | 0 src/pages/pc/components/{Select => base/select}/Select.vue | 2 +- src/pages/pc/components/{Select => base/select}/index.ts | 0 src/pages/pc/components/{Toast => base/toast}/Toast.ts | 4 ++-- src/pages/pc/components/{Toast => base/toast}/Toast.vue | 0 src/pages/pc/components/{Toast => base/toast}/type.ts | 0 src/pages/pc/word/DictDetail.vue | 2 +- src/pages/pc/word/StudyWord.vue | 2 +- src/pages/pc/word/WordHomePage.vue | 4 ++-- src/pages/pc/word/components/Footer.vue | 2 +- src/utils/index.ts | 2 +- 24 files changed, 25 insertions(+), 25 deletions(-) rename src/pages/pc/components/{ => base}/Pagination.vue (100%) rename src/pages/pc/components/{ => base}/Progress.vue (100%) rename src/pages/pc/components/{ => base}/Switch.vue (100%) rename src/pages/pc/components/{Select => base/select}/Option.vue (100%) rename src/pages/pc/components/{Select => base/select}/Select.vue (98%) rename src/pages/pc/components/{Select => base/select}/index.ts (100%) rename src/pages/pc/components/{Toast => base/toast}/Toast.ts (96%) rename src/pages/pc/components/{Toast => base/toast}/Toast.vue (100%) rename src/pages/pc/components/{Toast => base/toast}/type.ts (100%) diff --git a/src/pages/pc/Setting.vue b/src/pages/pc/Setting.vue index f26a852b..6a80c407 100644 --- a/src/pages/pc/Setting.vue +++ b/src/pages/pc/Setting.vue @@ -15,9 +15,9 @@ import {GITHUB} from "@/config/ENV.ts"; import dayjs from "dayjs"; import BasePage from "@/pages/pc/components/BasePage.vue"; import {ElInputNumber, ElRadio, ElRadioGroup, ElSlider} from 'element-plus' -import Toast from '@/pages/pc/components/Toast/Toast.ts' -import {Option, Select} from "@/pages/pc/components/Select"; -import Switch from "@/pages/pc/components/Switch.vue"; +import Toast from '@/pages/pc/components/base/toast/Toast.ts' +import {Option, Select} from "@/pages/pc/components/base/select"; +import Switch from "@/pages/pc/components/base/Switch.vue"; const emit = defineEmits<{ toggleDisabledDialogEscKey: [val: boolean] diff --git a/src/pages/pc/article/ArticleHomePage.vue b/src/pages/pc/article/ArticleHomePage.vue index 34ebef38..fa61f216 100644 --- a/src/pages/pc/article/ArticleHomePage.vue +++ b/src/pages/pc/article/ArticleHomePage.vue @@ -8,8 +8,8 @@ import {DictResource, DictType} from "@/types/types.ts"; import {useRuntimeStore} from "@/stores/runtime.ts"; import BaseIcon from "@/components/BaseIcon.vue"; import Book from "@/pages/pc/components/Book.vue"; -import Progress from '@/pages/pc/components/Progress.vue'; -import Toast from '@/pages/pc/components/Toast/Toast.ts' +import Progress from '@/pages/pc/components/base/Progress.vue'; +import Toast from '@/pages/pc/components/base/toast/Toast.ts' import BaseButton from "@/components/BaseButton.vue"; import PopConfirm from "@/pages/pc/components/PopConfirm.vue"; import {onMounted, watch} from "vue"; diff --git a/src/pages/pc/article/BatchEditArticlePage.vue b/src/pages/pc/article/BatchEditArticlePage.vue index 4c82384c..d31dbe01 100644 --- a/src/pages/pc/article/BatchEditArticlePage.vue +++ b/src/pages/pc/article/BatchEditArticlePage.vue @@ -13,7 +13,7 @@ import {useRuntimeStore} from "@/stores/runtime.ts"; import {nanoid} from "nanoid"; import EditArticle from "@/pages/pc/article/components/EditArticle.vue"; import BaseIcon from "@/components/BaseIcon.vue"; -import Toast from '@/pages/pc/components/Toast/Toast.ts' +import Toast from '@/pages/pc/components/base/toast/Toast.ts' import {getDefaultArticle} from "@/types/func.ts"; const emit = defineEmits<{ diff --git a/src/pages/pc/article/StudyArticle.vue b/src/pages/pc/article/StudyArticle.vue index 0f29680d..89e09613 100644 --- a/src/pages/pc/article/StudyArticle.vue +++ b/src/pages/pc/article/StudyArticle.vue @@ -7,7 +7,7 @@ import {useSettingStore} from "@/stores/setting.ts"; import {Article, ArticleItem, ArticleWord, ShortcutKey, Word} from "@/types/types.ts"; import {useOnKeyboardEventListener, useStartKeyboardEventListener} from "@/hooks/event.ts"; import useTheme from "@/hooks/theme.ts"; -import Toast from '@/pages/pc/components/Toast/Toast.ts' +import Toast from '@/pages/pc/components/base/toast/Toast.ts' import {cloneDeep} from "@/utils"; import {usePracticeStore} from "@/stores/practice.ts"; import {useArticleOptions} from "@/hooks/dict.ts"; diff --git a/src/pages/pc/article/components/EditArticle.vue b/src/pages/pc/article/components/EditArticle.vue index 56931d0d..a8c3e2bd 100644 --- a/src/pages/pc/article/components/EditArticle.vue +++ b/src/pages/pc/article/components/EditArticle.vue @@ -10,13 +10,13 @@ import {_nextTick, _parseLRC, cloneDeep, last} from "@/utils"; import {watch} from "vue"; import Empty from "@/components/Empty.vue"; import {ElInputNumber, ElOption, ElPopover, ElSelect} from "element-plus"; -import Toast from '@/pages/pc/components/Toast/Toast.ts' +import Toast from '@/pages/pc/components/base/toast/Toast.ts' import * as Comparison from "string-comparison" import BaseIcon from "@/components/BaseIcon.vue"; import Dialog from "@/pages/pc/components/dialog/Dialog.vue"; import {getDefaultArticle} from "@/types/func.ts"; import copy from "copy-to-clipboard"; -import {Option, Select} from "@/pages/pc/components/Select"; +import {Option, Select} from "@/pages/pc/components/base/select"; interface IProps { article?: Article, diff --git a/src/pages/pc/article/components/EditBook.vue b/src/pages/pc/article/components/EditBook.vue index 77ae0671..1db4b65d 100644 --- a/src/pages/pc/article/components/EditBook.vue +++ b/src/pages/pc/article/components/EditBook.vue @@ -4,13 +4,13 @@ import {Dict, DictId, DictType} from "@/types/types.ts"; import {cloneDeep} from "@/utils"; import {ElForm, ElFormItem, ElInput, FormInstance, FormRules} from "element-plus"; -import Toast from '@/pages/pc/components/Toast/Toast.ts' +import Toast from '@/pages/pc/components/base/toast/Toast.ts' import {onMounted, reactive} from "vue"; import {useRuntimeStore} from "@/stores/runtime.ts"; import {useBaseStore} from "@/stores/base.ts"; import BaseButton from "@/components/BaseButton.vue"; import {getDefaultDict} from "@/types/func.ts"; -import {Option, Select} from "@/pages/pc/components/Select"; +import {Option, Select} from "@/pages/pc/components/base/select"; const props = defineProps<{ isAdd: boolean, diff --git a/src/pages/pc/article/components/QuestionForm.vue b/src/pages/pc/article/components/QuestionForm.vue index ccb962a5..e6a6fcae 100644 --- a/src/pages/pc/article/components/QuestionForm.vue +++ b/src/pages/pc/article/components/QuestionForm.vue @@ -45,7 +45,7 @@ + + + + diff --git a/src/pages/pc/components/base/Slider.vue b/src/pages/pc/components/base/Slider.vue new file mode 100644 index 00000000..ba57ddde --- /dev/null +++ b/src/pages/pc/components/base/Slider.vue @@ -0,0 +1,236 @@ + + + + + diff --git a/src/pages/pc/components/list/ArticleList.vue b/src/pages/pc/components/list/ArticleList.vue index f2b204d9..4ea0604c 100644 --- a/src/pages/pc/components/list/ArticleList.vue +++ b/src/pages/pc/components/list/ArticleList.vue @@ -48,7 +48,7 @@ defineExpose({scrollToBottom, scrollToItem})