feat: 开始任务直接跳转并补会话页加载

This commit is contained in:
2026-08-05 21:41:27 +08:00
parent 4d9b3c0b02
commit 9ed53aa4bc
3 changed files with 52 additions and 27 deletions
@@ -8,6 +8,7 @@ import router from '@/router'
import { import {
continueSession, continueSession,
endSession, endSession,
getActiveSession,
getExpectation, getExpectation,
getSessionDetail, getSessionDetail,
pauseSession, pauseSession,
@@ -18,6 +19,7 @@ import { getFragmentsBySession } from '@/api/reportFragments'
vi.mock('@/api/studySessions', () => ({ vi.mock('@/api/studySessions', () => ({
continueSession: vi.fn(), continueSession: vi.fn(),
endSession: vi.fn(), endSession: vi.fn(),
getActiveSession: vi.fn(),
getExpectation: vi.fn(), getExpectation: vi.fn(),
getReportDraft: vi.fn(), getReportDraft: vi.fn(),
getSessionDetail: vi.fn(), getSessionDetail: vi.fn(),
@@ -78,6 +80,7 @@ describe('StartTask.vue', () => {
beforeEach(async () => { beforeEach(async () => {
vi.clearAllMocks() vi.clearAllMocks()
localStorage.clear() localStorage.clear()
vi.mocked(getActiveSession).mockResolvedValue({ code: 200, data: null } as any)
vi.mocked(startOrContinueStudySession).mockResolvedValue({ code: 200, data: defaultSessionData } as any) vi.mocked(startOrContinueStudySession).mockResolvedValue({ code: 200, data: defaultSessionData } as any)
vi.mocked(getExpectation).mockResolvedValue({ code: 200, data: { description: '本次学习预期' } } as any) vi.mocked(getExpectation).mockResolvedValue({ code: 200, data: { description: '本次学习预期' } } as any)
vi.mocked(getFragmentsBySession).mockResolvedValue({ code: 200, data: [] } as any) vi.mocked(getFragmentsBySession).mockResolvedValue({ code: 200, data: [] } as any)
@@ -142,6 +145,19 @@ describe('StartTask.vue', () => {
wrapper.unmount() 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 () => { it('endTimer refuses empty content without calling API', async () => {
const wrapper = await mountTask() const wrapper = await mountTask()
+29 -1
View File
@@ -7,6 +7,7 @@ import { useTimer } from "@/components/composables/useTimer";
import { import {
continueSession, continueSession,
endSession, endSession,
getActiveSession,
getSessionDetail, getSessionDetail,
pauseSession, pauseSession,
startOrContinueStudySession, startOrContinueStudySession,
@@ -26,6 +27,8 @@ const {
confirmGenerateFragment, confirmGenerateFragment,
} = useStudyFragment(); } = useStudyFragment();
const pageLoading = ref(true);
const summaryDialogVisible = ref(false); const summaryDialogVisible = ref(false);
const summaryContent = ref(""); const summaryContent = ref("");
const summaryPreview = ref(false); const summaryPreview = ref(false);
@@ -434,6 +437,27 @@ const restTimer = async () => {
const loadTaskSession = async () => { const loadTaskSession = async () => {
try { 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); const res = await startOrContinueStudySession(taskNum);
Object.assign(taskInfo.value, res.data); Object.assign(taskInfo.value, res.data);
await loadExpectation(); await loadExpectation();
@@ -519,12 +543,16 @@ const saveExpectation = async () => {
}; };
const initPage = async () => { const initPage = async () => {
try {
const hasPermission = await checkAudioPermission(); const hasPermission = await checkAudioPermission();
if (!hasPermission) { if (!hasPermission) {
const activated = await requestAudioPermission(); const activated = await requestAudioPermission();
if (!activated) return; if (!activated) return;
} }
await loadTaskSession(); await loadTaskSession();
} finally {
pageLoading.value = false;
}
}; };
// 碎片列表 // 碎片列表
@@ -609,7 +637,7 @@ defineExpose({
<template> <template>
<div> <div>
<section class="start-page"> <section class="start-page" v-loading="pageLoading">
<el-alert <el-alert
v-if="showResumeHint" v-if="showResumeHint"
title="已恢复上次的学习会话,继续学习吧" title="已恢复上次的学习会话,继续学习吧"
+2 -21
View File
@@ -4,7 +4,6 @@ import request from "@/utils/request";
import router from "@/router"; import router from "@/router";
import { ElMessage, ElMessageBox } from "element-plus"; import { ElMessage, ElMessageBox } from "element-plus";
import { getReviewTaskStatsByTask } from "@/api/review"; import { getReviewTaskStatsByTask } from "@/api/review";
import { getActiveSession } from "@/api/studySessions";
import { renderMarkdown } from "@/utils/markdown"; import { renderMarkdown } from "@/utils/markdown";
import { applicationStatusOptions } from "@/utils/taskApplication"; import { applicationStatusOptions } from "@/utils/taskApplication";
@@ -179,30 +178,12 @@ const handlePageChange = (page: number) => {
fetchTasks(page); fetchTasks(page);
}; };
const startTask = async () => { const startTask = () => {
if (!selectedTask.value) { if (!selectedTask.value) {
ElMessage.warning("请先选择一个任务"); ElMessage.warning("请先选择一个任务");
return; return;
} }
const taskNum = selectedTask.value.taskNum; router.push(`/start-task/${encodeURIComponent(selectedTask.value.taskNum)}`);
try {
const res = await getActiveSession(taskNum);
if (res?.code === 200 && res.data) {
// 有其他任务的活跃会话
const active = res.data;
ElMessageBox.confirm(
`你还有一个未完成的学习任务「${active.taskName}」(${active.sessionNum}),是否前往继续?`,
"有其他任务正在进行",
{ confirmButtonText: "前往继续", cancelButtonText: "取消", type: "warning" }
).then(() => {
router.push(`/start-task/${encodeURIComponent(active.taskNum)}`);
}).catch(() => {});
return;
}
} catch {
// 查询失败不阻塞,直接跳转
}
router.push(`/start-task/${encodeURIComponent(taskNum)}`);
}; };
const addTask = () => { const addTask = () => {