feat: 复习跳转改为先进入目标页

This commit is contained in:
2026-08-05 21:40:12 +08:00
parent 605495fd53
commit 4d9b3c0b02
5 changed files with 61 additions and 54 deletions
+2 -19
View File
@@ -1,18 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, onMounted, ref } from "vue"; import { computed, onMounted, ref } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { ElMessage } from "element-plus";
import { import {
getReviewTaskStats, getReviewTaskStats,
getTaskReview,
type ReviewFeedItem,
type ReviewTaskStats, type ReviewTaskStats,
} from "@/api/review"; } from "@/api/review";
const router = useRouter(); const router = useRouter();
const loading = ref(false); const loading = ref(false);
const openingTaskNum = ref("");
const tasks = ref<ReviewTaskStats[]>([]); const tasks = ref<ReviewTaskStats[]>([]);
const summary = computed(() => ({ const summary = computed(() => ({
@@ -40,21 +36,9 @@ const loadTasks = async () => {
} }
}; };
const openTaskReview = async (row: ReviewTaskStats) => { const openTaskReview = (row: ReviewTaskStats) => {
if (!row.taskNum) return; if (!row.taskNum) return;
openingTaskNum.value = row.taskNum; router.push(`/review/detail/task/${encodeURIComponent(row.taskNum)}`);
try {
const res = await getTaskReview(row.taskNum);
const items: ReviewFeedItem[] = res?.data || [];
const first = items[0];
if (!first) {
ElMessage.info("该任务暂无可复习内容");
return;
}
router.push(`/review/detail/${first.sourceType.toLowerCase()}/${first.id}`);
} finally {
openingTaskNum.value = "";
}
}; };
onMounted(() => { onMounted(() => {
@@ -105,7 +89,6 @@ onMounted(() => {
text text
type="success" type="success"
size="small" size="small"
:loading="openingTaskNum === row.taskNum"
@click="openTaskReview(row)" @click="openTaskReview(row)"
> >
查看记录 查看记录
+30 -19
View File
@@ -9,34 +9,29 @@ import {
} from "@/api/review"; } from "@/api/review";
import { getSessionDetail } from "@/api/studySessions"; import { getSessionDetail } from "@/api/studySessions";
import { updateFragments } from "@/api/reportFragments"; import { updateFragments } from "@/api/reportFragments";
import { findNode } from "@/api/standardMindMap";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import MarkdownRenderer from "@/components/MarkdownRenderer.vue"; import MarkdownRenderer from "@/components/MarkdownRenderer.vue";
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
/** 调用 findNode API 匹配标准导图中的最近节点,跳转到回忆页 */ /** 直接进入回忆复习页,节点匹配交给目标页加载后处理 */
const goToRecall = async () => { const goToRecall = () => {
if (!content.value || !content.value.trim()) { const tn = taskNum.value;
router.push(`/review/recall/${taskNum.value}`); if (!tn) return;
return; if (content.value && content.value.trim()) {
} router.push(`/review/recall/${tn}?focusContent=${encodeURIComponent(content.value.substring(0, 500))}`);
try {
const res = await findNode(taskNum.value, content.value.substring(0, 500));
const data = res?.data;
if (data?.path) {
router.push(`/review/recall/${taskNum.value}?focusPath=${encodeURIComponent(data.path)}`);
} else { } else {
router.push(`/review/recall/${taskNum.value}`); router.push(`/review/recall/${tn}`);
}
} catch {
router.push(`/review/recall/${taskNum.value}`);
} }
}; };
const contentType = computed(() => route.params.type as string); const isTaskMode = computed(() => !!route.params.taskNum);
const contentId = computed(() => Number(route.params.id)); const activeType = ref<string | undefined>(undefined);
const activeId = ref<number | undefined>(undefined);
const contentType = computed(() => isTaskMode.value ? activeType.value : (route.params.type as string));
const contentId = computed(() => isTaskMode.value ? activeId.value ?? 0 : Number(route.params.id));
const taskModeTaskNum = computed(() => route.params.taskNum as string | undefined);
const loading = ref(true); const loading = ref(true);
const content = ref(""); const content = ref("");
@@ -118,7 +113,19 @@ const loadDetail = async () => {
taskNum.value = ""; taskNum.value = "";
sessionInfo.value = null; sessionInfo.value = null;
taskSessions.value = []; taskSessions.value = [];
if (isTaskMode.value) {
activeType.value = undefined;
activeId.value = undefined;
}
try { try {
if (isTaskMode.value && taskModeTaskNum.value) {
const taskRes = await getTaskReview(taskModeTaskNum.value);
const items: ReviewFeedItem[] = taskRes?.data || [];
const first = items[0];
if (!first) return;
activeType.value = first.sourceType.toLowerCase();
activeId.value = first.id;
}
let res; let res;
if (contentType.value === "report") { if (contentType.value === "report") {
res = await getReportDetail(contentId.value); res = await getReportDetail(contentId.value);
@@ -194,8 +201,12 @@ const saveEdit = async () => {
}; };
watch( watch(
() => [contentType.value, contentId.value], () => [route.params.type, route.params.id, route.params.taskNum],
() => { () => {
if (!isTaskMode.value) {
activeType.value = undefined;
activeId.value = undefined;
}
loadDetail(); loadDetail();
}, },
{ immediate: true }, { immediate: true },
+14 -1
View File
@@ -2,6 +2,7 @@
import { ref, onMounted, computed } from "vue"; import { ref, onMounted, computed } from "vue";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import { import {
findNode,
getStandardMindMap, getStandardMindMap,
regenerateStandardMindMap, regenerateStandardMindMap,
recallCompare, recallCompare,
@@ -31,6 +32,7 @@ const hasCompared = ref(false);
// 起点节点选择 // 起点节点选择
const focusPath = ref((route.query.focusPath as string) || ""); const focusPath = ref((route.query.focusPath as string) || "");
const focusContent = ref((route.query.focusContent as string) || "");
const focusConfirmVisible = ref(false); const focusConfirmVisible = ref(false);
const selectedNodeInfo = ref<{ title: string; path: string; childCount: number } | null>(null); const selectedNodeInfo = ref<{ title: string; path: string; childCount: number } | null>(null);
@@ -114,6 +116,17 @@ const loadData = async () => {
try { try {
const res = await getStandardMindMap(taskNum.value); const res = await getStandardMindMap(taskNum.value);
standard.value = res?.data || null; standard.value = res?.data || null;
if (focusContent.value && standard.value) {
try {
const nodeRes = await findNode(taskNum.value, focusContent.value.substring(0, 500));
const data = nodeRes?.data;
if (data?.path) {
focusPath.value = data.path;
}
} catch {
// 匹配失败时仍可进入回忆页
}
}
} catch (e: any) { } catch (e: any) {
standard.value = null; standard.value = null;
} finally { } finally {
@@ -382,7 +395,7 @@ onMounted(() => {
</script> </script>
<template> <template>
<section class="recall-page"> <section class="recall-page" v-loading="loading">
<!-- 顶部操作栏 --> <!-- 顶部操作栏 -->
<div class="page-header"> <div class="page-header">
<h2>回忆复习</h2> <h2>回忆复习</h2>
+9 -14
View File
@@ -87,9 +87,11 @@ const revealRecallContent = async () => {
recallCard.value.loadError = ""; recallCard.value.loadError = "";
try { try {
const res = await getTaskReview(fragment.taskNum); const res = await getTaskReview(fragment.taskNum);
const items = (res?.data || []).filter(item => item.sessionNum === fragment.sessionNum); const items: ReviewFeedItem[] = (res?.data || []).filter(
recallCard.value.report = items.find(item => item.sourceType === "REPORT") || null; (item: ReviewFeedItem) => item.sessionNum === fragment.sessionNum,
recallCard.value.fragments = items.filter(item => item.sourceType === "FRAGMENT"); );
recallCard.value.report = items.find((item: ReviewFeedItem) => item.sourceType === "REPORT") || null;
recallCard.value.fragments = items.filter((item: ReviewFeedItem) => item.sourceType === "FRAGMENT");
recallCard.value.revealed = true; recallCard.value.revealed = true;
} catch { } catch {
recallCard.value.loadError = "展开对照内容加载失败,请稍后重试"; recallCard.value.loadError = "展开对照内容加载失败,请稍后重试";
@@ -98,23 +100,16 @@ const revealRecallContent = async () => {
} }
}; };
/** 从回忆卡片跳转到回忆复习页(先匹配标准导图节点) */ /** 从回忆卡片跳转到回忆复习页,节点匹配交给目标页加载后处理 */
const goToRecallFromCard = async () => { const goToRecallFromCard = () => {
const fragment = recallCard.value.fragment; const fragment = recallCard.value.fragment;
if (!fragment) return; if (!fragment) return;
recallCard.value.visible = false; recallCard.value.visible = false;
const tn = fragment.taskNum; const tn = fragment.taskNum;
const content = fragment.content || ""; const content = fragment.content || "";
if (tn && content) { if (tn && content) {
try { router.push(`/review/recall/${tn}?focusContent=${encodeURIComponent(content)}`);
const { findNode } = await import("@/api/standardMindMap"); } else if (tn) {
const res = await findNode(tn, content.substring(0, 500));
const data = res?.data;
if (data?.path) {
router.push(`/review/recall/${tn}?focusPath=${encodeURIComponent(data.path)}`);
return;
}
} catch { /* fall through */ }
router.push(`/review/recall/${tn}`); router.push(`/review/recall/${tn}`);
} else { } else {
router.push("/review"); router.push("/review");
+5
View File
@@ -27,6 +27,11 @@ const routes: RouteRecordRaw[] = [
component: () => import("@/components/Review.vue"), component: () => import("@/components/Review.vue"),
meta: { requiresAuth: true, title: "复习总览" }, meta: { requiresAuth: true, title: "复习总览" },
}, },
{
path: "/review/detail/task/:taskNum",
component: () => import("@/components/ReviewDetail.vue"),
meta: { requiresAuth: true, title: "复习详情" },
},
{ {
path: "/review/detail/:type/:id", path: "/review/detail/:type/:id",
component: () => import("@/components/ReviewDetail.vue"), component: () => import("@/components/ReviewDetail.vue"),