@ -28,7 +28,8 @@
< el -select v-model ="questionQuery.type" placeholder="全部题型" clearable @change="loadQuestions" >
< el -option v -for = " item in typeOptions " :key ="item.value" :label ="item.label" :value ="item.value" / >
< / e l - s e l e c t >
< el -select v-model ="questionQuery.taskKey" placeholder="全部项目" clearable @change="loadQuestions" style="width: 190px" >
<!-- 全部项目筛选暂时隐藏 -- >
< el -select v-if ="false" v-model="questionQuery.taskKey" placeholder="全部项目" clearable @change="loadQuestions" style="width: 190px" >
< el -option v -for = " item in projectOptions " :key ="item.taskKey" : label = "`${item.projectName} / ${item.taskName}`" :value ="item.taskKey" / >
< / e l - s e l e c t >
< el -input v -model = " questionQuery.keyword " placeholder = "搜索题干" clearable :prefix-icon ="Search" @keyup.enter ="loadQuestions" / >
@ -58,7 +59,7 @@
< input ref = "importInput" class = "import-file-input" type = "file" :accept ="importAccept" @change ="handleImportFile" / >
< / div >
< / section >
< el -table v-loading ="loading" :data=" q uestions" class="data-table">
< el -table v-loading ="loading" :data=" pagedQ uestions" class="data-table">
< el -table -column label = "题型" min -width = " 110 " > < template # default = "{ row }" > < el -tag :type ="typeTone[row.type]" > { { typeName [ row . type ] } } < / e l - t a g > < / t e m p l a t e > < / e l - t a b l e - c o l u m n >
< el -table -column prop = "stem" label = "题干" min -width = " 420 " show -overflow -tooltip / >
< el -table -column label = "题目来源" width = "110" > < template # default = "{ row }" > < el -tag : type = "row.sourceType === 'PLATFORM' ? 'success' : 'info'" > { { row . sourceType === 'PLATFORM' ? '平台题库' : '教师自建' } } < / e l - t a g > < / t e m p l a t e > < / e l - t a b l e - c o l u m n >
@ -78,6 +79,16 @@
< / div >
< / template >
< / e l - t a b l e >
< div v-if ="questions.length" class="question-pager" >
< el -pagination
layout = "total, prev, pager, next, sizes, jumper"
: total = "questions.length"
v - model : current - page = "questionPager.page"
v - model : page - size = "questionPager.pageSize"
: page - sizes = "[10, 20, 50, 100]"
background
/ >
< / div >
< / e l - t a b - p a n e >
< / e l - t a b s >
@ -130,6 +141,12 @@ 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 questionPager = reactive ( { page : 1 , pageSize : 10 } ) ;
const pagedQuestions = computed ( ( ) => {
const start = ( questionPager . page - 1 ) * questionPager . pageSize ;
return questions . 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 ( ) ) ;
const questionRules = { type : [ { required : true , message : "请选择题型" } ] , stem : [ { required : true , message : "请输入题干" } ] , answer : [ { required : true , message : "请输入参考答案" } ] } ;
@ -140,7 +157,7 @@ onMounted(() => Promise.all([loadQuestions(), loadExams(), loadProjects()]));
let examsMounted = false ; / / K e e p A l i v e 缓 存 页 面 : 再 次 进 入 时 刷 新 考 试 列 表 ( 新 建 / 发 布 后 无 需 手 动 刷 新 ) , 首 次 激 活 跳 过 避 免 与 o n M o u n t e d 重 复 请 求
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 { question s. value = ( await examApi . getQuestions ( questionQuery ) ) . data || [ ] ; } finally { loading . value = false ; } }
async function loadQuestions ( ) { loading . value = true ; try { question Pager. page = 1 ; question s. value = ( await examApi . getQuestions ( questionQuery ) ) . data || [ ] ; } finally { loading . value = false ; } }
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' ) ; }
@ -234,6 +251,13 @@ function durationBetween(row) { if (!row.startTime || !row.endTime) return 0; re
display : none ;
}
/* ===== 题库分页(外观继承自 teacher-light.scss 全局样式,仅控制布局)===== */
. question - pager {
display : flex ;
justify - content : flex - end ;
margin - top : var ( -- sp - 4 ) ;
}
/* ===== 数据表格(纯白 + 灰线)===== */
. data - table {
width : 100 % ;