electron-vue-exam-single/electron/db/examing.js

1298 lines
43 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 导入必要的模块和函数
import { getSystemDbPath, getUserDbPath } from './path.js';
import { getDbConnection, closeAllConnections } from './index.js';
import { batchInsert } from './utils.js';
// 新增:格式化日期为年-月-日 时:分:秒
export function formatDateTime(date) {
if (!(date instanceof Date)) {
date = new Date(date);
}
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
/**
* 生成考生试卷
* @param {Object} examineeData - 考生数据
* @param {Object} examData - 考试数据
* @returns {Promise<Object>} - 包含试卷ID和状态的对象
*/
export async function generateExamineePaper(examineeData, examData) {
try {
// 1. 获取数据库连接
const systemDb = await getDbConnection(getSystemDbPath());
const userDb = await getDbConnection(getUserDbPath());
// 2. 处理考生数据,将空值转换为空字符串
console.log('开始处理考生数据...', examineeData);
const processedExamineeData = {
id: examineeData.id,
examinee_name: examineeData.examinee_name || '',
examinee_gender: examineeData.examinee_gender || '',
examinee_unit: examineeData.examinee_unit || '',
written_exam_room: examineeData.written_exam_room || '',
written_exam_seat: examineeData.written_exam_seat || '',
computer_exam_room: examineeData.computer_exam_room || '',
computer_exam_seat: examineeData.computer_exam_seat || '',
examinee_id_card: examineeData.examinee_id_card || '',
examinee_admission_ticket: examineeData.examinee_admission_ticket || ''
};
// 3. 检查考生是否已存在
console.log('检查考生是否已存在...');
const existingExaminee = await userDb.getAsync(
`SELECT id FROM examinee WHERE id = ?`,
[processedExamineeData.id]
);
let examineeId;
if (existingExaminee) {
// 考生已存在
examineeId = existingExaminee.id;
console.log(`考生已存在ID: ${examineeId}`);
/// TODO: 更新考生信息
// 实现考生信息更新
await userDb.runAsync(
`UPDATE examinee SET
examinee_name = ?,
examinee_gender = ?,
examinee_unit = ?,
written_exam_room = ?,
written_exam_seat = ?,
computer_exam_room = ?,
computer_exam_seat = ?,
examinee_admission_ticket = ?,
created_at = ?
WHERE id = ?`,
[
processedExamineeData.examinee_name,
processedExamineeData.examinee_gender,
processedExamineeData.examinee_unit,
processedExamineeData.written_exam_room,
processedExamineeData.written_exam_seat,
processedExamineeData.computer_exam_room,
processedExamineeData.computer_exam_seat,
processedExamineeData.examinee_admission_ticket,
new Date().toISOString(),
examineeId
]
);
console.log(`考生信息已更新ID: ${examineeId}`);
// 4. 检查该考生是否有试卷记录
console.log('检查考生试卷记录...');
const existingPaper = await userDb.getAsync(
`SELECT id, paper_status FROM examinee_papers WHERE examinee_id = ? ORDER BY created_at DESC LIMIT 1`,
[examineeId]
);
if (existingPaper) {
// 试卷已存在
const paperId = existingPaper.id;
const paperStatus = existingPaper.paper_status;
console.log(`试卷已存在ID: ${paperId},状态: ${paperStatus}`);
if (paperStatus === 2) {
// 状态为2已完成考试不能重复考试
console.log('考生已完成考试,不能重复考试');
return {
success: false,
message: '已完成考试,不能重复考试。'
};
// } else if (paperStatus === 1) {
// // 状态为1进行中直接返回该试卷
// console.log('返回进行中的考试');
// return {
// success: true,
// paperId,
// examineeId,
// message: '已进入上次进行中的考试'
// };
// } else if (paperStatus === 0) {
} else {
// 状态为0未开始删除旧试卷及相关数据重新组卷
console.log('删除未开始的旧试卷及相关数据...');
// 删除question_choices记录
await userDb.runAsync(
`DELETE FROM question_choices WHERE question_id IN (
SELECT id FROM paper_questions WHERE paper_id = ?
)`,
[paperId]
);
// 删除question_fill_blanks记录
await userDb.runAsync(
`DELETE FROM question_fill_blanks WHERE question_id IN (
SELECT id FROM paper_questions WHERE paper_id = ?
)`,
[paperId]
);
// 删除question_images记录
await userDb.runAsync(
`DELETE FROM question_images WHERE question_id IN (
SELECT id FROM paper_questions WHERE paper_id = ?
)`,
[paperId]
);
// 删除question_datasets记录
await userDb.runAsync(
`DELETE FROM question_datasets WHERE question_id IN (
SELECT id FROM paper_questions WHERE paper_id = ?
)`,
[paperId]
);
// 删除paper_questions记录
await userDb.runAsync(
`DELETE FROM paper_questions WHERE paper_id = ?`,
[paperId]
);
// 删除examinee_papers记录
await userDb.runAsync(
`DELETE FROM examinee_papers WHERE id = ?`,
[paperId]
);
console.log('旧试卷数据删除完成');
}
}
} else {
// 考生不存在,添加新考生
console.log('添加新考生...');
const examineeResult = await userDb.runAsync(
`INSERT INTO examinee (
id, examinee_name, examinee_gender, examinee_unit,
written_exam_room, written_exam_seat, computer_exam_room,
computer_exam_seat, examinee_id_card, examinee_admission_ticket, created_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
[
processedExamineeData.id,
processedExamineeData.examinee_name,
processedExamineeData.examinee_gender,
processedExamineeData.examinee_unit,
processedExamineeData.written_exam_room,
processedExamineeData.written_exam_seat,
processedExamineeData.computer_exam_room,
processedExamineeData.computer_exam_seat,
processedExamineeData.examinee_id_card,
processedExamineeData.examinee_admission_ticket,
new Date().toISOString() // 修改为toISOString格式
]
);
examineeId = examineeResult.lastID;
console.log(`新考生添加成功ID: ${examineeId}`);
}
// 5. 生成新的examinee_papers记录
console.log('生成新试卷记录...');
const paperResult = await userDb.runAsync(
`INSERT INTO examinee_papers (
examinee_id, paper_minutes, paper_minutes_min, paper_status
) VALUES (?, ?, ?, ?)`,
[examineeId, examData.exam_minutes, examData.exam_minutes_min, 0] // 0表示未开始
);
const paperId = paperResult.lastID;
console.log(`试卷记录生成成功ID: ${paperId}`);
// 6. 从system库获取所有questions记录
console.log('获取系统题库...');
const systemQuestions = await systemDb.allAsync('SELECT * FROM questions');
console.log(`成功获取 ${systemQuestions.length} 道题目`);
// 打乱题目顺序
const shuffledQuestions = [...systemQuestions].sort(() => Math.random() - 0.5);
// 7. 准备paper_questions数据
console.log('准备试卷题目数据...');
const paperQuestionsData = shuffledQuestions.map(question => ({
examinee_id: examineeId,
paper_id: paperId,
question_type: question.question_type,
question_name: question.question_name,
question_description: question.question_description,
created_at: new Date().toISOString() // 修改为toISOString格式
}));
// 创建question_id映射关系system_id -> user_id
const questionIdMap = new Map();
// 8. 插入paper_questions数据并记录映射关系
console.log('插入试卷题目数据...');
for (let i = 0; i < paperQuestionsData.length; i++) {
const result = await userDb.runAsync(
`INSERT INTO paper_questions (
examinee_id, paper_id, question_type,
question_name, question_description, created_at
) VALUES (?, ?, ?, ?, ?, ?)`,
[
paperQuestionsData[i].examinee_id,
paperQuestionsData[i].paper_id,
paperQuestionsData[i].question_type,
paperQuestionsData[i].question_name,
paperQuestionsData[i].question_description,
paperQuestionsData[i].created_at
]
);
// 使用shuffledQuestions[i].id而不是systemQuestions[i].id
questionIdMap.set(shuffledQuestions[i].id, result.lastID);
}
console.log(`成功插入 ${paperQuestionsData.length} 条试卷题目数据`);
// 9. 处理question_datasets表
console.log('处理数据集...');
const systemDatasets = await systemDb.allAsync('SELECT * FROM question_datasets');
const userDatasets = systemDatasets
.filter(dataset => questionIdMap.has(dataset.question_id))
.map(dataset => ({
question_id: questionIdMap.get(dataset.question_id),
dataset_name: dataset.dataset_name,
dataset_data: dataset.dataset_data,
created_at: new Date().toISOString() // 修改为toISOString格式
}));
if (userDatasets.length > 0) {
await batchInsert(userDb, 'question_datasets', userDatasets);
}
console.log(`成功处理 ${userDatasets.length} 个数据集`);
// 10. 处理question_images表
console.log('处理图片...');
const systemImages = await systemDb.allAsync('SELECT * FROM question_images');
const userImages = systemImages
.filter(image => questionIdMap.has(image.question_id))
.map(image => ({
question_id: questionIdMap.get(image.question_id),
image_name: image.image_name,
image_base64: image.image_base64,
created_at: new Date().toISOString(), // 修改为toISOString格式
updated_at: new Date().toISOString() // 修改为toISOString格式
}));
if (userImages.length > 0) {
await batchInsert(userDb, 'question_images', userImages);
}
console.log(`成功处理 ${userImages.length} 张图片`);
// 11. 处理question_choices表
console.log('处理选择题...');
const systemChoices = await systemDb.allAsync('SELECT * FROM question_choices');
let userChoices = systemChoices
.filter(choice => questionIdMap.has(choice.question_id))
.map(choice => {
// 打乱选项顺序
const options = JSON.parse(choice.choice_options);
// const sortedOptions = [...options].sort();
return {
question_id: questionIdMap.get(choice.question_id),
choice_description: choice.choice_description,
choice_type: choice.choice_type,
choice_options: JSON.stringify(options),
correct_answers: choice.correct_answers,
examinee_answers: '',
score: choice.score,
score_real: 0,
created_at: new Date().toISOString(), // 修改为toISOString格式
updated_at: new Date().toISOString() // 修改为toISOString格式
};
});
// 打乱选择题顺序
userChoices = userChoices.sort(() => Math.random() - 0.5);
if (userChoices.length > 0) {
await batchInsert(userDb, 'question_choices', userChoices);
}
console.log(`成功处理 ${userChoices.length} 道选择题`);
// 12. 处理question_fill_blanks表
console.log('处理填空题...');
const systemFillBlanks = await systemDb.allAsync('SELECT * FROM question_fill_blanks');
let userFillBlanks = systemFillBlanks
.filter(blank => questionIdMap.has(blank.question_id))
.map(blank => ({
question_id: questionIdMap.get(blank.question_id),
blank_description: blank.blank_description,
blank_count: blank.blank_count,
correct_answers: blank.correct_answers,
examinee_answers: '',
score: blank.score,
score_real: 0,
created_at: new Date().toISOString(), // 修改为toISOString格式
updated_at: new Date().toISOString() // 修改为toISOString格式
}));
// 打乱填空题顺序
userFillBlanks = userFillBlanks.sort(() => Math.random() - 0.5);
if (userFillBlanks.length > 0) {
await batchInsert(userDb, 'question_fill_blanks', userFillBlanks);
}
console.log(`成功处理 ${userFillBlanks.length} 道填空题`);
// 新增: 计算试卷总分
console.log('计算试卷总分...');
// 查询所有选择题分数
const choicesScoreResult = await userDb.getAsync(
`SELECT SUM(score) as total FROM question_choices WHERE question_id IN (
SELECT id FROM paper_questions WHERE paper_id = ?
)`,
[paperId]
);
const choicesScore = choicesScoreResult.total || 0;
// 查询所有填空题分数
const fillBlanksScoreResult = await userDb.getAsync(
`SELECT SUM(score) as total FROM question_fill_blanks WHERE question_id IN (
SELECT id FROM paper_questions WHERE paper_id = ?
)`,
[paperId]
);
const fillBlanksScore = fillBlanksScoreResult.total || 0;
// 计算总分
const paperScore = choicesScore + fillBlanksScore;
console.log(`试卷总分计算完成: ${paperScore}`);
// 更新试卷总分
await userDb.runAsync(
`UPDATE examinee_papers SET paper_score = ? WHERE id = ?`,
[paperScore, paperId]
);
// 返回成功结果
// 先查询完整的试卷数据
const paperData = await userDb.getAsync(
`SELECT * FROM examinee_papers WHERE id = ?`,
[paperId]
);
// 查询试卷题目数量
const questionCount = await userDb.getAsync(
`SELECT COUNT(*) as count FROM paper_questions WHERE paper_id = ?`,
[paperId]
);
// 构建完整的试卷数据对象
const completePaperData = {
...paperData,
question_count: questionCount.count,
examinee_id: examineeId,
examinee_name: processedExamineeData.examinee_name,
examinee_id_card: processedExamineeData.examinee_id_card,
examinee_admission_ticket: processedExamineeData.examinee_admission_ticket
};
return {
success: true,
message: '试卷生成成功',
data: completePaperData
};
} catch (error) {
console.error('生成试卷失败:', error);
return {
success: false,
message: `生成试卷失败: ${error.message}`,
data: null
};
}
}
/**
* 加载试卷试题序列
* @param {number} paperId - 试卷ID
* @returns {Promise<Array>} - 包含试题序列的数组
*/
export async function loadPaperSerial(paperId) {
// 函数实现保持不变
try {
// 1. 获取数据库连接
const userDb = await getDbConnection(getUserDbPath());
const systemDb = await getDbConnection(getSystemDbPath());
// 2. 查询题型字典,获取题型名称
console.log('开始查询题型字典...');
const questionTypeDict = await systemDb.allAsync(
`SELECT item_code, item_name FROM dict_items WHERE type_code = ?`,
['question_type']
);
const questionTypeMap = new Map();
questionTypeDict.forEach(item => {
questionTypeMap.set(item.item_code, item.item_name);
});
console.log('成功获取题型字典');
// 3. 查询试卷中的所有题目并按question_type和id升序排序
console.log(`开始查询试卷 ${paperId} 的所有题目...`);
const paperQuestions = await userDb.allAsync(
`SELECT * FROM paper_questions
WHERE paper_id = ?
ORDER BY question_type ASC, id ASC`,
[paperId]
);
console.log(`成功获取试卷 ${paperId}${paperQuestions.length} 道题目`);
// 4. 构建试题序列
const paperSerial = [];
let addedCount = 0;
let skippedCount = 0;
let globalSerialNo = 1; // 全局序列号
console.log('开始构建试题序列...');
console.log(`试卷 ${paperId} 的题目列表:`);
paperQuestions.forEach((q, idx) => {
console.log(` ${idx + 1}. ID: ${q.id}, 题型: ${q.question_type}`);
});
for (let i = 0; i < paperQuestions.length; i++) {
const question = paperQuestions[i];
const questionType = question.question_type;
const questionTypeName = questionTypeMap.get(questionType) || '未知题型';
console.log(`处理第 ${i + 1} 题题干 (ID: ${question.id}, 题型: ${questionType})`);
let tableName = '';
let relatedRecords = [];
// 根据题型查询相关表的所有记录
if (questionType === 'choice') { // 选择题
tableName = 'question_choices';
relatedRecords = await userDb.allAsync(
`SELECT id, examinee_answers FROM question_choices WHERE question_id = ?`,
[question.id]
);
console.log(` 找到 ${relatedRecords.length} 条选择题记录`);
} else if (questionType === 'fill_blank') { // 填空题
tableName = 'question_fill_blanks';
relatedRecords = await userDb.allAsync(
`SELECT id, examinee_answers FROM question_fill_blanks WHERE question_id = ?`,
[question.id]
);
console.log(` 找到 ${relatedRecords.length} 条填空题记录`);
} else {
console.log(` 未处理的题型: ${questionType}`);
}
// 为每条记录添加到试题序列
if (relatedRecords.length > 0) {
relatedRecords.forEach((record, recordIdx) => {
const answered = record.examinee_answers ? 1 : 0;
const serialNo = globalSerialNo++;
// 添加到试题序列
paperSerial.push({
serial_no: serialNo,
id: record.id,
table_name: tableName,
question_id: question.id,
question_type: questionType,
question_type_name: questionTypeName,
[tableName === 'question_choices' ? 'choice_id' : 'fill_blank_id']: record.id,
answered
});
console.log(` 添加第 ${recordIdx + 1} 个具体问题到试题序列,序列号: ${serialNo}`);
addedCount++;
});
} else {
console.log(` 未找到相关记录,跳过`);
skippedCount++;
}
}
console.log(`试题序列构建完成: 共 ${paperQuestions.length} 道题,添加 ${addedCount} 道,跳过 ${skippedCount}`);
return paperSerial;
} catch (error) {
console.error('加载试卷试题序列失败:', error);
return [];
}
}
/**
* 根据表名和ID获取完整的试题数据
* @param {string} tableName - 表名 (question_choices 或 question_fill_blanks)
* @param {number} id - 记录ID
* @returns {Promise<Object>} - 完整的试题数据
*/
export async function getQuestionByRelatedId(tableName, id) {
try {
// 1. 获取数据库连接
const userDb = await getDbConnection(getUserDbPath());
const systemDb = await getDbConnection(getSystemDbPath());
// 2. 验证表名
// if (!['question_choices', 'question_fill_blanks'].includes(tableName)) {
// throw new Error('无效的表名,只能是 question_choices 或 question_fill_blanks');
// }
// 3. 查询相关表获取question_id
console.log(`查询 ${tableName}ID: ${id}`);
const relatedRecord = await userDb.getAsync(
`SELECT * FROM ${tableName} WHERE id = ?`,
[id]
);
if (!relatedRecord) {
throw new Error(`未找到 ${tableName} 表中ID为 ${id} 的记录`);
}
const questionId = relatedRecord.question_id;
console.log(`找到关联的题干ID: ${questionId}`);
// 4. 查询题干信息
const question = await userDb.getAsync(
`SELECT * FROM paper_questions WHERE id = ?`,
[questionId]
);
if (!question) {
throw new Error(`未找到题干ID为 ${questionId} 的记录`);
}
// 5. 查询题型字典信息
const questionType = question.question_type;
const dictItem = await systemDb.getAsync(
`SELECT * FROM dict_items WHERE item_code = ? AND type_code = 'question_type'`,
[questionType]
);
// 6. 查询关联的数据集
const datasets = await userDb.allAsync(
`SELECT * FROM question_datasets WHERE question_id = ?`,
[questionId]
);
// 7. 查询关联的图片
const images = await userDb.allAsync(
`SELECT * FROM question_images WHERE question_id = ?`,
[questionId]
);
// 8. 根据题型查询关联问题
// let relatedQuestionData = [];
// if (questionType === 'choice') {
// relatedQuestionData = await userDb.allAsync(
// `SELECT * FROM question_choices WHERE question_id = ?`,
// [questionId]
// );
// // 将选项、正确答案和考生答案解析为数组
// relatedQuestionData.forEach(item => {
// // 解析选项
// if (item.choice_options) {
// try {
// item.choice_options = JSON.parse(item.choice_options);
// if (!Array.isArray(item.choice_options)) {
// item.choice_options = [item.choice_options];
// }
// } catch (e) {
// console.error('解析选项失败:', e);
// item.choice_options = []; // 解析失败时设置为空数组
// }
// } else {
// item.choice_options = [];
// }
// // 解析正确答案
// if (item.correct_answers) {
// try {
// item.correct_answers = JSON.parse(item.correct_answers);
// if (!Array.isArray(item.correct_answers)) {
// item.correct_answers = [item.correct_answers];
// }
// } catch (e) {
// console.error('解析正确答案失败:', e);
// item.correct_answers = []; // 解析失败时设置为空数组
// }
// } else {
// item.correct_answers = [];
// }
// // 解析考生答案
// if (item.examinee_answers) {
// // 处理空字符串情况
// if (item.examinee_answers.trim() === '') {
// item.examinee_answers = [];
// } else {
// try {
// item.examinee_answers = JSON.parse(item.examinee_answers);
// if (!Array.isArray(item.examinee_answers)) {
// item.examinee_answers = [item.examinee_answers];
// }
// } catch (e) {
// console.error('解析考生答案失败:', e);
// item.examinee_answers = []; // 解析失败时设置为空数组
// }
// }
// } else {
// item.examinee_answers = [];
// }
// });
// } else if (questionType === 'fill_blank') {
// relatedQuestionData = await userDb.allAsync(
// `SELECT * FROM question_fill_blanks WHERE question_id = ?`,
// [questionId]
// );
// // 解析填空题的正确答案和考生答案
// relatedQuestionData.forEach(item => {
// // 解析正确答案
// if (item.correct_answers) {
// try {
// item.correct_answers = JSON.parse(item.correct_answers);
// // 确保结果是数组
// if (!Array.isArray(item.correct_answers)) {
// item.correct_answers = [item.correct_answers];
// }
// } catch (e) {
// console.error('解析正确答案失败:', e);
// item.correct_answers = [];
// }
// } else {
// item.correct_answers = [];
// }
// // 解析考生答案
// if (item.examinee_answers) {
// // 处理空字符串情况
// if (item.examinee_answers.trim() === '') {
// item.examinee_answers = [];
// } else {
// try {
// item.examinee_answers = JSON.parse(item.examinee_answers);
// // 确保结果是数组
// if (!Array.isArray(item.examinee_answers)) {
// item.examinee_answers = [item.examinee_answers];
// }
// } catch (e) {
// console.error('解析考生答案失败:', e);
// item.examinee_answers = [];
// }
// }
// } else {
// item.examinee_answers = [];
// }
// });
// }
// 9. 构建返回结果
question.datasets = datasets;
question.images = images;
question.type_info = dictItem || null;
// 将关联问题数据添加到question对象
// if (relatedQuestionData.length > 0) {
// if (questionType === 'choice') {
// question.choices = relatedQuestionData;
// } else if (questionType === 'fill_blank') {
// question.fill_blanks = relatedQuestionData;
// }
// }
/// TODO: 如果question.question_type是choice
/// 把relatedRecord的choice_options、correct_answers、examinee_answers解析成数组注意有可能是空字符串
/// 如果是fill_blank把relatedRecord的correct_answers、examinee_answers解析成数组
/// 解析选项
if (question.question_type === 'choice') {
if (relatedRecord.choice_options) {
try {
relatedRecord.choice_options = JSON.parse(relatedRecord.choice_options);
if (!Array.isArray(relatedRecord.choice_options)) {
relatedRecord.choice_options = [relatedRecord.choice_options];
}
} catch (e) {
console.error('解析选项失败:', e);
relatedRecord.choice_options = []; // 解析失败时设置为空数组
}
} else {
relatedRecord.choice_options = [];
}
}
/// 解析正确答案
if (question.question_type === 'choice') {
if (relatedRecord.correct_answers) {
try {
relatedRecord.correct_answers = JSON.parse(relatedRecord.correct_answers);
if (!Array.isArray(relatedRecord.correct_answers)) {
relatedRecord.correct_answers = [relatedRecord.correct_answers];
}
} catch (e) {
console.error('解析正确答案失败:', e);
relatedRecord.correct_answers = []; // 解析失败时设置为空数组
}
} else {
relatedRecord.correct_answers = [];
}
}
/// 解析考生答案
if (question.question_type === 'choice') {
if (relatedRecord.examinee_answers) {
try {
relatedRecord.examinee_answers = JSON.parse(relatedRecord.examinee_answers);
if (!Array.isArray(relatedRecord.examinee_answers)) {
relatedRecord.examinee_answers = [relatedRecord.examinee_answers];
}
} catch (e) {
console.error('解析考生答案失败:', e);
relatedRecord.examinee_answers = []; // 解析失败时设置为空数组
}
} else {
relatedRecord.examinee_answers = [];
}
}
/// 如果是fill_blank把relatedRecord的correct_answers、examinee_answers解析成数组
if (question.question_type === 'fill_blank') {
if (relatedRecord.correct_answers) {
try {
relatedRecord.correct_answers = JSON.parse(relatedRecord.correct_answers);
if (!Array.isArray(relatedRecord.correct_answers)) {
relatedRecord.correct_answers = [relatedRecord.correct_answers];
}
} catch (e) {
console.error('解析正确答案失败:', e);
relatedRecord.correct_answers = []; // 解析失败时设置为空数组
}
} else {
relatedRecord.correct_answers = [];
}
}
/// 解析考生答案
if (question.question_type === 'fill_blank') {
if (relatedRecord.examinee_answers) {
try {
relatedRecord.examinee_answers = JSON.parse(relatedRecord.examinee_answers);
if (!Array.isArray(relatedRecord.examinee_answers)) {
relatedRecord.examinee_answers = [relatedRecord.examinee_answers];
}
} catch (e) {
console.error('解析考生答案失败:', e);
relatedRecord.examinee_answers = []; // 解析失败时设置为空数组
}
} else {
relatedRecord.examinee_answers = [];
}
}
const result = {
question_detail: relatedRecord,
question: question
};
console.log('成功获取完整试题数据');
return result;
} catch (error) {
console.error('获取试题数据失败:', error);
throw error;
}
}
/**
* 更新考生答案
* @param {string} tableName - 表名 (question_choices 或 question_fill_blanks)
* @param {number} id - 记录ID
* @param {Array|string} answers - 考生答案
* @returns {Promise<boolean>} - 是否更新成功
*/
export async function updateExamineeAnswer(tableName, id, answers) {
try {
// 验证表名
if (!['question_choices', 'question_fill_blanks'].includes(tableName)) {
throw new Error('无效的表名,只能是 question_choices 或 question_fill_blanks');
}
// 获取数据库连接
const userDb = await getDbConnection(getUserDbPath());
// 确保答案是JSON字符串
const answersJson = Array.isArray(answers) ? JSON.stringify(answers) : answers;
// 更新考生答案
const result = await userDb.runAsync(
`UPDATE ${tableName} SET examinee_answers = ?, updated_at = ? WHERE id = ?`,
[answersJson, new Date().toISOString(), id] // 修改为toISOString格式
);
return result.changes > 0;
} catch (error) {
console.error('更新考生答案失败:', error);
throw error;
}
}
// 替换现有的startPaper方法
/**
* 开始考试
* @param {number} paperId - 试卷ID
* @returns {Promise<Object>} - 包含操作结果和试卷数据的对象
*/
export async function startPaper(paperId) {
try {
const userDb = await getDbConnection(getUserDbPath());
const currentTime = formatDateTime(new Date()); // 修改为格式化日期
await userDb.runAsync(
`UPDATE examinee_papers
SET paper_status = 1,
paper_start_time = ?
WHERE id = ?`,
[currentTime, paperId]
);
// 查询更新后的试卷数据
const paper = await userDb.getAsync(
`SELECT * FROM examinee_papers WHERE id = ?`,
[paperId]
);
return {
success: true,
message: '考试已成功开始',
data: paper
};
} catch (error) {
console.error('开始考试失败:', error);
return {
success: false,
message: `开始考试失败: ${error.message}`,
data: null
};
}
}
// 替换现有的submitPaper方法
/**
* 提交考试
* @param {number} paperId - 试卷ID
* @returns {Promise<Object>} - 包含操作结果和试卷数据的对象
*/
export async function submitPaper(paperId) {
try {
const userDb = await getDbConnection(getUserDbPath());
const currentTime = formatDateTime(new Date()); // 修改为格式化日期
await userDb.runAsync(
`UPDATE examinee_papers
SET paper_status = 2,
paper_submit_time = ?,
paper_end_time = ?
WHERE id = ?`,
[currentTime, currentTime, paperId]
);
// 查询更新后的试卷数据
const paper = await userDb.getAsync(
`SELECT * FROM examinee_papers WHERE id = ?`,
[paperId]
);
return {
success: true,
message: '考试已成功提交',
data: paper
};
} catch (error) {
console.error('提交考试失败:', error);
return {
success: false,
message: `提交考试失败: ${error.message}`,
data: null
};
}
}
// 替换现有的endPaper方法
/**
* 结束考试
* @param {number} paperId - 试卷ID
* @returns {Promise<Object>} - 包含操作结果和试卷数据的对象
*/
export async function endPaper(paperId) {
try {
const userDb = await getDbConnection(getUserDbPath());
const currentTime = formatDateTime(new Date()); // 修改为格式化日期
await userDb.runAsync(
`UPDATE examinee_papers
SET paper_status = 2,
paper_end_time = ?
WHERE id = ?`,
[currentTime, paperId]
);
// 查询更新后的试卷数据
const paper = await userDb.getAsync(
`SELECT * FROM examinee_papers WHERE id = ?`,
[paperId]
);
return {
success: true,
message: '考试已成功结束',
data: paper
};
} catch (error) {
console.error('结束考试失败:', error);
return {
success: false,
message: `结束考试失败: ${error.message}`,
data: null
};
}
}
// 替换现有的processPaper方法
/**
* 更新试卷最后操作时间
* @param {number} paperId - 试卷ID
* @returns {Promise<Object>} - 包含操作结果和试卷数据的对象
*/
export async function processPaper(paperId) {
try {
const userDb = await getDbConnection(getUserDbPath());
const currentTime = formatDateTime(new Date()); // 统一使用格式化日期
await userDb.runAsync(
`UPDATE examinee_papers
SET paper_last_time = ?
WHERE id = ?`,
[currentTime, paperId]
);
// 查询更新后的试卷数据
const paper = await userDb.getAsync(
`SELECT * FROM examinee_papers WHERE id = ?`,
[paperId]
);
console.log('更新试卷最后操作时间成功:', paper); // 修复拼写错误并添加日志
return {
success: true,
message: '试卷处理时间已更新',
data: paper
};
} catch (error) {
console.error('处理试卷失败:', error);
return {
success: false,
message: `处理试卷失败: ${error.message}`,
data: null
};
}
}
/**
* 检查试卷答案并计算得分
* @param {number} paperId - 试卷ID
* @returns {Promise<Object>} - 包含操作结果和带关联的试卷数据的对象
*/
export async function checkPaperAnswers(paperId) {
try {
// 获取用户数据库路径
const userDbPath = getUserDbPath();
// 连接用户数据库
const userDb = await getDbConnection(userDbPath);
// 1. 查询试卷基本信息
const paper = await userDb.getAsync(
`SELECT * FROM examinee_papers WHERE id = ?`,
[paperId]
);
if (!paper) {
await closeAllConnections();
return {
success: false,
message: `未找到ID为${paperId}的试卷`,
data: null
};
}
// 2. 查询试卷关联的所有试题
const paperQuestions = await userDb.allAsync(
`SELECT * FROM paper_questions WHERE paper_id = ?`,
[paperId]
);
let totalScore = 0;
// 3. 遍历所有试题,查询并比对答案
for (const question of paperQuestions) {
const questionId = question.id;
const questionType = question.question_type;
// 根据题型查询对应的答案表
if (questionType === 'choice') {
// 选择题
const choices = await userDb.allAsync(
`SELECT * FROM question_choices WHERE question_id = ?`,
[questionId]
);
for (const choice of choices) {
// 解析正确答案和考生答案
const correctAnswers = JSON.parse(choice.correct_answers || '[]');
const examineeAnswers = JSON.parse(choice.examinee_answers || '[]');
// 打印题目信息
console.log(`\n选择题ID: ${choice.id}`);
console.log(`正确答案:`, correctAnswers);
console.log(`考生答案:`, examineeAnswers);
// 比对答案 - 不考虑顺序
let isCorrect = true;
if (correctAnswers.length !== examineeAnswers.length) {
isCorrect = false;
} else {
// 创建正确答案的副本用于比对
const correctAnswersCopy = [...correctAnswers];
// 检查考生答案中的每个元素是否在正确答案中存在
for (const answer of examineeAnswers) {
const index = correctAnswersCopy.indexOf(answer);
if (index === -1) {
isCorrect = false;
break;
}
// 移除已匹配的答案,避免重复匹配
correctAnswersCopy.splice(index, 1);
}
}
// 计算得分
const scoreReal = isCorrect ? (choice.score || 0) : 0;
totalScore += scoreReal;
// 打印判断结果和得分
console.log(`判断结果: ${isCorrect ? '正确' : '错误'}`);
console.log(`本题得分: ${scoreReal}`);
// 更新本题得分
await userDb.runAsync(
`UPDATE question_choices SET score_real = ? WHERE id = ?`,
[scoreReal, choice.id]
);
}
} else if (questionType === 'fill_blank') {
// 填空题
const blanks = await userDb.allAsync(
`SELECT * FROM question_fill_blanks WHERE question_id = ?`,
[questionId]
);
for (const blank of blanks) {
// 解析正确答案和考生答案
const correctAnswers = JSON.parse(blank.correct_answers || '[]');
const examineeAnswers = JSON.parse(blank.examinee_answers || '[]');
// 打印题目信息
console.log(`\n填空题ID: ${blank.id}`);
console.log(`正确答案:`, correctAnswers);
console.log(`考生答案:`, examineeAnswers);
// 比对答案 - 不考虑顺序
let isCorrect = true;
if (correctAnswers.length !== examineeAnswers.length) {
isCorrect = false;
} else {
// 创建正确答案的副本用于比对
const correctAnswersCopy = [...correctAnswers];
// 检查考生答案中的每个元素是否在正确答案中存在
for (const answer of examineeAnswers) {
const index = correctAnswersCopy.indexOf(answer);
if (index === -1) {
isCorrect = false;
break;
}
// 移除已匹配的答案,避免重复匹配
correctAnswersCopy.splice(index, 1);
}
}
// 计算得分
const scoreReal = isCorrect ? (blank.score || 0) : 0;
totalScore += scoreReal;
// 打印判断结果和得分
console.log(`判断结果: ${isCorrect ? '正确' : '错误'}`);
console.log(`本题得分: ${scoreReal}`);
// 更新本题得分
await userDb.runAsync(
`UPDATE question_fill_blanks SET score_real = ? WHERE id = ?`,
[scoreReal, blank.id]
);
}
}
// 可以根据需要添加其他题型的处理
}
// 4. 更新试卷总分
await userDb.runAsync(
`UPDATE examinee_papers SET paper_score_real = ? WHERE id = ?`,
[totalScore, paperId]
);
// 5. 查询更新后的试卷信息(包含关联数据)
// const updatedPaper = await userDb.getAsync(
// `SELECT * FROM examinee_papers WHERE id = ?`,
// [paperId]
// );
const updatedPaper = await getPaper(paperId);
console.log(updatedPaper);
// 关闭数据库连接
await closeAllConnections();
return {
success: true,
message: '试卷判卷成功',
data: updatedPaper.data
};
} catch (error) {
console.error('判卷过程中发生错误:', error);
await closeAllConnections();
return {
success: false,
message: `判卷失败: ${error.message}`,
data: null
};
}
}
export async function getPaper(paperId) {
try {
// 获取数据库路径
const systemDbPath = getSystemDbPath();
const userDbPath = getUserDbPath();
// 连接数据库
const systemDb = await getDbConnection(systemDbPath);
const userDb = await getDbConnection(userDbPath);
// 1. 查询试卷基本信息
const paper = await userDb.getAsync(
`SELECT * FROM examinee_papers WHERE id = ?`,
[paperId]
);
if (!paper) {
await closeAllConnections();
return {
success: false,
message: `未找到ID为${paperId}的试卷`,
data: null
};
}
// 补充: 查询关联的examinee
const examinee = await userDb.getAsync(
`SELECT * FROM examinee WHERE id = ?`,
[paper.examinee_id]
);
// 2. 查询试卷关联的题目
const paperQuestions = await userDb.allAsync(
`SELECT * FROM paper_questions WHERE paper_id = ?`,
[paperId]
);
// 3. 为每个题目获取详细信息
const questionsWithDetails = [];
for (const question of paperQuestions) {
const questionId = question.id;
const questionType = question.question_type;
// 3.1 查询题型名称
const dictItem = await systemDb.getAsync(
`SELECT item_name FROM dict_items WHERE type_code = 'question_type' AND item_code = ?`,
[questionType]
);
const questionWithDetails = {
...question,
question_type_name: dictItem?.item_name || '',
images: [],
datasets: [],
choices: [],
blanks: []
};
// 3.2 查询题目图片
const images = await userDb.allAsync(
`SELECT * FROM question_images WHERE question_id = ?`,
[questionId]
);
questionWithDetails.images = images;
// 3.3 查询题目数据集
const datasets = await userDb.allAsync(
`SELECT * FROM question_datasets WHERE question_id = ?`,
[questionId]
);
// 解析dataset_data为数组
questionWithDetails.datasets = datasets.map(dataset => ({
...dataset,
dataset_data: JSON.parse(dataset.dataset_data || '[]')
}));
// 3.4 根据题型查询对应的答案表
if (questionType === 'choice') {
// 查询选择题
const choices = await userDb.allAsync(
`SELECT * FROM question_choices WHERE question_id = ?`,
[questionId]
);
// 解析数组列
questionWithDetails.choices = choices.map(choice => ({
...choice,
choice_options: JSON.parse(choice.choice_options || '[]'),
correct_answers: JSON.parse(choice.correct_answers || '[]'),
examinee_answers: JSON.parse(choice.examinee_answers || '[]')
}));
} else if (questionType === 'fill_blank') {
// 查询填空题
const blanks = await userDb.allAsync(
`SELECT * FROM question_fill_blanks WHERE question_id = ?`,
[questionId]
);
// 解析数组列
questionWithDetails.blanks = blanks.map(blank => ({
...blank,
correct_answers: JSON.parse(blank.correct_answers || '[]'),
examinee_answers: JSON.parse(blank.examinee_answers || '[]')
}));
}
questionsWithDetails.push(questionWithDetails);
}
// 4. 构建完整的试卷对象
const fullPaper = {
...paper,
examinee: examinee,
questions: questionsWithDetails
};
// 关闭数据库连接
await closeAllConnections();
return {
success: true,
message: '获取试卷成功',
data: JSON.stringify(fullPaper)
};
} catch (error) {
console.error('获取试卷过程中发生错误:', error);
await closeAllConnections();
return {
success: false,
message: `获取试卷失败: ${error.message}`,
data: null
};
}
}