import { getSystemDbPath } from './path.js'; import { executeWithRetry } from './utils.js'; import { getDbConnection } from './index.js'; /** * 添加新题干及相关数据 * @param {Object} questionData - 题干数据 * @param {string} questionData.question_type - 题型代码 * @param {string} questionData.question_description - 题干描述 * @param {Array} questionData.images - 图片数据数组 * @param {Array} questionData.datasets - 数据集数据数组 * @returns {Promise} 新创建的题干ID */ async function addQuestion(questionData) { const { question_type, question_description, images = [], datasets = [] } = questionData; const db = await getDbConnection(getSystemDbPath()); return executeWithRetry(db, async () => { // 开始事务 await db.runAsync('BEGIN TRANSACTION'); try { // 1. 插入题干基本信息 const questionResult = await db.runAsync( 'INSERT INTO questions (question_type, question_name, question_description, created_at, updated_at) VALUES (?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)', [question_type, '', question_description] ); const questionId = questionResult.lastID; // 2. 插入图片数据 if (images.length > 0) { for (const image of images) { await db.runAsync( 'INSERT INTO question_images (question_id, image_name, image_base64, created_at, updated_at) VALUES (?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)', [questionId, image.image || 'image', image.base64] ); } } // 3. 插入数据集数据 if (datasets.length > 0) { for (const dataset of datasets) { await db.runAsync( 'INSERT INTO question_datasets (question_id, dataset_name, dataset_data, created_at, updated_at) VALUES (?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)', [questionId, dataset.name || 'dataset',dataset.content] ); } } // 提交事务 await db.runAsync('COMMIT'); return questionId; } catch (error) { // 回滚事务 await db.runAsync('ROLLBACK'); throw error; } }); } /** * 获取所有题干 * @returns {Promise} 题干列表 */ async function getAllQuestions() { const db = await getDbConnection(getSystemDbPath()); return executeWithRetry(db, async () => { return await db.allAsync('SELECT * FROM questions ORDER BY id DESC'); }); } /** * 根据ID获取题干详情 * @param {number} id - 题干ID * @returns {Promise} 题干详情 */ async function getQuestionById(id) { const db = await getDbConnection(getSystemDbPath()); return executeWithRetry(db, async () => { return await db.getAsync('SELECT * FROM questions WHERE id = ?', [id]); }); } /** * 更新题干信息 * @param {number} id - 题干ID * @param {Object} questionData - 题干数据 * @returns {Promise} 是否更新成功 */ async function updateQuestion(id, questionData) { const { question_type, question_description } = questionData; const db = await getDbConnection(getSystemDbPath()); return executeWithRetry(db, async () => { const result = await db.runAsync( 'UPDATE questions SET question_type = ?, question_description = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?', [question_type, question_description, id] ); return result.changes > 0; }); } /** * 删除题干 * @param {number} id - 题干ID * @returns {Promise} 是否删除成功 */ async function deleteQuestion(id) { const db = await getDbConnection(getSystemDbPath()); return executeWithRetry(db, async () => { // 开始事务 await db.runAsync('BEGIN TRANSACTION'); try { // 先删除关联数据 await db.runAsync('DELETE FROM question_images WHERE question_id = ?', [id]); await db.runAsync('DELETE FROM question_datasets WHERE question_id = ?', [id]); // 删除关联的试题数据 await db.runAsync('DELETE FROM question_choices WHERE question_id = ?', [id]); await db.runAsync('DELETE FROM question_fill_blanks WHERE question_id = ?', [id]); await db.runAsync('DELETE FROM question_fill_table WHERE question_id = ?', [id]); await db.runAsync('DELETE FROM question_fill_table_blanks WHERE question_id = ?', [id]); await db.runAsync('DELETE FROM question_judge WHERE question_id = ?', [id]); await db.runAsync('DELETE FROM question_short WHERE question_id = ?', [id]); // 再删除题干 const result = await db.runAsync('DELETE FROM questions WHERE id = ?', [id]); // 提交事务 await db.runAsync('COMMIT'); return result.changes > 0; } catch (error) { // 回滚事务 await db.runAsync('ROLLBACK'); throw error; } }); } /** * 获取所有题干及其关联信息 * @returns {Promise} 包含关联信息的题干列表 */ async function getAllQuestionsWithRelations() { const db = await getDbConnection(getSystemDbPath()); return executeWithRetry(db, async () => { // 1. 查询所有题干基本信息及关联的题型名称 const questions = await db.allAsync(` SELECT q.*, di.item_name as question_type_name FROM questions q LEFT JOIN dict_items di ON q.question_type = di.item_code AND di.type_code = 'question_type' ORDER BY q.id DESC `); // 2. 为每个题干查询关联的图片、数据集和特定类型的问题数据 for (const question of questions) { // 查询关联的图片 const images = await db.allAsync( 'SELECT * FROM question_images WHERE question_id = ?', [question.id] ); question.images = images; // 查询关联的数据集 const datasets = await db.allAsync( 'SELECT * FROM question_datasets WHERE question_id = ?', [question.id] ); datasets.forEach(dataset => { try { dataset.dataset_data = JSON.parse(dataset.dataset_data); } catch (e) { console.error('解析数据集失败:', e); dataset.dataset_data = null; } }); question.datasets = datasets; // 根据question_type关联不同的问题表 switch (question.question_type) { case 'choice': // 关联选择题表 question.choices = await db.allAsync( 'SELECT * FROM question_choices WHERE question_id = ?', [question.id] ); break; case 'fill_blank': // 关联填空题表 question.fillBlanks = await db.allAsync( 'SELECT * FROM question_fill_blanks WHERE question_id = ?', [question.id] ); break; case 'fill_table': // 关联表格填空题表和表格填空项表 question.fillTables = await db.allAsync( 'SELECT * FROM question_fill_table WHERE question_id = ?', [question.id] ); // 对每个表格查询其填空项 for (let table of question.fillTables) { table.blanks = await db.allAsync( 'SELECT * FROM question_fill_table_blanks WHERE table_id = ?', [table.id] ); } break; case 'true_false': // 关联判断题表 question.judges = await db.allAsync( 'SELECT * FROM question_judge WHERE question_id = ?', [question.id] ); break; case 'short_answer': case 'analysis': case 'essay': // 关联简答题表 question.shorts = await db.allAsync( 'SELECT * FROM question_short WHERE question_id = ?', [question.id] ); break; default: // 未知题型,不关联任何表 break; } } return questions; }); } /** * 更新题干描述 * @param {number} id - 题干ID * @param {string} questionDescription - 新的题干描述 * @returns {Promise} 是否更新成功 */ async function updateQuestionDescription(id, questionDescription) { const db = await getDbConnection(getSystemDbPath()); return executeWithRetry(db, async () => { const result = await db.runAsync( 'UPDATE questions SET question_description = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?', [questionDescription, id] ); return result.changes > 0; }); } /** * 添加选择题问题 * @param {Object} choiceData - 选择题数据 * @param {number} choiceData.question_id - 题干ID * @param {string} choiceData.choice_description - 问题描述 * @param {string} choiceData.choice_type - 题型(single/multiple) * @param {Array} choiceData.choice_options - 候选项数组 * @param {Array} choiceData.correct_answers - 正确答案序号数组 * @returns {Promise} 新创建的选择题ID */ async function addChoiceQuestion(choiceData) { const { question_id, choice_description, choice_type, score, choice_options, correct_answers } = choiceData; const db = await getDbConnection(getSystemDbPath()); return executeWithRetry(db, async () => { const result = await db.runAsync( 'INSERT INTO question_choices (question_id, choice_description, choice_type, score, choice_options, correct_answers, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)', [question_id, choice_description, choice_type, score, JSON.stringify(choice_options), JSON.stringify(correct_answers)] ); return result.lastID; }); } /** * 添加选择题问题 * @param {number} id - 选择题ID * @param {Object} choiceData - 选择题数据 * @returns {Promise} 是否更新成功 */ async function updateChoiceQuestion(id, choiceData) { const { choice_description, choice_type, score, choice_options, correct_answers } = choiceData; const db = await getDbConnection(getSystemDbPath()); return executeWithRetry(db, async () => { const result = await db.runAsync( 'UPDATE question_choices SET choice_description = ?, choice_type = ?, score = ?, choice_options = ?, correct_answers = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?', [choice_description, choice_type, score, JSON.stringify(choice_options), JSON.stringify(correct_answers), id] ); return result.changes > 0; }); } /** * 添加填空题问题 * @param {Object} fillBlankData - 填空题数据 * @param {number} fillBlankData.question_id - 题干ID * @param {string} fillBlankData.blank_description - 问题描述 * @param {number} fillBlankData.blank_count - 空白数量 * @param {Array} fillBlankData.correct_answers - 正确答案数组 * @param {number} fillBlankData.score - 分值 * @returns {Promise} 新创建的填空题ID */ async function addFillBlankQuestion(fillBlankData) { const { question_id, blank_description, blank_count, correct_answers, score } = fillBlankData; const db = await getDbConnection(getSystemDbPath()); return executeWithRetry(db, async () => { const result = await db.runAsync( 'INSERT INTO question_fill_blanks (question_id, blank_description, blank_count, correct_answers, score, created_at, updated_at) VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)', [question_id, blank_description, blank_count, JSON.stringify(correct_answers), score] ); return result.lastID; }); } /** * 更新填空题问题 * @param {number} id - 填空题ID * @param {Object} fillBlankData - 填空题数据 * @returns {Promise} 是否更新成功 */ async function updateFillBlankQuestion(id, fillBlankData) { const { blank_description, blank_count, correct_answers, score } = fillBlankData; const db = await getDbConnection(getSystemDbPath()); return executeWithRetry(db, async () => { const result = await db.runAsync( 'UPDATE question_fill_blanks SET blank_description = ?, blank_count = ?, correct_answers = ?, score = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?', [blank_description, blank_count, JSON.stringify(correct_answers), score, id] ); return result.changes > 0; }); } /** * 删除填空题问题 * @param {number} id - 填空题ID * @returns {Promise} 是否删除成功 */ async function deleteFillBlankQuestion(id) { const db = await getDbConnection(getSystemDbPath()); return executeWithRetry(db, async () => { const result = await db.runAsync('DELETE FROM question_fill_blanks WHERE id = ?', [id]); return result.changes > 0; }); } /** * 根据题干ID查询填空题问题 * @param {number} questionId - 题干ID * @returns {Promise} 填空题列表 */ async function getFillBlankQuestionsByQuestionId(questionId) { const db = await getDbConnection(getSystemDbPath()); return executeWithRetry(db, async () => { const questions = await db.allAsync('SELECT * FROM question_fill_blanks WHERE question_id = ?', [questionId]); // 解析correct_answers为数组 questions.forEach(question => { try { question.correct_answers = JSON.parse(question.correct_answers); } catch (e) { console.error('解析填空题答案失败:', e); question.correct_answers = []; } }); return questions; }); } /** * 查询试题总数和总分 * @returns {Promise<{totalQuestions: number, totalScore: number}>} 包含试题总数和总分的对象 */ async function getQuestionsCountAndScore() { const db = await getDbConnection(getSystemDbPath()); return executeWithRetry(db, async () => { // 查询选择题总数和总分 const choiceResult = await db.getAsync(` SELECT COUNT(*) as count, SUM(qc.score) as score FROM questions q LEFT JOIN question_choices qc ON q.id = qc.question_id WHERE q.question_type = 'choice' `); // 查询填空题总数和总分 const fillBlankResult = await db.getAsync(` SELECT COUNT(*) as count, SUM(qfb.score) as score FROM questions q LEFT JOIN question_fill_blanks qfb ON q.id = qfb.question_id WHERE q.question_type = 'fill_blank' `); // 计算总题数和总分 const totalQuestions = (choiceResult.count || 0) + (fillBlankResult.count || 0); const totalScore = (choiceResult.score || 0) + (fillBlankResult.score || 0); return { totalQuestions, totalScore }; }); } export { addQuestion, getAllQuestions, getQuestionById, updateQuestion, deleteQuestion, getAllQuestionsWithRelations, updateQuestionDescription, addChoiceQuestion, updateChoiceQuestion, addFillBlankQuestion, updateFillBlankQuestion, deleteFillBlankQuestion, getFillBlankQuestionsByQuestionId, getQuestionsCountAndScore };