From 4f7ecbea29e43745acf8a4e764cc28a647231e36 Mon Sep 17 00:00:00 2001 From: Zyronon Date: Sun, 16 Nov 2025 20:53:32 +0800 Subject: [PATCH] save --- src/App.vue | 7 +-- src/components/BaseButton.vue | 19 ++++-- src/config/env.ts | 7 +-- src/pages/article/ArticlesPage.vue | 4 +- src/pages/article/BookDetail.vue | 4 +- src/pages/article/PracticeArticles.vue | 6 +- src/pages/article/components/EditBook.vue | 4 +- src/pages/setting/Setting.vue | 4 +- src/pages/user/User.vue | 1 + src/pages/word/DictDetail.vue | 4 +- src/pages/word/PracticeWords.vue | 20 +++--- src/pages/word/WordsPage.vue | 75 +++++++++++++---------- src/pages/word/components/Footer.vue | 28 ++++++--- src/pages/word/components/TypeWord.vue | 8 +++ src/stores/base.ts | 24 ++++---- src/stores/setting.ts | 14 ++--- src/utils/index.ts | 5 +- 17 files changed, 137 insertions(+), 97 deletions(-) diff --git a/src/App.vue b/src/App.vue index 758f7c8d..99dde4c5 100644 --- a/src/App.vue +++ b/src/App.vue @@ -5,14 +5,13 @@ import { useRuntimeStore } from "@/stores/runtime.ts"; import { useSettingStore } from "@/stores/setting.ts"; import useTheme from "@/hooks/theme.ts"; import { shakeCommonDict } from "@/utils"; -import { routes } from "@/router.ts"; import { get, set } from 'idb-keyval' import { useRoute } from "vue-router"; import { DictId } from "@/types/types.ts"; -import { APP_VERSION, CAN_REQUEST, LOCAL_FILE_KEY, SAVE_DICT_KEY, SAVE_SETTING_KEY } from "@/config/env.ts"; +import { APP_VERSION, AppEnv, LOCAL_FILE_KEY, SAVE_DICT_KEY, SAVE_SETTING_KEY } from "@/config/env.ts"; import { syncSetting } from "@/apis"; -import {useUserStore} from "@/stores/auth.ts"; +import { useUserStore } from "@/stores/auth.ts"; const store = useBaseStore() const runtimeStore = useRuntimeStore() @@ -53,7 +52,7 @@ watch(store.$state, (n: BaseState) => { watch(settingStore.$state, (n) => { set(SAVE_SETTING_KEY.key, JSON.stringify({val: n, version: SAVE_SETTING_KEY.version})) - if (CAN_REQUEST) { + if (AppEnv.CAN_REQUEST) { syncSetting(null, settingStore.$state) } }) diff --git a/src/components/BaseButton.vue b/src/components/BaseButton.vue index 53ca1a91..55cb3a45 100644 --- a/src/components/BaseButton.vue +++ b/src/components/BaseButton.vue @@ -98,19 +98,19 @@ defineEmits(['click']) } } - &:hover:not(.disabled) { - opacity: .6; - } - &.primary { background: var(--btn-primary); + + &:hover:not(.disabled) { + opacity: 0.6; + } } &.link { border-radius: 0; border-bottom: 2px solid transparent; - &:hover { + &:hover:not(.disabled) { border-bottom: 2px solid var(--color-font-2); } } @@ -119,11 +119,20 @@ defineEmits(['click']) background: var(--btn-info); border: 1px solid var(--color-main-text); color: var(--color-main-text); + + &:hover:not(.disabled) { + opacity: 0.6; + } } &.orange { background: #FACC15; color: black; + + &:hover:not(.disabled) { + background: #fbe27e; + color: rgba(0, 0, 0, 0.6); + } } &.active { diff --git a/src/config/env.ts b/src/config/env.ts index 445d1df4..2deac2bf 100644 --- a/src/config/env.ts +++ b/src/config/env.ts @@ -14,15 +14,10 @@ const map = { } export const ENV = Object.assign(map['DEV'], common) -// export const IS_OFFICIAL = import.meta.env.DEV -// export let IS_LOGIN = true -export let IS_OFFICIAL = true -export let IS_LOGIN = (!!localStorage.getItem('token')) || false -export let CAN_REQUEST = IS_LOGIN && IS_OFFICIAL export let AppEnv = { TOKEN: localStorage.getItem('token') ?? '', - IS_OFFICIAL: true, + IS_OFFICIAL: false, IS_LOGIN: false, CAN_REQUEST: false } diff --git a/src/pages/article/ArticlesPage.vue b/src/pages/article/ArticlesPage.vue index 88d1c98a..0918ef86 100644 --- a/src/pages/article/ArticlesPage.vue +++ b/src/pages/article/ArticlesPage.vue @@ -18,7 +18,7 @@ import dayjs from "dayjs"; import isBetween from "dayjs/plugin/isBetween"; import isoWeek from 'dayjs/plugin/isoWeek' import { useFetch } from "@vueuse/core"; -import { CAN_REQUEST, DICT_LIST, PracticeSaveArticleKey } from "@/config/env.ts"; +import { AppEnv, DICT_LIST, PracticeSaveArticleKey } from "@/config/env.ts"; import { myDictList } from "@/apis"; dayjs.extend(isoWeek) @@ -36,7 +36,7 @@ watch(() => store.load, n => { }, {immediate: true}) async function init() { - if (CAN_REQUEST) { + if (AppEnv.CAN_REQUEST) { let res = await myDictList({type: "article"}) if (res.success) { store.setState(Object.assign(store.$state, res.data)) diff --git a/src/pages/article/BookDetail.vue b/src/pages/article/BookDetail.vue index e6fd7e1b..d3afefdf 100644 --- a/src/pages/article/BookDetail.vue +++ b/src/pages/article/BookDetail.vue @@ -20,7 +20,7 @@ import ArticleAudio from "@/pages/article/components/ArticleAudio.vue"; import { MessageBox } from "@/utils/MessageBox.tsx"; import { useSettingStore } from "@/stores/setting.ts"; import { useFetch } from "@vueuse/core"; -import { CAN_REQUEST, DICT_LIST } from "@/config/env.ts"; +import { AppEnv, DICT_LIST } from "@/config/env.ts"; import { detail } from "@/apis"; const runtimeStore = useRuntimeStore() @@ -93,7 +93,7 @@ async function init() { } if (base.article.bookList.find(book => book.id === runtimeStore.editDict.id)) { - if (CAN_REQUEST) { + if (AppEnv.CAN_REQUEST) { let res = await detail({id: runtimeStore.editDict.id}) if (res.success) { runtimeStore.editDict.statistics = res.data.statistics diff --git a/src/pages/article/PracticeArticles.vue b/src/pages/article/PracticeArticles.vue index e7de59ff..ad5b94b3 100644 --- a/src/pages/article/PracticeArticles.vue +++ b/src/pages/article/PracticeArticles.vue @@ -34,7 +34,7 @@ import { useRoute, useRouter } from "vue-router"; import PracticeLayout from "@/components/PracticeLayout.vue"; import ArticleAudio from "@/pages/article/components/ArticleAudio.vue"; import VolumeSetting from "@/pages/article/components/VolumeSetting.vue"; -import { CAN_REQUEST, DICT_LIST, PracticeSaveArticleKey } from "@/config/env.ts"; +import { AppEnv, DICT_LIST, PracticeSaveArticleKey } from "@/config/env.ts"; import { addStat, setDictProp } from "@/apis"; import { useRuntimeStore } from "@/stores/runtime.ts"; @@ -254,7 +254,7 @@ async function complete() { wrong: statStore.wrong, } - if (CAN_REQUEST) { + if (AppEnv.CAN_REQUEST) { let res = await addStat({...data, type: 'article'}) if (!res.success) { Toast.error(res.msg) @@ -337,7 +337,7 @@ async function changeArticle(val: ArticleItem) { store.sbook.lastLearnIndex = rIndex getCurrentPractice() - if (CAN_REQUEST) { + if (AppEnv.CAN_REQUEST) { let res = await setDictProp(null, store.sbook) if (!res.success) { Toast.error(res.msg) diff --git a/src/pages/article/components/EditBook.vue b/src/pages/article/components/EditBook.vue index fbfe96be..ad510912 100644 --- a/src/pages/article/components/EditBook.vue +++ b/src/pages/article/components/EditBook.vue @@ -12,8 +12,8 @@ import { Option, Select } from "@/components/base/select"; import BaseInput from "@/components/base/BaseInput.vue"; import Form from "@/components/base/form/Form.vue"; import FormItem from "@/components/base/form/FormItem.vue"; -import { CAN_REQUEST } from "@/config/env.ts"; import { addDict } from "@/apis"; +import { AppEnv } from "@/config/env.ts"; const props = defineProps<{ isAdd: boolean, @@ -58,7 +58,7 @@ async function onSubmit() { Toast.warning('已有相同名称!') return } else { - if (CAN_REQUEST) { + if (AppEnv.CAN_REQUEST) { loading = true let res = await addDict(null, data) loading = false diff --git a/src/pages/setting/Setting.vue b/src/pages/setting/Setting.vue index 89d93b20..1afc54c2 100644 --- a/src/pages/setting/Setting.vue +++ b/src/pages/setting/Setting.vue @@ -728,7 +728,7 @@ function importOldData() {
  1. 智能模式优化
    -
    练习时新增四种练习模式:学习、复习、听写、默写。
    +
    练习时新增四种练习模式:学习、辨认、听写、默写。
  2. 学习模式
    @@ -741,7 +741,7 @@ function importOldData() {
  3. -
    复习模式(新增)
    +
    辨认模式(新增)
    • 仅在复习已学单词时出现。
    • diff --git a/src/pages/user/User.vue b/src/pages/user/User.vue index 19bd2cd0..29b5da90 100644 --- a/src/pages/user/User.vue +++ b/src/pages/user/User.vue @@ -490,6 +490,7 @@ function subscribe() { :placeholder="`请输入新密码(${PASSWORD_CONFIG.minLength}-${PASSWORD_CONFIG.maxLength}位)`" :min="PASSWORD_CONFIG.minLength" :max="PASSWORD_CONFIG.maxLength" + autofocus /> diff --git a/src/pages/word/DictDetail.vue b/src/pages/word/DictDetail.vue index 345960ed..5cbc62fb 100644 --- a/src/pages/word/DictDetail.vue +++ b/src/pages/word/DictDetail.vue @@ -26,7 +26,7 @@ import { getCurrentStudyWord } from "@/hooks/dict.ts"; import PracticeSettingDialog from "@/pages/word/components/PracticeSettingDialog.vue"; import { useSettingStore } from "@/stores/setting.ts"; import { MessageBox } from "@/utils/MessageBox.tsx"; -import { CAN_REQUEST, Origin, PracticeSaveWordKey } from "@/config/env.ts"; +import { AppEnv, Origin, PracticeSaveWordKey } from "@/config/env.ts"; import { detail } from "@/apis"; const runtimeStore = useRuntimeStore() @@ -196,7 +196,7 @@ onMounted(async () => { } if (base.word.bookList.find(book => book.id === runtimeStore.editDict.id)) { - if (CAN_REQUEST) { + if (AppEnv.CAN_REQUEST) { let res = await detail({id: runtimeStore.editDict.id}) if (res.success) { runtimeStore.editDict.statistics = res.data.statistics diff --git a/src/pages/word/PracticeWords.vue b/src/pages/word/PracticeWords.vue index 0839bbd5..06ad9763 100644 --- a/src/pages/word/PracticeWords.vue +++ b/src/pages/word/PracticeWords.vue @@ -248,9 +248,7 @@ function goNextStep(originList, mode, msg) { } async function next(isTyping: boolean = true) { - if (isTyping) { - statStore.inputWordNumber++ - } + if (isTyping) statStore.inputWordNumber++ if (settingStore.wordPracticeMode === WordPracticeMode.Free) { if (data.index === data.words.length - 1) { data.wrongWords = data.wrongWords.filter(v => (!data.excludeWords.includes(v.word))) @@ -310,9 +308,9 @@ async function next(isTyping: boolean = true) { return goNextStep(shuffle(taskWords.write), WordPracticeType.Listen, '开始听写之前') } - //开始复写之前 + //开始辨认之前 if (statStore.step === 5) { - return goNextStep(taskWords.write, WordPracticeType.Identify, '开始复写之前') + return goNextStep(taskWords.write, WordPracticeType.Identify, '开始辨认之前') } //开始默写上次 @@ -325,9 +323,9 @@ async function next(isTyping: boolean = true) { return goNextStep(shuffle(taskWords.review), WordPracticeType.Listen, '开始听写上次') } - //开始复写昨日 + //开始辨认昨日 if (statStore.step === 2) { - return goNextStep(taskWords.review, WordPracticeType.Identify, '开始复写昨日') + return goNextStep(taskWords.review, WordPracticeType.Identify, '开始辨认昨日') } //开始默写新词 @@ -352,6 +350,13 @@ async function next(isTyping: boolean = true) { savePracticeData() } +function skipStep(){ + data.index = data.words.length - 1 + settingStore.wordPracticeType = WordPracticeType.Spell + data.wrongWords = [] + next(false) +} + function onWordKnow() { //标记模式时,用户认识的单词加入到排除里面,后续不再复习 let rIndex = data.excludeWords.findIndex(v => v === word.word) @@ -649,6 +654,7 @@ useEvents([ :is-collect="isWordCollect(word)" @toggle-collect="toggleWordCollect(word)" @skip="next(false)" + @skipStep="skipStep" /> diff --git a/src/pages/word/WordsPage.vue b/src/pages/word/WordsPage.vue index 80db19da..66c2491d 100644 --- a/src/pages/word/WordsPage.vue +++ b/src/pages/word/WordsPage.vue @@ -19,11 +19,10 @@ import PracticeSettingDialog from "@/pages/word/components/PracticeSettingDialog import ChangeLastPracticeIndexDialog from "@/pages/word/components/ChangeLastPracticeIndexDialog.vue"; import { useSettingStore } from "@/stores/setting.ts"; import { useFetch } from "@vueuse/core"; -import { CAN_REQUEST, DICT_LIST, PracticeSaveWordKey } from "@/config/env.ts"; +import { AppEnv, DICT_LIST, PracticeSaveWordKey } from "@/config/env.ts"; import { myDictList } from "@/apis"; import PracticeWordListDialog from "@/pages/word/components/PracticeWordListDialog.vue"; import ShufflePracticeSettingDialog from "@/pages/word/components/ShufflePracticeSettingDialog.vue"; -import Header from "@/components/Header.vue"; const store = useBaseStore() @@ -45,7 +44,7 @@ watch(() => store.load, n => { }, {immediate: true}) async function init() { - if (CAN_REQUEST) { + if (AppEnv.CAN_REQUEST) { let res = await myDictList({type: "word"}) if (res.success) { store.setState(Object.assign(store.$state, res.data)) @@ -262,12 +261,12 @@ const {
      -
      +
      - {{ isSaveData ? '上次学习任务' : '今日任务' }} + {{ isSaveData ? '上次任务' : '今日任务' }}
      -
      + class="w-full flex box-border cp color-white"> +
      {{ isSaveData ? '继续学习' : '开始学习' }}
      + class="w-10 rounded-r-lg h-full center bg-[var(--btn-primary)] hover:bg-gray border-solid border-2 border-l-gray border-transparent box-border">
      - -
      - 随机复习 - -
      -
      +
      + +
      + 随机复习 + +
      +
      +
      +
      + +
      + 重新学习 + +
      +
      +
      - -
      - - - -
      - 随机复习 - -
      -
      + + + + + + + + + +
      diff --git a/src/pages/word/components/Footer.vue b/src/pages/word/components/Footer.vue index e6bfb2b4..1349d749 100644 --- a/src/pages/word/components/Footer.vue +++ b/src/pages/word/components/Footer.vue @@ -3,7 +3,7 @@ import { inject, Ref, watch } from "vue" import { usePracticeStore } from "@/stores/practice.ts"; import { useSettingStore } from "@/stores/setting.ts"; -import {PracticeData, WordPracticeType, ShortcutKey, TaskWords} from "@/types/types.ts"; +import { PracticeData, WordPracticeType, ShortcutKey, TaskWords } from "@/types/types.ts"; import BaseIcon from "@/components/BaseIcon.vue"; import Tooltip from "@/components/base/Tooltip.vue"; import Progress from '@/components/base/Progress.vue' @@ -22,6 +22,7 @@ const emit = defineEmits<{ toggleSimple: [], edit: [], skip: [], + skipStep:[] }>() let practiceData = inject('practiceData') @@ -33,8 +34,12 @@ function format(val: number, suffix: string = '', check: number = -1) { const status = $computed(() => { if (isTypingWrongWord.value) return '复习错词' + return getStepStr(statStore.step) +}) + +function getStepStr(step: number) { let str = '' - switch (statStore.step) { + switch (step) { case 0: str += `学习新词` break @@ -45,7 +50,7 @@ const status = $computed(() => { str += `默写新词` break case 3: - str += `复习上次学习` + str += `辨认上次学习` break case 4: str += '听写上次学习' @@ -54,7 +59,7 @@ const status = $computed(() => { str += '默写上次学习' break case 6: - str += '复习之前学习' + str += '辨认之前学习' break case 7: str += '听写之前学习' @@ -62,12 +67,15 @@ const status = $computed(() => { case 8: str += '默写之前学习' break + case 9: + str += '学习完成' + break case 10: str += '随机复习' break } return str -}) +} const progress = $computed(() => { if (!practiceData.words.length) return 0 @@ -115,6 +123,13 @@ const progress = $computed(() => {
      + + + + { + :title="`跳过当前单词(${settingStore.shortcutKeyMap[ShortcutKey.Next]})`"> @@ -207,7 +222,6 @@ const progress = $computed(() => { flex-direction: column; align-items: center; gap: .3rem; - width: 6rem; color: gray; .line { diff --git a/src/pages/word/components/TypeWord.vue b/src/pages/word/components/TypeWord.vue index 743d85d0..a827a515 100644 --- a/src/pages/word/components/TypeWord.vue +++ b/src/pages/word/components/TypeWord.vue @@ -189,6 +189,7 @@ async function onTyping(e: KeyboardEvent) { } inputLock = true let letter = e.key + console.log('letter',letter) //默写特殊逻辑 if (settingStore.wordPracticeType === WordPracticeType.Dictation) { if (e.code === 'Space') { @@ -221,6 +222,13 @@ async function onTyping(e: KeyboardEvent) { playKeyboardAudio() updateCurrentWordInfo(); inputLock = false + } else if (settingStore.wordPracticeType === WordPracticeType.Identify && !showWordResult) { + //当辨认模式下,按1和2会单独处理,如果按其他键则自动默认为不认识 + showWordResult = true + emit('wrong') + if (settingStore.wordSound) volumeIconRef?.play() + inputLock = false + onTyping(e) } else { let right = false if (settingStore.ignoreCase) { diff --git a/src/stores/base.ts b/src/stores/base.ts index ce451acd..e542bef5 100644 --- a/src/stores/base.ts +++ b/src/stores/base.ts @@ -1,11 +1,11 @@ -import {defineStore} from 'pinia' -import {Dict, DictId, Word} from "../types/types.ts" -import {_getStudyProgress, checkAndUpgradeSaveDict, shakeCommonDict} from "@/utils"; -import {shallowReactive} from "vue"; -import {getDefaultDict} from "@/types/func.ts"; -import {get, set} from 'idb-keyval' -import {CAN_REQUEST, IS_OFFICIAL, SAVE_DICT_KEY} from "@/config/env.ts"; -import {add2MyDict, dictListVersion, myDictList} from "@/apis"; +import { defineStore } from 'pinia' +import { Dict, DictId, Word } from "../types/types.ts" +import { _getStudyProgress, checkAndUpgradeSaveDict, shakeCommonDict } from "@/utils"; +import { shallowReactive } from "vue"; +import { getDefaultDict } from "@/types/func.ts"; +import { get, set } from 'idb-keyval' +import { AppEnv, SAVE_DICT_KEY } from "@/config/env.ts"; +import { add2MyDict, dictListVersion, myDictList } from "@/apis"; import Toast from "@/components/base/toast/Toast.ts"; export interface BaseState { @@ -125,13 +125,13 @@ export const useBaseStore = defineStore('base', { try { let configStr: string = await get(SAVE_DICT_KEY.key) let data = checkAndUpgradeSaveDict(configStr) - if (IS_OFFICIAL) { + if (AppEnv.IS_OFFICIAL) { let r = await dictListVersion() if (r.success) { data.dictListVersion = r.data } } - if (CAN_REQUEST) { + if (AppEnv.CAN_REQUEST) { let res = await myDictList() if (res.success) { Object.assign(data, res.data) @@ -147,7 +147,7 @@ export const useBaseStore = defineStore('base', { }, //改变词典 async changeDict(val: Dict) { - if (CAN_REQUEST) { + if (AppEnv.CAN_REQUEST) { let r = await add2MyDict(val) if (!r.success) { return Toast.error(r.msg) @@ -175,7 +175,7 @@ export const useBaseStore = defineStore('base', { }, //改变书籍 async changeBook(val: Dict) { - if (CAN_REQUEST) { + if (AppEnv.CAN_REQUEST) { let r = await add2MyDict(val) if (!r.success) { return Toast.error(r.msg) diff --git a/src/stores/setting.ts b/src/stores/setting.ts index 424ae68e..30576a16 100644 --- a/src/stores/setting.ts +++ b/src/stores/setting.ts @@ -1,9 +1,9 @@ -import {defineStore} from "pinia" -import {checkAndUpgradeSaveSetting, cloneDeep} from "@/utils"; -import {DefaultShortcutKeyMap, WordPracticeMode, WordPracticeType} from "@/types/types.ts"; -import {get} from "idb-keyval"; -import {CAN_REQUEST, SAVE_SETTING_KEY} from "@/config/env.ts"; -import {getSetting} from "@/apis"; +import { defineStore } from "pinia" +import { checkAndUpgradeSaveSetting, cloneDeep } from "@/utils"; +import { DefaultShortcutKeyMap, WordPracticeMode, WordPracticeType } from "@/types/types.ts"; +import { get } from "idb-keyval"; +import { AppEnv, SAVE_SETTING_KEY } from "@/config/env.ts"; +import { getSetting } from "@/apis"; export interface SettingState { soundType: string, @@ -119,7 +119,7 @@ export const useSettingStore = defineStore('setting', { return new Promise(async resolve => { let configStr = await get(SAVE_SETTING_KEY.key) let data = checkAndUpgradeSaveSetting(configStr) - if (CAN_REQUEST) { + if (AppEnv.CAN_REQUEST) { let res = await getSetting() if (res.success) { Object.assign(data, res.data) diff --git a/src/utils/index.ts b/src/utils/index.ts index e04fb9d2..e65633c2 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -4,8 +4,7 @@ import { Dict, DictId, DictResource, DictType } from "@/types/types.ts"; import { useRouter } from "vue-router"; import { useRuntimeStore } from "@/stores/runtime.ts"; import dayjs from 'dayjs' -import axios from "axios"; -import { ENV, IS_OFFICIAL, RESOURCE_PATH, SAVE_DICT_KEY, SAVE_SETTING_KEY } from "@/config/env.ts"; +import { AppEnv, RESOURCE_PATH, SAVE_DICT_KEY, SAVE_SETTING_KEY } from "@/config/env.ts"; import { nextTick } from "vue"; import Toast from '@/components/base/toast/Toast.ts' import { getDefaultDict, getDefaultWord } from "@/types/func.ts"; @@ -440,7 +439,7 @@ export function total(arr, key) { } export function resourceWrap(resource: string, version?: number) { - if (IS_OFFICIAL) { + if (AppEnv.IS_OFFICIAL) { if (resource.includes('.json')) resource = resource.replace('.json', ''); if (!resource.includes('http')) resource = RESOURCE_PATH + resource if (version === undefined) {