feat: 开始任务直接跳转并补会话页加载
This commit is contained in:
@@ -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()
|
||||||
|
|
||||||
|
|||||||
@@ -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 () => {
|
||||||
const hasPermission = await checkAudioPermission();
|
try {
|
||||||
if (!hasPermission) {
|
const hasPermission = await checkAudioPermission();
|
||||||
const activated = await requestAudioPermission();
|
if (!hasPermission) {
|
||||||
if (!activated) return;
|
const activated = await requestAudioPermission();
|
||||||
|
if (!activated) return;
|
||||||
|
}
|
||||||
|
await loadTaskSession();
|
||||||
|
} finally {
|
||||||
|
pageLoading.value = false;
|
||||||
}
|
}
|
||||||
await loadTaskSession();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 碎片列表
|
// 碎片列表
|
||||||
@@ -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="已恢复上次的学习会话,继续学习吧"
|
||||||
|
|||||||
@@ -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 = () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user