duidui_mini_program/pages/camp_task_objective_questions/modules/result-service.js
2026-03-27 10:41:46 +08:00

217 lines
6.6 KiB
JavaScript

/**
* 客观题结果服务模块
* 负责试卷结果数据获取和处理
*/
import { questionApi } from '../../config/question_api.js';
/**
* 格式化时间显示(秒数转为 MM:SS 或 HH:MM:SS 格式)
* @param {Number} totalSeconds - 总秒数
* @returns {String} 格式化后的时间字符串
*/
export function formatTime(totalSeconds) {
if (totalSeconds < 0) totalSeconds = 0;
const hours = Math.floor(totalSeconds / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
const seconds = totalSeconds % 60;
const formatNumber = (num) => {
return num < 10 ? '0' + num : String(num);
};
if (hours > 0) {
return `${formatNumber(hours)}:${formatNumber(minutes)}:${formatNumber(seconds)}`;
} else {
return `${formatNumber(minutes)}:${formatNumber(seconds)}`;
}
}
/**
* 获取试卷和答题记录
* @param {String} paperId - 试卷ID
* @param {String} taskId - 任务ID
* @param {String} userId - 用户ID
* @returns {Promise} 处理后的结果数据
*/
export function fetchQuestionPaper(paperId, taskId, userId) {
return new Promise((resolve, reject) => {
if (!paperId) {
reject(new Error('试卷ID不能为空'));
return;
}
if (!userId) {
reject(new Error('用户未登录'));
return;
}
Promise.all([
questionApi.getAnswerRecord(userId, paperId, 1, 361),
questionApi.getPaperWithAnswers(paperId), // 使用新接口获取包含答案和解析的试卷数据
]).then(([recordRes, paperRes]) => {
// 处理试卷数据
let paperInfo = null;
if (paperRes.code === 200 && paperRes.data) {
paperInfo = paperRes.data;
} else if (paperRes.success === true && (paperRes.paper || paperRes.data)) {
paperInfo = paperRes.paper || paperRes.data;
}
if (!paperInfo) {
reject(new Error(paperRes.msg || '获取试卷失败'));
return;
}
// 处理答题记录
const records = recordRes.records || recordRes.data || [];
const answerRecordMap = {};
records.forEach(record => {
answerRecordMap[record.question_id] = record;
});
// 统计信息
const totalCount = records.length;
const correctCount = records.filter(r => r.is_correct === true).length;
const correctRate = totalCount > 0 ? (correctCount / totalCount * 100) : 0;
// 计算总用时
let usedTimeSeconds = 0;
if (records.length > 0) {
const sortedRecords = records.sort((a, b) => a.start_time - b.start_time);
const firstStartTime = sortedRecords[0].start_time;
const lastEndTime = sortedRecords[sortedRecords.length - 1].end_time;
usedTimeSeconds = lastEndTime - firstStartTime;
}
const usedTime = formatTime(usedTimeSeconds);
// 合并试卷题目和答题记录
const mapped = paperInfo.questions.map(q => {
let mappedQ = null;
if (q && (q.question_id || q.question_content || q.question_type)) {
// 旧结构
mappedQ = {
...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
})),
explanation: q.explanation || ''
};
} else {
// 新结构
const opts = Array.isArray(q.options) ? q.options.map((text, idx) => {
if (typeof text === 'string') {
return {
id: idx + 1,
content: text,
label: String.fromCharCode(65 + idx)
};
} else {
return {
...text,
id: text.id || text.option_id || (idx + 1),
content: text.content || text.option_content || text,
label: text.label || text.option_label || String.fromCharCode(65 + idx)
};
}
}) : [];
const mappedType = (q.type === 2 || q.type === 'single_choice') ? 'single_choice' : (q.type === 3 || q.type === 'multiple_choice' ? 'multiple_choice' : 'single_choice');
mappedQ = {
...q,
id: q.id,
title: q.title || q.content || '',
type: mappedType,
materials: q.materials || [],
options: opts,
explanation: q.explanation || ''
};
}
// 获取答题记录
const record = answerRecordMap[mappedQ.id];
const userAnswer = record ? record.user_answer : '';
// 优先使用题目本身的答案(新接口会返回),如果没有则使用答题记录中的答案
const correctAnswer = q.answer || (record ? record.correct_answer : '');
const isCorrect = record ? record.is_correct : false;
// 处理用户答案
const userAnswerArray = userAnswer ? (Array.isArray(userAnswer) ? userAnswer : [userAnswer]) : [];
const isUserAnswerEmpty = !userAnswer || userAnswer === '';
// 处理选项样式
const optionsWithStyle = mappedQ.options.map((opt, optIndex) => {
const optionLabel = opt.label || opt.option_label;
const isOptionCorrect = opt.is_correct || (opt.answer === 'true') || (optionLabel === correctAnswer);
const isUserSelected = userAnswerArray.includes(optionLabel);
let cssClass = '';
if (isOptionCorrect) {
cssClass = 'option-correct';
} else if (isUserSelected) {
cssClass = 'option-wrong';
}
// 确保每个选项都有唯一的 id
const optionId = opt.id || opt.option_id || (mappedQ.id ? `${mappedQ.id}_opt_${optIndex}` : `opt_${optIndex}`);
return {
...opt,
id: optionId,
content: opt.content || opt.option_content,
label: optionLabel,
isCorrect: isOptionCorrect,
cssClass: cssClass
};
});
// 获取解析内容,优先使用题目本身的解析(新接口会返回)
// 注意:空字符串也是有效值,需要明确检查
let answerAnalysis = '';
if (q.explanation !== undefined && q.explanation !== null && q.explanation !== '') {
answerAnalysis = q.explanation;
} else if (mappedQ.explanation !== undefined && mappedQ.explanation !== null && mappedQ.explanation !== '') {
answerAnalysis = mappedQ.explanation;
} else if (q.answer_analysis !== undefined && q.answer_analysis !== null && q.answer_analysis !== '') {
answerAnalysis = q.answer_analysis;
}
return {
...mappedQ,
options: optionsWithStyle,
cssClass: isCorrect ? 'arc-correct' : !isUserAnswerEmpty ? 'arc-wrong' : 'arc-unanswered',
correct_answer: correctAnswer,
user_answer: userAnswer,
is_correct: isCorrect,
answer_analysis: answerAnalysis
};
});
resolve({
paperInfo,
questions: mapped,
stats: {
totalCount,
correctCount,
correctRate,
usedTime,
usedTimeSeconds
}
});
})
.catch(err => {
console.error('API调用失败:', err);
reject(err);
});
});
}