重新实现数据库初始化,改变user.db库中的表结构
This commit is contained in:
parent
0e1b9a496b
commit
fc110beee0
@ -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;
|
||||
}
|
||||
|
||||
// 初始化数据库
|
||||
|
@ -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
|
||||
getFillBlankQuestionsByQuestionId,
|
||||
getQuestionsCountAndScore
|
||||
};
|
@ -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 };
|
||||
|
@ -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'),
|
||||
|
@ -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;
|
||||
}
|
||||
});
|
||||
|
||||
// 注册查询试题总数和总分的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;
|
||||
}
|
||||
});
|
||||
}
|
@ -85,7 +85,7 @@
|
||||
考题数量
|
||||
</div>
|
||||
</template>
|
||||
<span class="text-gray-500">待设置</span>
|
||||
<span class="text-gray-500">{{ totalQuestions }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
@ -96,7 +96,7 @@
|
||||
考试总分
|
||||
</div>
|
||||
</template>
|
||||
<span class="text-gray-500">待设置</span>
|
||||
<span class="text-gray-500">{{ totalScore }}</span>
|
||||
</el-descriptions-item>
|
||||
|
||||
</el-descriptions>
|
||||
@ -120,6 +120,10 @@
|
||||
暂无考试须知
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<el-button type="info" @click="exitExam">返回</el-button>
|
||||
<el-button type="primary" @click="startExam">开始考试</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -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()
|
||||
})
|
||||
</script>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user