diff --git a/src/__tests__/components/StartTask.spec.ts b/src/__tests__/components/StartTask.spec.ts index fb93cf3..855da16 100644 --- a/src/__tests__/components/StartTask.spec.ts +++ b/src/__tests__/components/StartTask.spec.ts @@ -8,6 +8,7 @@ import router from '@/router' import { continueSession, endSession, + getActiveSession, getExpectation, getSessionDetail, pauseSession, @@ -18,6 +19,7 @@ import { getFragmentsBySession } from '@/api/reportFragments' vi.mock('@/api/studySessions', () => ({ continueSession: vi.fn(), endSession: vi.fn(), + getActiveSession: vi.fn(), getExpectation: vi.fn(), getReportDraft: vi.fn(), getSessionDetail: vi.fn(), @@ -78,6 +80,7 @@ describe('StartTask.vue', () => { beforeEach(async () => { vi.clearAllMocks() localStorage.clear() + vi.mocked(getActiveSession).mockResolvedValue({ code: 200, data: null } as any) vi.mocked(startOrContinueStudySession).mockResolvedValue({ code: 200, data: defaultSessionData } as any) vi.mocked(getExpectation).mockResolvedValue({ code: 200, data: { description: '本次学习预期' } } as any) vi.mocked(getFragmentsBySession).mockResolvedValue({ code: 200, data: [] } as any) @@ -142,6 +145,19 @@ describe('StartTask.vue', () => { wrapper.unmount() }) + it('redirects to another active task when one exists', async () => { + vi.mocked(getActiveSession).mockResolvedValue({ + code: 200, + data: { taskNum: 'T002', taskName: '其他任务', sessionNum: 'S002' }, + } as any) + const wrapper = await mountTask() + await flushPromises() + + expect(startOrContinueStudySession).not.toHaveBeenCalled() + expect(router.currentRoute.value.path).toBe('/start-task/T002') + wrapper.unmount() + }) + it('endTimer refuses empty content without calling API', async () => { const wrapper = await mountTask() diff --git a/src/components/StartTask.vue b/src/components/StartTask.vue index 8bcea24..af5d3b5 100644 --- a/src/components/StartTask.vue +++ b/src/components/StartTask.vue @@ -7,6 +7,7 @@ import { useTimer } from "@/components/composables/useTimer"; import { continueSession, endSession, + getActiveSession, getSessionDetail, pauseSession, startOrContinueStudySession, @@ -26,6 +27,8 @@ const { confirmGenerateFragment, } = useStudyFragment(); +const pageLoading = ref(true); + const summaryDialogVisible = ref(false); const summaryContent = ref(""); const summaryPreview = ref(false); @@ -434,6 +437,27 @@ const restTimer = async () => { const loadTaskSession = async () => { try { + const activeRes = await getActiveSession(); + const active = activeRes?.data; + if (active?.taskNum && active.taskNum !== taskNum) { + let goToActive = false; + try { + await ElMessageBox.confirm( + `你还有一个未完成的学习任务「${active.taskName}」(${active.sessionNum}),是否前往继续?`, + "有其他任务正在进行", + { confirmButtonText: "前往继续", cancelButtonText: "取消", type: "warning" }, + ); + goToActive = true; + } catch { + // 用户取消,不开始当前任务 + } + if (goToActive) { + router.push(`/start-task/${encodeURIComponent(active.taskNum)}`); + } else { + ElMessage.warning("请先完成进行中的任务后再开始"); + } + return; + } const res = await startOrContinueStudySession(taskNum); Object.assign(taskInfo.value, res.data); await loadExpectation(); @@ -519,12 +543,16 @@ const saveExpectation = async () => { }; const initPage = async () => { - const hasPermission = await checkAudioPermission(); - if (!hasPermission) { - const activated = await requestAudioPermission(); - if (!activated) return; + try { + const hasPermission = await checkAudioPermission(); + if (!hasPermission) { + const activated = await requestAudioPermission(); + if (!activated) return; + } + await loadTaskSession(); + } finally { + pageLoading.value = false; } - await loadTaskSession(); }; // 碎片列表 @@ -609,7 +637,7 @@ defineExpose({