diff --git a/src/assets/styles/sidebar.scss b/src/assets/styles/sidebar.scss index 57435f0..788f1d7 100644 --- a/src/assets/styles/sidebar.scss +++ b/src/assets/styles/sidebar.scss @@ -1013,8 +1013,9 @@ * 同时隐藏教师端唯一的分组标题"教学管理"(标识),仅保留菜单项 */ #app .teacherLayout { + --teacher-sidebar-width: 180px; .main-container { - margin-left: 180px !important; + margin-left: var(--teacher-sidebar-width) !important; } // 收起后侧边栏仅保留 64px 图标轨道,主内容同步释放展开态的空间。 @@ -1023,7 +1024,7 @@ } .sidebar-container { - width: 180px !important; + width: var(--teacher-sidebar-width) !important; } // 隐藏教师端顶部分组标题("教学管理"标识),不影响学生端多分组标题 .student-course-nav > .student-course-heading { diff --git a/src/views/exam/index.vue b/src/views/exam/index.vue index 99c2ad7..0c978af 100644 --- a/src/views/exam/index.vue +++ b/src/views/exam/index.vue @@ -6,8 +6,8 @@ diff --git a/src/views/teacherEnd/exam/editor.vue b/src/views/teacherEnd/exam/editor.vue index d409a3f..3f76792 100644 --- a/src/views/teacherEnd/exam/editor.vue +++ b/src/views/teacherEnd/exam/editor.vue @@ -193,7 +193,7 @@ - + @@ -1048,7 +1048,7 @@ function toBoolean(value, fallback) { if (value === undefined || value === null diff --git a/src/views/teacherEnd/exam/index.vue b/src/views/teacherEnd/exam/index.vue index adc0c63..9c8eb6c 100644 --- a/src/views/teacherEnd/exam/index.vue +++ b/src/views/teacherEnd/exam/index.vue @@ -15,6 +15,7 @@
撤回 编辑 + 删除 指定人回退
@@ -28,6 +29,10 @@ + + + + @@ -79,10 +84,10 @@ -
+
正确错误 - 上传资料 + 上传资料 {{ questionForm.attachmentName }} @@ -141,11 +146,17 @@ const typeName = Object.fromEntries(typeOptions.map((item) => [item.value, item. const typeTone = { SINGLE: "", MULTIPLE: "success", TRUE_FALSE: "warning", SHORT_ANSWER: "info" }; const statusMeta = { DRAFT: { label: "未发布", tone: "info" }, NOT_STARTED: { label: "未开始", tone: "" }, IN_PROGRESS: { label: "进行中", tone: "success" }, ENDED: { label: "已结束", tone: "warning" } }; const questionQuery = reactive({ type: "", taskKey: "", keyword: "" }); +const sourceFilter = ref(""); // 题目来源前端筛选:PLATFORM=平台题库 / CUSTOM=教师自建(非 PLATFORM) // 题库列表使用前端分页:后端一次返回全部,前端按页切片 const questionPager = reactive({ page: 1, pageSize: 10 }); +const filteredQuestions = computed(() => { + const st = sourceFilter.value; + if (!st) return questions.value; + return questions.value.filter(q => st === "PLATFORM" ? q.sourceType === "PLATFORM" : q.sourceType !== "PLATFORM"); +}); const pagedQuestions = computed(() => { const start = (questionPager.page - 1) * questionPager.pageSize; - return questions.value.slice(start, start + questionPager.pageSize); + return filteredQuestions.value.slice(start, start + questionPager.pageSize); }); const emptyQuestion = () => ({ id: null, taskKey: "", type: "SINGLE", stem: "", options: [{ label: "A", content: "" }, { label: "B", content: "" }, { label: "C", content: "" }, { label: "D", content: "" }], answer: [], analysis: "", attachmentName: "", attachmentUrl: "" }); const questionForm = reactive(emptyQuestion()); @@ -158,6 +169,7 @@ let examsMounted = false; // KeepAlive 缓存页面:再次进入时刷新考 onActivated(() => { if (examsMounted) loadExams(); examsMounted = true; }); async function loadProjects() { try { projectOptions.value = (await examApi.getQuestionProjects()).data || []; } catch (e) { projectOptions.value = []; } } async function loadQuestions() { loading.value = true; try { questionPager.page = 1; questions.value = (await examApi.getQuestions(questionQuery)).data || []; } finally { loading.value = false; } } +function resetQuestionPager() { questionPager.page = 1; } async function loadExams() { loading.value = true; try { exams.value = (await examApi.getTeacherExams({ keyword: examKeyword.value })).data || []; } finally { loading.value = false; } } function openQuestion(row) { questionReadonly.value = row?.sourceType === 'PLATFORM'; Object.assign(questionForm, row ? JSON.parse(JSON.stringify(row)) : emptyQuestion()); if (!Array.isArray(questionForm.answer) && isChoice.value) questionForm.answer = []; questionDialog.value = true; } function openAi() { router.push('/exam/ai-generate'); } @@ -175,7 +187,7 @@ async function doImport({ file }) { importing.value = true; try { const form = n async function downloadTemplate(format) { const extension = format === "excel" ? "xlsx" : "docx"; saveAs(await examApi.downloadQuestionTemplate(format), `考试题库${format === "excel" ? "Excel" : "Word"}导入模板.${extension}`); } async function publish(row) { await ElMessageBox.confirm(`确认发布“${row.name}”?发布后将在设定时间自动开始。`, "发布考试", { type: "warning" }); await examApi.publishExam(row.id); ElMessage.success("已发布"); loadExams(); } async function withdraw(row) { await examApi.withdrawExam(row.id); ElMessage.success("已撤回"); loadExams(); } -async function removeExam(row) { await ElMessageBox.confirm(`确认永久删除“${row.name}”?仅在已导出全部答卷后允许删除。`, "删除考试", { type: "warning", confirmButtonText: "确认删除" }); await examApi.deleteExam(row.id); ElMessage.success("已删除"); loadExams(); } +async function removeExam(row) { const message = row.status === "DRAFT" ? `确认删除未发布的考试“${row.name}”?删除后无法恢复。` : `确认永久删除“${row.name}”?仅在已导出全部答卷后允许删除。`; await ElMessageBox.confirm(message, "删除考试", { type: "warning", confirmButtonText: "确认删除" }); await examApi.deleteExam(row.id); ElMessage.success("已删除"); loadExams(); } async function handleExport(command, row) { const actions = { paper: [examApi.exportExamPaper, `${row.name}试卷.docx`], scores: [examApi.exportExamScores, `${row.name}班级成绩.xlsx`], submissions: [examApi.exportExamSubmissions, `${row.name}全部试卷.zip`] }; const [action, filename] = actions[command]; saveAs(await action(row.id), filename); if (command === "submissions") loadExams(); } function displayAnswer(value) { if (Array.isArray(value)) return value.join("、"); if (value === true) return "正确"; if (value === false) return "错误"; return value || "-"; } function formatTime(value) { return value ? new Date(value).toLocaleString("zh-CN", { hour12: false }).replaceAll("/", "-") : "-"; }