139 lines
4.5 KiB
JavaScript
139 lines
4.5 KiB
JavaScript
/**
|
||
* 客观题试卷服务模块
|
||
* 负责试卷数据获取和处理
|
||
*/
|
||
|
||
import { questionApi } from '../../../config/question_api.js';
|
||
|
||
/**
|
||
* 获取试卷详情
|
||
* @param {String} paperId - 试卷ID
|
||
* @param {String} taskId - 任务ID
|
||
* @returns {Promise} 处理后的试卷数据
|
||
*/
|
||
export function fetchQuestionPaper(paperId, taskId) {
|
||
return new Promise((resolve, reject) => {
|
||
if (!paperId) {
|
||
reject(new Error('试卷ID不能为空'));
|
||
return;
|
||
}
|
||
|
||
questionApi.getPaperDetail(paperId)
|
||
.then(res => {
|
||
let paperInfo = null;
|
||
if (res && res.code === 200 && res.data) {
|
||
paperInfo = res.data;
|
||
} else if (res && res.success === true && (res.paper || res.data)) {
|
||
paperInfo = res.paper || res.data;
|
||
}
|
||
|
||
if (paperInfo) {
|
||
if (!paperInfo.questions || !Array.isArray(paperInfo.questions)) {
|
||
reject(new Error('试卷数据格式错误'));
|
||
return;
|
||
}
|
||
|
||
const mapped = paperInfo.questions.map(q => {
|
||
// Fiber 后端返回的格式:QuestionInfo
|
||
// { id, type (QuestionType: 1=主观题, 2=选择题, 3=判断题, 4=填空题), title, content, answer, explanation, options ([]string), tags }
|
||
|
||
// 兼容旧格式(PHP后端)
|
||
if (q && (q.question_id || q.question_content || q.question_type)) {
|
||
return {
|
||
...q,
|
||
id: q.question_id,
|
||
title: q.question_content,
|
||
type: q.question_type,
|
||
materials: q.materials || [],
|
||
options: (q.options || []).map(opt => ({
|
||
...opt,
|
||
id: opt.option_id,
|
||
content: opt.option_content,
|
||
label: opt.option_label
|
||
})),
|
||
user_answer: q.user_answer || null,
|
||
explanation: q.explanation || ''
|
||
};
|
||
} else {
|
||
// Fiber 后端格式
|
||
// type: 1=主观题, 2=选择题(单选), 3=判断题, 4=填空题
|
||
// 对于客观题,type 应该是 2 (选择题)
|
||
const opts = Array.isArray(q.options) ? q.options.map((text, idx) => ({
|
||
id: idx + 1,
|
||
content: text,
|
||
label: String.fromCharCode(65 + idx) // A, B, C...
|
||
})) : [];
|
||
|
||
// 映射题目类型
|
||
// Fiber: 2=选择题 -> 前端: 'single_choice' 或 'multiple_choice'
|
||
// 这里默认是单选,如果需要判断多选,可能需要根据其他字段或答案格式
|
||
let mappedType = 'single_choice';
|
||
if (q.type === 2) {
|
||
// 选择题,根据答案是否包含逗号判断单选或多选
|
||
const answer = q.answer || '';
|
||
mappedType = answer.includes(',') ? 'multiple_choice' : 'single_choice';
|
||
} else if (q.type === 3) {
|
||
mappedType = 'true_false';
|
||
} else if (q.type === 4) {
|
||
mappedType = 'fill_blank';
|
||
}
|
||
|
||
return {
|
||
...q,
|
||
id: q.id,
|
||
title: q.title || q.content || '',
|
||
type: mappedType,
|
||
material_id: q.material_id || null, // 保留题目关联的材料ID
|
||
materials: q.materials || [], // Fiber 后端可能没有 materials 字段
|
||
options: opts,
|
||
user_answer: q.user_answer || null,
|
||
explanation: q.explanation || ''
|
||
};
|
||
}
|
||
});
|
||
|
||
const questions = mapped.filter(q => Array.isArray(q.options) && q.options.length > 0);
|
||
|
||
const answers = questions.map(question => {
|
||
const optionsLength = question.options.length;
|
||
const arr = new Array(optionsLength).fill(false);
|
||
if (question.user_answer) {
|
||
const userAnsArr = question.user_answer.split(',').map(s => s.trim()).filter(Boolean);
|
||
userAnsArr.forEach(ans => {
|
||
const idx = question.options.findIndex(opt => opt.label === ans);
|
||
if (idx !== -1) arr[idx] = true;
|
||
});
|
||
}
|
||
return arr;
|
||
});
|
||
|
||
// 确保 paperInfo 包含必要的字段
|
||
const finalPaperInfo = {
|
||
...paperInfo,
|
||
title: paperInfo.title || '',
|
||
description: paperInfo.description || '',
|
||
duration_minutes: paperInfo.duration_minutes || 0 // Fiber 后端可能没有此字段,默认为 0
|
||
};
|
||
|
||
// 材料列表:后端 /paper/detail 返回 paper.materials,用于背景层左右滑动展示
|
||
const materials = Array.isArray(paperInfo.materials) ? paperInfo.materials : [];
|
||
|
||
resolve({
|
||
paperInfo: finalPaperInfo,
|
||
questions,
|
||
answers,
|
||
questionAnsweredStatus: answers.map(arr => arr.some(v => v)),
|
||
materials
|
||
});
|
||
} else {
|
||
reject(new Error((res && res.message) || (res && res.msg) || '获取试卷失败'));
|
||
}
|
||
})
|
||
.catch(err => {
|
||
console.error('API调用失败:', err);
|
||
reject(err);
|
||
});
|
||
});
|
||
}
|
||
|