diff --git a/components.d.ts b/components.d.ts index 9fc75307..3ed930b1 100644 --- a/components.d.ts +++ b/components.d.ts @@ -44,6 +44,7 @@ declare module 'vue' { IconFluentArrowLeft16Regular: typeof import('~icons/fluent/arrow-left16-regular')['default'] IconFluentArrowMove20Regular: typeof import('~icons/fluent/arrow-move20-regular')['default'] IconFluentArrowRight16Regular: typeof import('~icons/fluent/arrow-right16-regular')['default'] + IconFluentArrowShuffle16Regular: typeof import('~icons/fluent/arrow-shuffle16-regular')['default'] IconFluentArrowSort20Regular: typeof import('~icons/fluent/arrow-sort20-regular')['default'] IconFluentBookLetter20Regular: typeof import('~icons/fluent/book-letter20-regular')['default'] IconFluentCheckmark20Regular: typeof import('~icons/fluent/checkmark20-regular')['default'] diff --git a/src/components/base/Audio.vue b/src/components/base/Audio.vue index 25bd3726..5711be6a 100644 --- a/src/components/base/Audio.vue +++ b/src/components/base/Audio.vue @@ -119,9 +119,14 @@ const handlePause = () => { isPlaying.value = false; }; +const emit = defineEmits<{ + ended: [] +}>(); + const handleEnded = () => { isPlaying.value = false; currentTime.value = 0; + emit('ended'); }; const handleError = () => { diff --git a/src/components/list/WordList.vue b/src/components/list/WordList.vue index 46637238..3d068536 100644 --- a/src/components/list/WordList.vue +++ b/src/components/list/WordList.vue @@ -47,7 +47,8 @@ defineExpose({scrollToBottom, scrollToItem}) diff --git a/src/pages/article/BookDetail.vue b/src/pages/article/BookDetail.vue index ff8ca796..1f38c074 100644 --- a/src/pages/article/BookDetail.vue +++ b/src/pages/article/BookDetail.vue @@ -33,6 +33,16 @@ let studyLoading = $ref(false) let selectArticle: Article = $ref(getDefaultArticle()) +// 计算当前选中文章的索引 +const currentArticleIndex = computed(() => { + return runtimeStore.editDict.articles.findIndex(article => article.id === selectArticle.id) +}) + +// 处理播放下一个音频 +const handlePlayNext = (nextArticle: Article) => { + selectArticle = nextArticle +} + function handleCheckedChange(val) { selectArticle = val.item } @@ -191,7 +201,11 @@ const totalSpend = $computed(() => {
- +
{{ selectArticle.title }}
diff --git a/src/pages/article/PracticeArticles.vue b/src/pages/article/PracticeArticles.vue index 23e1bf95..9d42a1f1 100644 --- a/src/pages/article/PracticeArticles.vue +++ b/src/pages/article/PracticeArticles.vue @@ -328,6 +328,14 @@ function changeArticle(val: ArticleItem) { } } +const handlePlayNext = (nextArticle: Article) => { + let rIndex = articleData.list.findIndex(v => v.id === nextArticle.id) + if (rIndex > -1) { + store.sbook.lastLearnIndex = rIndex + getCurrentPractice() + } +} + const { isArticleCollect, toggleArticleCollect @@ -489,7 +497,12 @@ provide('currentPractice', currentPractice)
单词总数
- +
diff --git a/src/pages/article/components/ArticleAudio.vue b/src/pages/article/components/ArticleAudio.vue index fe3c9e24..5995ee6e 100644 --- a/src/pages/article/components/ArticleAudio.vue +++ b/src/pages/article/components/ArticleAudio.vue @@ -7,10 +7,45 @@ import Audio from "@/components/base/Audio.vue"; const props = defineProps<{ article: Article + articleList?: Article[] + currentIndex?: number }>() let file = $ref(null) let instance = $ref<{ audioRef: HTMLAudioElement }>({audioRef: null}) +let shouldAutoPlay = $ref(false) // 标记是否应该自动播放 + +const emit = defineEmits<{ + playNext: [nextArticle: Article] +}>() + +// 处理音频播放结束,自动播放下一个 +const handleAudioEnded = () => { + if (props.articleList && props.currentIndex !== undefined) { + const nextIndex = props.currentIndex + 1 + if (nextIndex < props.articleList.length) { + const nextArticle = props.articleList[nextIndex] + if (nextArticle.audioSrc || nextArticle.audioFileId) { + shouldAutoPlay = true // 设置自动播放标记 + emit('playNext', nextArticle) + } + } + } +} + +// 当音频源改变时,如果需要自动播放则开始播放 +const startAutoPlay = async () => { + if (shouldAutoPlay && instance?.audioRef) { + shouldAutoPlay = false // 重置标记 + try { + // 等待一小段时间确保音频元素已经准备好 + await new Promise(resolve => setTimeout(resolve, 100)) + await instance.audioRef.play() + } catch (error) { + console.error('自动播放失败:', error) + } + } +} watch(() => props.article.audioFileId, async () => { if (!props.article.audioSrc && props.article.audioFileId) { @@ -19,6 +54,9 @@ watch(() => props.article.audioFileId, async () => { let rItem = list.find((file) => file.id === props.article.audioFileId) if (rItem) { file = URL.createObjectURL(rItem.file) + // 当文件加载完成后尝试自动播放 + await new Promise(resolve => setTimeout(resolve, 50)) + startAutoPlay() } } }else { @@ -26,6 +64,15 @@ watch(() => props.article.audioFileId, async () => { } }, {immediate: true}) +// 监听音频源变化,触发自动播放 +watch(() => props.article.audioSrc, async (newSrc) => { + if (newSrc) { + // 当音频源改变后尝试自动播放 + await new Promise(resolve => setTimeout(resolve, 50)) + startAutoPlay() + } +}) + //转发一遍,这里Proxy的默认值不能为{},可能是vue做了什么 defineExpose(new Proxy({ currentTime: 0, @@ -57,8 +104,10 @@ defineExpose(new Proxy({ diff --git a/src/pages/setting/Setting.vue b/src/pages/setting/Setting.vue index 3ffc53ae..f1af2864 100644 --- a/src/pages/setting/Setting.vue +++ b/src/pages/setting/Setting.vue @@ -152,7 +152,9 @@ function getShortcutKeyName(key: string): string { 'ToggleDictation': '切换默写模式', 'ToggleTheme': '切换主题', 'ToggleConciseMode': '切换简洁模式', - 'TogglePanel': '切换面板' + 'TogglePanel': '切换面板', + 'RandomWrite': '随机默写', + 'NextRandomWrite': '继续随机默写' } return shortcutKeyNameMap[key] || key diff --git a/src/pages/word/PracticeWords.vue b/src/pages/word/PracticeWords.vue index 0aacca14..1630202c 100644 --- a/src/pages/word/PracticeWords.vue +++ b/src/pages/word/PracticeWords.vue @@ -57,6 +57,8 @@ let data = $ref({ wrongWords: [], }) +let isRandomWrite = false; + async function loadDict() { // console.log('load好了开始加载') let dict = getDefaultDict() @@ -229,7 +231,8 @@ function next(isTyping: boolean = true) { //开始默写新词 if (statStore.step === 0) { - if (settingStore.wordPracticeMode === 1) { + if (settingStore.wordPracticeMode === 1 || isRandomWrite) { + isRandomWrite = false console.log('自由模式,全完学完了') showStatDialog = true localStorage.removeItem(PracticeSaveWordKey.key) @@ -380,9 +383,24 @@ function continueStudy() { initData(getCurrentStudyWord()) } +function randomWrite() { + console.log('随机默写') + data.words = shuffle(data.words); + data.index = 0 + settingStore.dictation = true + isRandomWrite = true +} +function nextRandomWrite() { + console.log('继续随机默写') + initData(getCurrentStudyWord()) + randomWrite(); + showStatDialog = false +} + useEvents([ [EventKey.repeatStudy, repeat], [EventKey.continueStudy, continueStudy], + [EventKey.randomWrite, nextRandomWrite], [EventKey.changeDict, () => { initData(getCurrentStudyWord()) }], @@ -401,6 +419,8 @@ useEvents([ [ShortcutKey.ToggleTheme, toggleTheme], [ShortcutKey.ToggleConciseMode, toggleConciseMode], [ShortcutKey.TogglePanel, togglePanel], + [ShortcutKey.RandomWrite, randomWrite], + [ShortcutKey.NextRandomWrite, nextRandomWrite], ]) @@ -453,6 +473,11 @@ useEvents([ :title="`下一组(${settingStore.shortcutKeyMap[ShortcutKey.NextChapter]})`"> + + +
diff --git a/src/pages/word/Statistics.vue b/src/pages/word/Statistics.vue index ca090289..f6a5cafe 100644 --- a/src/pages/word/Statistics.vue +++ b/src/pages/word/Statistics.vue @@ -168,6 +168,11 @@ function options(emitType: string) { @click="options(EventKey.continueStudy)"> {{ dictIsEnd ? '重新练习' : '再来一组' }} + + 继续默写 + 返回主页 diff --git a/src/types/types.ts b/src/types/types.ts index 0f2cca47..68b2bd7e 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -115,7 +115,9 @@ export enum ShortcutKey { ToggleDictation = 'ToggleDictation', ToggleTheme = 'ToggleTheme', ToggleConciseMode = 'ToggleConciseMode', - TogglePanel = 'TogglePanel' + TogglePanel = 'TogglePanel', + RandomWrite = 'RandomWrite', + NextRandomWrite = 'NextRandomWrite' } export const DefaultShortcutKeyMap = { @@ -135,6 +137,8 @@ export const DefaultShortcutKeyMap = { [ShortcutKey.ToggleTheme]: 'Ctrl+Q', [ShortcutKey.ToggleConciseMode]: 'Ctrl+M', [ShortcutKey.TogglePanel]: 'Ctrl+L', + [ShortcutKey.RandomWrite]: 'Ctrl+R', + [ShortcutKey.NextRandomWrite]: 'Ctrl+Shift+R', } export enum TranslateEngine { diff --git a/src/utils/eventBus.ts b/src/utils/eventBus.ts index 4ce756ce..6fb47c48 100644 --- a/src/utils/eventBus.ts +++ b/src/utils/eventBus.ts @@ -17,6 +17,7 @@ export const EventKey = { editDict: 'editDict', openMyDictDialog: 'openMyDictDialog', stateInitEnd: 'stateInitEnd', + randomWrite: 'randomWrite', } export function useEvent(key: string, func: any) {