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, /