From 031a5ccc8972d2c9db14120ea0c74cd3f5976d72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E6=B2=85?= <907037276@qq.com> Date: Sat, 5 Sep 2026 13:10:36 +0800 Subject: [PATCH] fix: stabilize task review preview scrolling --- .../teacherEnd/score/TaskReviewPanel.vue | 28 +++++++++-- .../taskReview/StudentTaskReadonlyPreview.vue | 49 ++++++++++++++++++- tests/task-review-preview.test.mjs | 7 +++ 3 files changed, 79 insertions(+), 5 deletions(-) diff --git a/src/views/teacherEnd/score/TaskReviewPanel.vue b/src/views/teacherEnd/score/TaskReviewPanel.vue index 9509bda..8e8d87a 100644 --- a/src/views/teacherEnd/score/TaskReviewPanel.vue +++ b/src/views/teacherEnd/score/TaskReviewPanel.vue @@ -80,6 +80,7 @@ :key="studentPreviewSrc" class="task-review__student-preview" :src="studentPreviewSrc" + :style="{ height: `${previewFrameHeight}px` }" scrolling="yes" title="学生任务页面只读预览" /> @@ -129,7 +130,9 @@ const studentTableRef = ref(); const previewKey = ref(""); const studentPreviewSrc = ref(""); const studentPreviewError = ref(""); +const previewFrameHeight = ref(580); let previewRequestVersion = 0; +const PREVIEW_HEIGHT_MESSAGE = "teacher-task-review-preview-height"; const canManageClass = computed(() => { const currentClass = teachingClasses.value.find((item) => item.schoolClassId === filters.value.classId); @@ -159,6 +162,7 @@ async function refreshStudentPreview() { const teachingClassId = filters.value.classId; const student = selectedStudent.value; studentPreviewError.value = ""; + previewFrameHeight.value = 580; if (!student || !taskKey || !teachingClassId) { previewKey.value = ""; studentPreviewSrc.value = ""; @@ -235,6 +239,13 @@ function selectStudent(row) { function studentRowClass({ row }) { return row.studentUserId === selectedStudentId.value ? "task-review__selected-row" : ""; } +function onPreviewMessage(event) { + if (event.origin !== window.location.origin) return; + const data = event.data || {}; + if (data.type !== PREVIEW_HEIGHT_MESSAGE || data.previewKey !== previewKey.value) return; + const height = Number(data.height); + if (Number.isFinite(height) && height > 0) previewFrameHeight.value = Math.max(580, Math.ceil(height)); +} async function saveSingleScore(row) { const score = row.teacherScoreDraft; if (!Number.isInteger(score) || score < 0 || score > 100) { @@ -270,8 +281,14 @@ async function saveBatchScore() { savingBatch.value = false; } } -onMounted(loadTeachingClasses); -onBeforeUnmount(() => clearTrainingReviewPreview(previewKey.value)); +onMounted(() => { + window.addEventListener("message", onPreviewMessage); + loadTeachingClasses(); +}); +onBeforeUnmount(() => { + window.removeEventListener("message", onPreviewMessage); + clearTrainingReviewPreview(previewKey.value); +}); diff --git a/tests/task-review-preview.test.mjs b/tests/task-review-preview.test.mjs index f4388f7..0c51aaa 100644 --- a/tests/task-review-preview.test.mjs +++ b/tests/task-review-preview.test.mjs @@ -45,6 +45,10 @@ assert.match(previewShell, /function guardPreviewInteraction/); assert.match(previewShell, /getAttribute\("aria-label"\)/); assert.doesNotMatch(previewShell, /:global\(html\)|:global\(body\)/, "预览壳不得改写学生页面的全局样式"); assert.doesNotMatch(previewShell, /pointer-events\s*:/, "预览壳不得用样式禁用学生页面控件"); +assert.match(previewShell, /training-ai-sidebar/, "评阅预览应隐藏 AI 助学"); +assert.match(previewShell, /training-ai-evaluation/, "评阅预览应隐藏 AI 助评"); +assert.match(previewShell, /teacher-task-review-preview-height/, "预览页应向外层同步内容高度"); +assert.match(previewShell, /ResizeObserver/, "预览页内容变化后应重新同步高度"); assert.match(reviewPanel, /writeTrainingReviewPreview/); assert.match(reviewPanel, /listClassTrainingTasks\(filters\.value\.classId/); assert.match(reviewPanel, /find\(\(task\) => task\.taskKey === taskKey\)/); @@ -55,6 +59,9 @@ assert.match(reviewPanel, /class="task-review__student-preview-scroll"/); assert.match(reviewPanel, /]+studentPreviewSrc/); assert.match(reviewPanel, /scrolling="yes"/); assert.match(reviewPanel, /min-width:\s*1280px/, "嵌入学生页面应保留桌面端视口,窄区域改为滚动查看"); +assert.match(reviewPanel, /previewFrameHeight/, "外层应使用嵌入页同步的真实高度"); +assert.match(reviewPanel, /teacher-task-review-preview-height/, "外层应接收预览内容高度"); +assert.match(reviewPanel, /overflow:\s*scroll/, "外层预览应始终显示滚动轨道"); assert.match(reviewPanel, /grid-template-columns: minmax\(360px, 400px\) minmax\(0, 1fr\)/); assert.match(reviewPanel, /class="task-review__student-table"/); assert.match(reviewPanel, /type="selection" width="38"/);