diff --git a/electron/db/index.js b/electron/db/index.js index 01ad571..c1d5713 100644 --- a/electron/db/index.js +++ b/electron/db/index.js @@ -20,7 +20,7 @@ export async function getDbConnection(dbPath) { } // 关闭所有数据库连接 -function closeAllConnections() { +export function closeAllConnections() { dbConnections.forEach((db, path) => { try { db.close(); @@ -57,57 +57,157 @@ async function initializeSystemDatabase() { const systemDbPath = getSystemDbPath(); const systemDb = await getDbConnection(systemDbPath); - try { - // 开始事务 - await systemDb.runAsync('BEGIN TRANSACTION'); - console.log('开始事务'); + // 记录成功和失败的操作 + const results = { success: [], failed: [] }; - // 创建表结构 - console.log('开始创建系统数据库表结构...'); + // 创建表结构 + console.log('开始创建系统数据库表结构...'); + + // 创建config表 + try { await systemDb.execAsync(systemSchema.config.trim()); console.log('创建 config 表成功'); + results.success.push('创建 config 表'); + } catch (error) { + console.error('创建 config 表失败:', error); + results.failed.push({ operation: '创建 config 表', error: error.message }); + } + // 创建dict_types表 + try { await systemDb.execAsync(systemSchema.dictTypes.trim()); console.log('创建 dict_types 表成功'); + results.success.push('创建 dict_types 表'); + } catch (error) { + console.error('创建 dict_types 表失败:', error); + results.failed.push({ operation: '创建 dict_types 表', error: error.message }); + } + // 创建dict_items表 + try { await systemDb.execAsync(systemSchema.dictItems.trim()); console.log('创建 dict_items 表成功'); + results.success.push('创建 dict_items 表'); + } catch (error) { + console.error('创建 dict_items 表失败:', error); + results.failed.push({ operation: '创建 dict_items 表', error: error.message }); + } + // 创建questions表 + try { await systemDb.execAsync(systemSchema.questions.trim()); console.log('创建 questions 表成功'); + results.success.push('创建 questions 表'); + } catch (error) { + console.error('创建 questions 表失败:', error); + results.failed.push({ operation: '创建 questions 表', error: error.message }); + } + // 创建question_datasets表 + try { await systemDb.execAsync(systemSchema.questionDatasets.trim()); console.log('创建 question_datasets 表成功'); + results.success.push('创建 question_datasets 表'); + } catch (error) { + console.error('创建 question_datasets 表失败:', error); + results.failed.push({ operation: '创建 question_datasets 表', error: error.message }); + } + // 创建question_images表 + try { await systemDb.execAsync(systemSchema.questionImages.trim()); console.log('创建 question_images 表成功'); + results.success.push('创建 question_images 表'); + } catch (error) { + console.error('创建 question_images 表失败:', error); + results.failed.push({ operation: '创建 question_images 表', error: error.message }); + } + // 创建question_fill_table表 + try { await systemDb.execAsync(systemSchema.questionFillTable.trim()); console.log('创建 question_fill_table 表成功'); + results.success.push('创建 question_fill_table 表'); + } catch (error) { + console.error('创建 question_fill_table 表失败:', error); + results.failed.push({ operation: '创建 question_fill_table 表', error: error.message }); + } + // 创建question_fill_table_blanks表 + try { await systemDb.execAsync(systemSchema.questionFillTableBlanks.trim()); console.log('创建 question_fill_table_blanks 表成功'); + results.success.push('创建 question_fill_table_blanks 表'); + } catch (error) { + console.error('创建 question_fill_table_blanks 表失败:', error); + results.failed.push({ operation: '创建 question_fill_table_blanks 表', error: error.message }); + } + // 创建question_choices表 + try { await systemDb.execAsync(systemSchema.questionChoices.trim()); console.log('创建 question_choices 表成功'); + results.success.push('创建 question_choices 表'); + } catch (error) { + console.error('创建 question_choices 表失败:', error); + results.failed.push({ operation: '创建 question_choices 表', error: error.message }); + } + // 创建question_fill_blanks表 + try { await systemDb.execAsync(systemSchema.questionFillBlanks.trim()); console.log('创建 question_fill_blanks 表成功'); + results.success.push('创建 question_fill_blanks 表'); + } catch (error) { + console.error('创建 question_fill_blanks 表失败:', error); + results.failed.push({ operation: '创建 question_fill_blanks 表', error: error.message }); + } + // 创建question_judge表 + try { await systemDb.execAsync(systemSchema.questionJudge.trim()); console.log('创建 question_judge 表成功'); + results.success.push('创建 question_judge 表'); + } catch (error) { + console.error('创建 question_judge 表失败:', error); + results.failed.push({ operation: '创建 question_judge 表', error: error.message }); + } + // 创建question_short表 + try { await systemDb.execAsync(systemSchema.questionShort.trim()); console.log('创建 question_short 表成功'); + results.success.push('创建 question_short 表'); + } catch (error) { + console.error('创建 question_short 表失败:', error); + results.failed.push({ operation: '创建 question_short 表', error: error.message }); + } + // 创建exam表 + try { await systemDb.execAsync(systemSchema.exam.trim()); console.log('创建 exam 表成功'); + results.success.push('创建 exam 表'); + } catch (error) { + console.error('创建 exam 表失败:', error); + results.failed.push({ operation: '创建 exam 表', error: error.message }); + } + // 创建examinee表 + try { await systemDb.execAsync(systemSchema.examinee.trim()); console.log('创建 examinee 表成功'); + results.success.push('创建 examinee 表'); + } catch (error) { + console.error('创建 examinee 表失败:', error); + results.failed.push({ operation: '创建 examinee 表', error: error.message }); + } - // 插入默认数据 - console.log('开始插入默认数据...'); + // 插入默认数据 + console.log('开始插入默认数据...'); + + // 处理密码哈希 + try { const plainPassword = defaultData.config.find(item => item.key === 'admin_password').value; const hashedPassword = await argon2.hash(plainPassword); @@ -119,26 +219,54 @@ async function initializeSystemDatabase() { return item; }); - await batchInsert(systemDb, 'config', configData); - console.log('插入 config 表数据成功'); + // 插入config表数据 + try { + await batchInsert(systemDb, 'config', configData); + console.log('插入 config 表数据成功'); + results.success.push('插入 config 表数据'); + } catch (error) { + console.error('插入 config 表数据失败:', error); + results.failed.push({ operation: '插入 config 表数据', error: error.message }); + } + } catch (error) { + console.error('处理密码哈希失败:', error); + results.failed.push({ operation: '处理密码哈希', error: error.message }); + } + // 插入dict_types表数据 + try { await batchInsert(systemDb, 'dict_types', defaultData.dictTypes); console.log('插入 dict_types 表数据成功'); + results.success.push('插入 dict_types 表数据'); + } catch (error) { + console.error('插入 dict_types 表数据失败:', error); + results.failed.push({ operation: '插入 dict_types 表数据', error: error.message }); + } + // 插入dict_items表数据 + try { await batchInsert(systemDb, 'dict_items', defaultData.dictItems); console.log('插入 dict_items 表数据成功'); - - // 提交事务 - await systemDb.runAsync('COMMIT'); - console.log('提交事务成功'); - - return true; + results.success.push('插入 dict_items 表数据'); } catch (error) { - // 处理错误 - await systemDb.runAsync('ROLLBACK'); - console.error('回滚事务:', error); - throw error; + console.error('插入 dict_items 表数据失败:', error); + results.failed.push({ operation: '插入 dict_items 表数据', error: error.message }); } + + console.log('系统数据库初始化结果:'); + console.log('成功操作:', results.success); + console.log('失败操作:', results.failed); + + // 如果有失败操作,抛出错误 + if (results.failed.length > 0) { + console.log(`系统数据库初始化有 ${results.failed.length} 个操作失败,请查看日志`); + // 输出详细的失败信息 + results.failed.forEach((item, index) => { + console.log(`${index + 1}. ${item.operation} 失败: ${item.error}`); + }); + } + + return true; } // 初始化用户数据库 @@ -147,54 +275,96 @@ async function initializeUserDatabase() { const userDbPath = getUserDbPath(); const userDb = await getDbConnection(userDbPath); + // 记录成功和失败的操作 + const results = { success: [], failed: [] }; + + // 创建表结构 + console.log('开始创建用户数据库表结构...'); + + // 创建examinee表 try { - // 开始事务 - await userDb.runAsync('BEGIN TRANSACTION'); - console.log('开始事务'); - - // 创建表结构 - console.log('开始创建用户数据库表结构...'); - await userDb.execAsync(userSchema.examineeLog.trim()); - console.log('创建 examinee_log 表成功'); - - await userDb.execAsync(userSchema.examineeExam.trim()); - console.log('创建 examinee_exam 表成功'); - - await userDb.execAsync(userSchema.examineePapers.trim()); - console.log('创建 examinee_papers 表成功'); - - await userDb.execAsync(userSchema.paperQuestions.trim()); - console.log('创建 paper_questions 表成功'); - - await userDb.execAsync(userSchema.paperQuestionChoices.trim()); - console.log('创建 paper_question_choices 表成功'); - - await userDb.execAsync(userSchema.paperQuestionBlanks.trim()); - console.log('创建 paper_question_blanks 表成功'); - - await userDb.execAsync(userSchema.paperQuestionJudge.trim()); - console.log('创建 paper_question_judge 表成功'); - - await userDb.execAsync(userSchema.paperQuestionFillTable.trim()); - console.log('创建 paper_question_fill_table 表成功'); - - await userDb.execAsync(userSchema.paperQuestionFillTableBlanks.trim()); - console.log('创建 paper_question_fill_table_blanks 表成功'); - - await userDb.execAsync(userSchema.paperQuestionSubjective.trim()); - console.log('创建 paper_question_subjective 表成功'); - - // 提交事务 - await userDb.runAsync('COMMIT'); - console.log('提交事务成功'); - - return true; + await userDb.execAsync(userSchema.examinee.trim()); + console.log('创建 examinee 表成功'); + results.success.push('创建 examinee 表'); } catch (error) { - // 处理错误 - await userDb.runAsync('ROLLBACK'); - console.error('回滚事务:', error); - throw error; + console.error('创建 examinee 表失败:', error); + results.failed.push({ operation: '创建 examinee 表', error: error.message }); } + + // 创建examinee_papers表 + try { + await userDb.execAsync(userSchema.examinee_papers.trim()); + console.log('创建 examinee_papers 表成功'); + results.success.push('创建 examinee_papers 表'); + } catch (error) { + console.error('创建 examinee_papers 表失败:', error); + results.failed.push({ operation: '创建 examinee_papers 表', error: error.message }); + } + + // 创建paper_questions表 + try { + await userDb.execAsync(userSchema.paper_questions.trim()); + console.log('创建 paper_questions 表成功'); + results.success.push('创建 paper_questions 表'); + } catch (error) { + console.error('创建 paper_questions 表失败:', error); + results.failed.push({ operation: '创建 paper_questions 表', error: error.message }); + } + + // 创建question_datasets表 + try { + await userDb.execAsync(userSchema.question_datasets.trim()); + console.log('创建 question_datasets 表成功'); + results.success.push('创建 question_datasets 表'); + } catch (error) { + console.error('创建 question_datasets 表失败:', error); + results.failed.push({ operation: '创建 question_datasets 表', error: error.message }); + } + + // 创建question_images表 + try { + await userDb.execAsync(userSchema.question_images.trim()); + console.log('创建 question_images 表成功'); + results.success.push('创建 question_images 表'); + } catch (error) { + console.error('创建 question_images 表失败:', error); + results.failed.push({ operation: '创建 question_images 表', error: error.message }); + } + + // 创建question_choices表 + try { + await userDb.execAsync(userSchema.question_choices.trim()); + console.log('创建 question_choices 表成功'); + results.success.push('创建 question_choices 表'); + } catch (error) { + console.error('创建 question_choices 表失败:', error); + results.failed.push({ operation: '创建 question_choices 表', error: error.message }); + } + + // 创建question_fill_blanks表 + try { + await userDb.execAsync(userSchema.question_fill_blanks.trim()); + console.log('创建 question_fill_blanks 表成功'); + results.success.push('创建 question_fill_blanks 表'); + } catch (error) { + console.error('创建 question_fill_blanks 表失败:', error); + results.failed.push({ operation: '创建 question_fill_blanks 表', error: error.message }); + } + + console.log('用户数据库初始化结果:'); + console.log('成功操作:', results.success); + console.log('失败操作:', results.failed); + + // 如果有失败操作,仅打印错误信息,不抛出异常 + if (results.failed.length > 0) { + console.error(`用户数据库初始化有 ${results.failed.length} 个操作失败,请查看日志`); + // 输出详细的失败信息 + results.failed.forEach((item, index) => { + console.error(`${index + 1}. ${item.operation} 失败: ${item.error}`); + }); + } + + return true; } // 初始化数据库 diff --git a/electron/db/question.js b/electron/db/question.js index af8f9d7..0dc00cd 100644 --- a/electron/db/question.js +++ b/electron/db/question.js @@ -370,6 +370,40 @@ async function getFillBlankQuestionsByQuestionId(questionId) { }); } +/** + * 查询试题总数和总分 + * @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, @@ -383,5 +417,6 @@ export { addFillBlankQuestion, updateFillBlankQuestion, deleteFillBlankQuestion, - getFillBlankQuestionsByQuestionId -}; \ No newline at end of file + getFillBlankQuestionsByQuestionId, + getQuestionsCountAndScore +}; diff --git a/electron/db/schema.js b/electron/db/schema.js index d93d7fe..ee8e885 100644 --- a/electron/db/schema.js +++ b/electron/db/schema.js @@ -1,5 +1,5 @@ // 辅助函数:将db.run包装为Promise -const runAsync = (db, sql, params = []) => { +export const runAsync = (db, sql, params = []) => { return new Promise((resolve, reject) => { db.run(sql, params, function (err) { if (err) reject(err); @@ -8,10 +8,8 @@ const runAsync = (db, sql, params = []) => { }); }; -export { runAsync }; - // 系统数据库表结构 -const systemSchema = { +export const systemSchema = { config: ` CREATE TABLE IF NOT EXISTS config ( id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -184,124 +182,97 @@ const systemSchema = { }; // 用户数据库表结构 -const userSchema = { - examineeLog: ` - CREATE TABLE IF NOT EXISTS examinee_log ( +export const userSchema = { + examinee: ` + CREATE TABLE IF NOT EXISTS examinee ( id INTEGER PRIMARY KEY AUTOINCREMENT, - examinee_id INTEGER NOT NULL, - operation TEXT NOT NULL DEFAULT '', - operation_time TEXT NOT NULL, + examinee_name TEXT NOT NULL DEFAULT '', + examinee_gender TEXT NOT NULL DEFAULT '', + examinee_unit TEXT NOT NULL DEFAULT '', + written_exam_room TEXT NOT NULL DEFAULT '', + written_exam_seat TEXT NOT NULL DEFAULT '', + computer_exam_room TEXT NOT NULL DEFAULT '', + computer_exam_seat TEXT NOT NULL DEFAULT '', + examinee_id_card TEXT NOT NULL DEFAULT '', + examinee_admission_ticket TEXT NOT NULL DEFAULT '', created_at TEXT DEFAULT CURRENT_TIMESTAMP ); `, - examineeExam: ` - CREATE TABLE IF NOT EXISTS examinee_exam ( + examinee_papers: ` + CREATE TABLE IF NOT EXISTS examinee_papers ( id INTEGER PRIMARY KEY AUTOINCREMENT, examinee_id INTEGER NOT NULL, - exam_name TEXT NOT NULL DEFAULT '', - exam_description TEXT NOT NULL DEFAULT '', - exam_examinee_type TEXT NOT NULL DEFAULT '', - exam_notice TEXT NOT NULL DEFAULT '', - exam_minutes INTEGER NOT NULL DEFAULT 0, - start_time TEXT NOT NULL, - latest_end_time TEXT NOT NULL, - end_time TEXT NOT NULL, - exam_duration INTEGER NOT NULL DEFAULT 0, + paper_minutes INTEGER NOT NULL DEFAULT 0, + paper_minuts_min INTEGER NOT NULL DEFAULT 0, + paper_start_time TEXT, + paper_last_time TEXT, + paper_submit_time TEXT, + paper_end_time TEXT, + paper_status INTEGER NOT NULL DEFAULT 0, -- 试卷状态:0未开始,1进行中,2已交卷 + paper_score_real REAL DEFAULT 0, + paper_score REAL DEFAULT 0, + created_at TEXT DEFAULT CURRENT_TIMESTAMP + ); + `, + paper_questions: ` + CREATE TABLE IF NOT EXISTS paper_questions ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + examinee_id INTEGER NOT NULL, + paper_id INTEGER NOT NULL, + question_type TEXT NOT NULL, + question_name TEXT NOT NULL DEFAULT '', + question_description TEXT NOT NULL DEFAULT '', + created_at TEXT DEFAULT CURRENT_TIMESTAMP + ); + `, + question_datasets: ` + CREATE TABLE IF NOT EXISTS question_datasets ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + question_id INTEGER NOT NULL, + dataset_name TEXT NOT NULL DEFAULT '', + dataset_data TEXT NOT NULL, + created_at TEXT DEFAULT CURRENT_TIMESTAMP + ); + `, + question_images: ` + CREATE TABLE IF NOT EXISTS question_images ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + question_id INTEGER NOT NULL, + image_name TEXT NOT NULL DEFAULT '', + image_base64 TEXT NOT NULL, created_at TEXT DEFAULT CURRENT_TIMESTAMP, updated_at TEXT DEFAULT CURRENT_TIMESTAMP ); `, - examineePapers: ` - CREATE TABLE IF NOT EXISTS examinee_papers ( + question_choices: ` + CREATE TABLE IF NOT EXISTS question_choices ( id INTEGER PRIMARY KEY AUTOINCREMENT, - examinee_id INTEGER NOT NULL, - exam_id INTEGER NOT NULL, - paper_minutes INTEGER NOT NULL DEFAULT 0, - paper_total_score INTEGER NOT NULL DEFAULT 0, - created_at TEXT DEFAULT CURRENT_TIMESTAMP - ); - `, - paperQuestions: ` - CREATE TABLE IF NOT EXISTS paper_questions ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - examinee_paper_id INTEGER NOT NULL, - question_type TEXT NOT NULL, - question_name TEXT NOT NULL DEFAULT '', - question_description TEXT NOT NULL DEFAULT '', - question_score INTEGER NOT NULL DEFAULT 0, - created_at TEXT DEFAULT CURRENT_TIMESTAMP - ); - `, - paperQuestionChoices: ` - CREATE TABLE IF NOT EXISTS paper_question_choices ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - paper_question_id INTEGER NOT NULL, + question_id INTEGER NOT NULL, + choice_description TEXT NOT NULL DEFAULT '', + choice_type TEXT NOT NULL DEFAULT 'single', choice_options TEXT NOT NULL, - user_answers TEXT NOT NULL DEFAULT '', + correct_answers TEXT NOT NULL, + examinee_answers TEXT NOT NULL DEFAULT '', + score REAL, + score_real REAL DEFAULT 0, -- 本题得分 created_at TEXT DEFAULT CURRENT_TIMESTAMP, - updated_at TEXT DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (paper_question_id) REFERENCES paper_questions(id) + updated_at TEXT DEFAULT CURRENT_TIMESTAMP ); `, - paperQuestionBlanks: ` - CREATE TABLE IF NOT EXISTS paper_question_blanks ( + question_fill_blanks: ` + CREATE TABLE IF NOT EXISTS question_fill_blanks ( id INTEGER PRIMARY KEY AUTOINCREMENT, - paper_question_id INTEGER NOT NULL, + question_id INTEGER NOT NULL, + blank_description TEXT NOT NULL DEFAULT '', blank_count INTEGER NOT NULL DEFAULT 0, - user_answers TEXT NOT NULL DEFAULT '', + correct_answers TEXT NOT NULL DEFAULT '', + examinee_answers TEXT NOT NULL DEFAULT '', + score REAL, + score_real REAL DEFAULT 0, -- 本题得分 created_at TEXT DEFAULT CURRENT_TIMESTAMP, - updated_at TEXT DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (paper_question_id) REFERENCES paper_questions(id) + updated_at TEXT DEFAULT CURRENT_TIMESTAMP ); - `, - paperQuestionJudge: ` - CREATE TABLE IF NOT EXISTS paper_question_judge ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - paper_question_id INTEGER NOT NULL, - judge_ask TEXT NOT NULL DEFAULT '', - user_answer INTEGER NOT NULL DEFAULT 0, - created_at TEXT DEFAULT CURRENT_TIMESTAMP, - updated_at TEXT DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (paper_question_id) REFERENCES paper_questions(id) - ); - `, - paperQuestionFillTable: ` - CREATE TABLE IF NOT EXISTS paper_question_fill_table ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - paper_question_id INTEGER NOT NULL, - table_name TEXT NOT NULL DEFAULT '', - table_data TEXT NOT NULL, - created_at TEXT DEFAULT CURRENT_TIMESTAMP, - updated_at TEXT DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (paper_question_id) REFERENCES paper_questions(id) - ); - `, - paperQuestionFillTableBlanks: ` - CREATE TABLE IF NOT EXISTS paper_question_fill_table_blanks ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - paper_question_fill_table_id INTEGER NOT NULL, - cell_position TEXT NOT NULL, - cell_type TEXT NOT NULL DEFAULT 'number', - user_answer TEXT NOT NULL DEFAULT '', - created_at TEXT DEFAULT CURRENT_TIMESTAMP, - updated_at TEXT DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (paper_question_fill_table_id) REFERENCES paper_question_fill_table(id) - ); - `, - paperQuestionSubjective: ` - CREATE TABLE IF NOT EXISTS paper_question_subjective ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - paper_question_id INTEGER NOT NULL, - subjective_type TEXT NOT NULL, - user_answer TEXT NOT NULL DEFAULT '', - score INTEGER NOT NULL DEFAULT -1, - scored_by TEXT NOT NULL DEFAULT '', - scored_at TEXT DEFAULT CURRENT_TIMESTAMP, - created_at TEXT DEFAULT CURRENT_TIMESTAMP, - updated_at TEXT DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (paper_question_id) REFERENCES paper_questions(id) - ); - `, + ` }; // 初始化默认数据 @@ -310,7 +281,7 @@ const plainPassword = "t2t6a9"; // 明文密码变量定义 // 注意:在实际初始化数据库时,需要使用argon2对plainPassword进行哈希 // 这里只定义默认数据结构,哈希操作应在index.js中的初始化函数中完成 -const defaultData = { +export const defaultData = { config: [ { key: "admin_password", value: plainPassword, protected: 1 }, { key: "question_bank_version", value: "1", protected: 1 }, @@ -368,7 +339,7 @@ const defaultData = { item_code: "fill_blank", item_name: "填空题", item_description: "填写空白处的答案", - is_active: 0, + is_active: 1, parent_code: "objective", }, { @@ -431,5 +402,3 @@ const defaultData = { ], }; -// 导出对象 -export { systemSchema, userSchema, defaultData }; diff --git a/electron/preload.js b/electron/preload.js index dbfd2f0..881db27 100644 --- a/electron/preload.js +++ b/electron/preload.js @@ -49,6 +49,7 @@ contextBridge.exposeInMainWorld('electronAPI', { updateFillBlankQuestion: (id, fillBlankData) => ipcRenderer.invoke('question-update-fill-blank', id, fillBlankData), deleteFillBlankQuestion: (id) => ipcRenderer.invoke('question-delete-fill-blank', id), fetchFillBlankQuestionsByQuestionId: (questionId) => ipcRenderer.invoke('question-fetch-fill-blank-by-question-id', questionId), + getQuestionsCountAndScore: () => ipcRenderer.invoke('question-get-count-and-score'), // 考试管理相关API createExam: (examData) => ipcRenderer.invoke('exam-create', examData), fetchAllExams: () => ipcRenderer.invoke('exam-fetch-all'), diff --git a/electron/service/questionService.js b/electron/service/questionService.js index bcb22ad..b21d06b 100644 --- a/electron/service/questionService.js +++ b/electron/service/questionService.js @@ -11,7 +11,8 @@ import { addFillBlankQuestion, updateFillBlankQuestion, deleteFillBlankQuestion, - getFillBlankQuestionsByQuestionId + getFillBlankQuestionsByQuestionId, + getQuestionsCountAndScore } from '../db/question.js'; // 导入configService中的increaseQuestionBankVersion方法 @@ -231,8 +232,21 @@ export async function fetchFillBlankQuestionsByQuestionId(questionId) { } /** - * 初始化question相关IPC - * @param {*} ipcMain + * 服务层:查询试题总数和总分 + * @returns {Promise<{totalQuestions: number, totalScore: number}>} 包含试题总数和总分的对象 + */ +export async function fetchQuestionsCountAndScore() { + try { + return await getQuestionsCountAndScore(); + } catch (error) { + console.error('服务层: 查询试题总数和总分失败', error); + throw error; + } +} + +/** + * 初始化试题相关IPC通信 + * @param {Electron.IpcMain} ipcMain - IPC主进程实例 */ export async function initQuestionIpc(ipcMain) { // 题干管理相关IPC @@ -361,4 +375,14 @@ export async function initQuestionIpc(ipcMain) { throw error; } }); -} \ No newline at end of file + + // 注册查询试题总数和总分的IPC处理程序 + ipcMain.handle('question-get-count-and-score', async () => { + try { + return await fetchQuestionsCountAndScore(); + } catch (error) { + console.error('Failed to fetch questions count and score:', error); + throw error; + } + }); +} diff --git a/src/views/user/ExamineeHomeView.vue b/src/views/user/ExamineeHomeView.vue index 33aa0d2..847083d 100644 --- a/src/views/user/ExamineeHomeView.vue +++ b/src/views/user/ExamineeHomeView.vue @@ -85,7 +85,7 @@ 考题数量 - 待设置 + {{ totalQuestions }} - 待设置 + {{ totalScore }} @@ -120,6 +120,10 @@ 暂无考试须知 +
+ 返回 + 开始考试 +
@@ -135,7 +139,6 @@ import Header from '@/components/common/Header.vue' import Footer from '@/components/common/Footer.vue' import { useRouter } from 'vue-router' -import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import { ref, computed, onMounted, watch } from 'vue' // 添加watch导入 import { ElMessage, ElDescriptions, ElDescriptionsItem, ElIcon } from 'element-plus' import { User, Postcard, Ticket, Clock, ScaleToOriginal, Timer } from '@element-plus/icons-vue' @@ -161,6 +164,8 @@ const size = ref('default') const lastExam = ref(null) const examLoading = ref(true) const examNotices = ref([]) +const totalQuestions = ref(0) +const totalScore = ref(0) // 添加watch监听lastExam变化 watch(lastExam, (newValue) => { @@ -195,6 +200,18 @@ const formatExamDuration = (minutes) => { return `${hours}小时${mins}分钟` } +// 得到考题数量和总分 +const getQuestionsCountAndScore = async () => { + try { + const result = await window.electronAPI.getQuestionsCountAndScore() + totalQuestions.value = result.totalQuestions + totalScore.value = result.totalScore + } catch (error) { + console.error('获取考题数量和总分失败:', error) + ElMessage.error(`获取考题数量和总分失败: ${error.message || '未知错误'}`) + } +} + // 获取最新考试信息 const fetchLastExam = async () => { examLoading.value = true @@ -218,6 +235,19 @@ const fetchLastExam = async () => { } } +const exitExam = async () => { + try { + if (!confirm('确定要退出考试吗?')) { + return + } + userStore.state.isLoggedIn = false + router.push('/') + } catch (error) { + console.error('退出考试失败:', error) + ElMessage.error(`退出考试失败: ${error.message || '未知错误'}`) + } +} + // 开始考试方法 const startExam = async () => { if (!lastExam.value) { @@ -251,6 +281,7 @@ const startExam = async () => { // 组件挂载时获取最新考试信息 onMounted(() => { fetchLastExam() + getQuestionsCountAndScore() })