You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dianshang-qianduan/src/views/teacherEnd/taskReview/StudentTaskReadonlyPreview.vue

62 lines
2.4 KiB
Vue

<template>
<main class="student-task-readonly-preview" @click.capture="guardPreviewInteraction" @keydown.capture="guardPreviewInteraction">
<component v-if="previewComponent" :is="previewComponent" v-bind="previewProps" />
<el-empty v-else :description="emptyDescription" :image-size="112" />
</main>
</template>
<script setup>
import { getTrainingReviewPreviewContext } from "@/utils/trainingReviewPreview";
import { studentTaskPreviewComponentByKey, studentTaskPreviewPropsByKey } from "./studentTaskPreviewMap";
const route = useRoute();
const previewComponent = shallowRef(null);
const previewProps = ref({});
const emptyDescription = ref("正在加载学生任务页面");
async function loadPreview() {
previewComponent.value = null;
const taskKey = String(route.query.taskKey || "");
const preview = getTrainingReviewPreviewContext();
const loader = studentTaskPreviewComponentByKey[taskKey];
if (!preview || preview.taskKey !== taskKey) {
emptyDescription.value = "学生作答预览已失效,请返回任务评阅重新选择学生";
return;
}
if (!loader) {
emptyDescription.value = "该实训任务暂不支持页面预览";
return;
}
try {
previewComponent.value = (await loader()).default;
previewProps.value = studentTaskPreviewPropsByKey[taskKey]?.(taskKey) || {};
} catch (_) {
emptyDescription.value = "学生任务页面加载失败,请刷新后重试";
}
}
watch(() => [route.query.taskKey, route.query.reviewPreviewKey], loadPreview, { immediate: true });
function guardPreviewInteraction(event) {
const target = event.target instanceof Element ? event.target : null;
if (!target) return;
if (target.closest("input, textarea, select, [contenteditable='true'], .el-input, .el-textarea, .el-select, .el-checkbox, .el-radio, .el-switch")) {
event.preventDefault();
event.stopImmediatePropagation();
return;
}
const action = target.closest("button, a, [role='button'], [role='tab'], .el-step");
if (action && !isStepNavigation(action)) {
event.preventDefault();
event.stopImmediatePropagation();
}
}
function isStepNavigation(element) {
if (element.matches("[role='tab'], .el-step")) return true;
const label = String(element.getAttribute("aria-label") || "");
const text = `${label} ${String(element.textContent || "")}`.replace(/\s+/g, " ").trim();
return /(上一步|下一步|第\s*\d+\s*步|切换.*步骤|步骤.*切换)/.test(text);
}
</script>