feat: 综合大题改造(替代 Word 上传)+ MockExam 按组分支

中职/高职组以「综合大题」替代原 Word 文件上传:管理员在后台录入题干
(wangEditor 富文本,含表格),系统按组随机抽题,考生在 3 个小问内作答,
每小题 10 分、大题合计 30 分。

- api/admin.js / api/exam.js / stores/exam.js:大题题库 CRUD、抽题、作答与评分链路
- Competition.vue:Word 上传区块替换为大题作答区(3 小问 + 字数上限 + 富文本题干渲染)
- Admin.vue:大题题库管理、考生作答查看与人工评分
- MockExam.vue:按组分支——中职/高职显示综合大题,其余组保持 Word 答题;侧栏与提交提示同步
- RichEditor.vue + utils/richtext.js:题干富文本渲染前做白名单消毒(零依赖,纵深防御)

说明:big_questions / big_question_answers 建表迁移 023/024 随后端仓库提交。
This commit is contained in:
2026-09-21 11:17:59 +08:00
parent e8f0195b61
commit 1bfe007149
8 changed files with 1729 additions and 470 deletions

View File

@@ -20,7 +20,7 @@
<script setup>
import '@wangeditor/editor/dist/css/style.css'
import { onBeforeUnmount, ref, shallowRef, watch } from 'vue'
import { computed, onBeforeUnmount, ref, shallowRef, watch } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import { useAuthStore } from '@/stores/auth'
@@ -29,6 +29,9 @@ const props = defineProps({
height: { type: String, default: '320px' },
placeholder: { type: String, default: '请输入内容…' },
mode: { type: String, default: 'default' }, // 'default' | 'simple'
// 是否开放表格菜单。综合大题题干需要富文本表格,故显式开启;
// 默认 false 保持资讯正文等既有调用方的工具栏不变(行为兼容)。
enableTable: { type: Boolean, default: false },
})
const emit = defineEmits(['update:modelValue'])
@@ -49,14 +52,15 @@ watch(
}
)
const toolbarConfig = {
const toolbarConfig = computed(() => ({
excludeKeys: [
'group-video', // 轮播正文不需要视频
'insertTable',
'group-video', // 题干/正文不需要视频
// 未开启表格时隐藏插入表格入口;开启后除去该项,表格相关菜单恢复默认可见
...(props.enableTable ? [] : ['insertTable']),
'codeBlock',
'fullScreen',
],
}
}))
const editorConfig = {
placeholder: props.placeholder,