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.
62 lines
2.4 KiB
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>
|