重新实现数据库初始化,改变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) => {
|
dbConnections.forEach((db, path) => {
|
||||||
try {
|
try {
|
||||||
db.close();
|
db.close();
|
||||||
@ -57,57 +57,157 @@ async function initializeSystemDatabase() {
|
|||||||
const systemDbPath = getSystemDbPath();
|
const systemDbPath = getSystemDbPath();
|
||||||
const systemDb = await getDbConnection(systemDbPath);
|
const systemDb = await getDbConnection(systemDbPath);
|
||||||
|
|
||||||
try {
|
// 记录成功和失败的操作
|
||||||
// 开始事务
|
const results = { success: [], failed: [] };
|
||||||
await systemDb.runAsync('BEGIN TRANSACTION');
|
|
||||||
console.log('开始事务');
|
|
||||||
|
|
||||||
// 创建表结构
|
// 创建表结构
|
||||||
console.log('开始创建系统数据库表结构...');
|
console.log('开始创建系统数据库表结构...');
|
||||||
|
|
||||||
|
// 创建config表
|
||||||
|
try {
|
||||||
await systemDb.execAsync(systemSchema.config.trim());
|
await systemDb.execAsync(systemSchema.config.trim());
|
||||||
console.log('创建 config 表成功');
|
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());
|
await systemDb.execAsync(systemSchema.dictTypes.trim());
|
||||||
console.log('创建 dict_types 表成功');
|
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());
|
await systemDb.execAsync(systemSchema.dictItems.trim());
|
||||||
console.log('创建 dict_items 表成功');
|
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());
|
await systemDb.execAsync(systemSchema.questions.trim());
|
||||||
console.log('创建 questions 表成功');
|
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());
|
await systemDb.execAsync(systemSchema.questionDatasets.trim());
|
||||||
console.log('创建 question_datasets 表成功');
|
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());
|
await systemDb.execAsync(systemSchema.questionImages.trim());
|
||||||
console.log('创建 question_images 表成功');
|
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());
|
await systemDb.execAsync(systemSchema.questionFillTable.trim());
|
||||||
console.log('创建 question_fill_table 表成功');
|
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());
|
await systemDb.execAsync(systemSchema.questionFillTableBlanks.trim());
|
||||||
console.log('创建 question_fill_table_blanks 表成功');
|
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());
|
await systemDb.execAsync(systemSchema.questionChoices.trim());
|
||||||
console.log('创建 question_choices 表成功');
|
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());
|
await systemDb.execAsync(systemSchema.questionFillBlanks.trim());
|
||||||
console.log('创建 question_fill_blanks 表成功');
|
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());
|
await systemDb.execAsync(systemSchema.questionJudge.trim());
|
||||||
console.log('创建 question_judge 表成功');
|
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());
|
await systemDb.execAsync(systemSchema.questionShort.trim());
|
||||||
console.log('创建 question_short 表成功');
|
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());
|
await systemDb.execAsync(systemSchema.exam.trim());
|
||||||
console.log('创建 exam 表成功');
|
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());
|
await systemDb.execAsync(systemSchema.examinee.trim());
|
||||||
console.log('创建 examinee 表成功');
|
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 plainPassword = defaultData.config.find(item => item.key === 'admin_password').value;
|
||||||
const hashedPassword = await argon2.hash(plainPassword);
|
const hashedPassword = await argon2.hash(plainPassword);
|
||||||
|
|
||||||
@ -119,26 +219,54 @@ async function initializeSystemDatabase() {
|
|||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
|
|
||||||
await batchInsert(systemDb, 'config', configData);
|
// 插入config表数据
|
||||||
console.log('插入 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);
|
await batchInsert(systemDb, 'dict_types', defaultData.dictTypes);
|
||||||
console.log('插入 dict_types 表数据成功');
|
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);
|
await batchInsert(systemDb, 'dict_items', defaultData.dictItems);
|
||||||
console.log('插入 dict_items 表数据成功');
|
console.log('插入 dict_items 表数据成功');
|
||||||
|
results.success.push('插入 dict_items 表数据');
|
||||||
// 提交事务
|
|
||||||
await systemDb.runAsync('COMMIT');
|
|
||||||
console.log('提交事务成功');
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 处理错误
|
console.error('插入 dict_items 表数据失败:', error);
|
||||||
await systemDb.runAsync('ROLLBACK');
|
results.failed.push({ operation: '插入 dict_items 表数据', error: error.message });
|
||||||
console.error('回滚事务:', error);
|
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 userDbPath = getUserDbPath();
|
||||||
const userDb = await getDbConnection(userDbPath);
|
const userDb = await getDbConnection(userDbPath);
|
||||||
|
|
||||||
|
// 记录成功和失败的操作
|
||||||
|
const results = { success: [], failed: [] };
|
||||||
|
|
||||||
|
// 创建表结构
|
||||||
|
console.log('开始创建用户数据库表结构...');
|
||||||
|
|
||||||
|
// 创建examinee表
|
||||||
try {
|
try {
|
||||||
// 开始事务
|
await userDb.execAsync(userSchema.examinee.trim());
|
||||||
await userDb.runAsync('BEGIN TRANSACTION');
|
console.log('创建 examinee 表成功');
|
||||||
console.log('开始事务');
|
results.success.push('创建 examinee 表');
|
||||||
|
|
||||||
// 创建表结构
|
|
||||||
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;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 处理错误
|
console.error('创建 examinee 表失败:', error);
|
||||||
await userDb.runAsync('ROLLBACK');
|
results.failed.push({ operation: '创建 examinee 表', error: error.message });
|
||||||
console.error('回滚事务:', error);
|
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 创建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 {
|
export {
|
||||||
addQuestion,
|
addQuestion,
|
||||||
getAllQuestions,
|
getAllQuestions,
|
||||||
@ -383,5 +417,6 @@ export {
|
|||||||
addFillBlankQuestion,
|
addFillBlankQuestion,
|
||||||
updateFillBlankQuestion,
|
updateFillBlankQuestion,
|
||||||
deleteFillBlankQuestion,
|
deleteFillBlankQuestion,
|
||||||
getFillBlankQuestionsByQuestionId
|
getFillBlankQuestionsByQuestionId,
|
||||||
};
|
getQuestionsCountAndScore
|
||||||
|
};
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// 辅助函数:将db.run包装为Promise
|
// 辅助函数:将db.run包装为Promise
|
||||||
const runAsync = (db, sql, params = []) => {
|
export const runAsync = (db, sql, params = []) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
db.run(sql, params, function (err) {
|
db.run(sql, params, function (err) {
|
||||||
if (err) reject(err);
|
if (err) reject(err);
|
||||||
@ -8,10 +8,8 @@ const runAsync = (db, sql, params = []) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export { runAsync };
|
|
||||||
|
|
||||||
// 系统数据库表结构
|
// 系统数据库表结构
|
||||||
const systemSchema = {
|
export const systemSchema = {
|
||||||
config: `
|
config: `
|
||||||
CREATE TABLE IF NOT EXISTS config (
|
CREATE TABLE IF NOT EXISTS config (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@ -184,124 +182,97 @@ const systemSchema = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 用户数据库表结构
|
// 用户数据库表结构
|
||||||
const userSchema = {
|
export const userSchema = {
|
||||||
examineeLog: `
|
examinee: `
|
||||||
CREATE TABLE IF NOT EXISTS examinee_log (
|
CREATE TABLE IF NOT EXISTS examinee (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
examinee_id INTEGER NOT NULL,
|
examinee_name TEXT NOT NULL DEFAULT '',
|
||||||
operation TEXT NOT NULL DEFAULT '',
|
examinee_gender TEXT NOT NULL DEFAULT '',
|
||||||
operation_time TEXT NOT NULL,
|
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
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
`,
|
`,
|
||||||
examineeExam: `
|
examinee_papers: `
|
||||||
CREATE TABLE IF NOT EXISTS examinee_exam (
|
CREATE TABLE IF NOT EXISTS examinee_papers (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
examinee_id INTEGER NOT NULL,
|
examinee_id INTEGER NOT NULL,
|
||||||
exam_name TEXT NOT NULL DEFAULT '',
|
paper_minutes INTEGER NOT NULL DEFAULT 0,
|
||||||
exam_description TEXT NOT NULL DEFAULT '',
|
paper_minuts_min INTEGER NOT NULL DEFAULT 0,
|
||||||
exam_examinee_type TEXT NOT NULL DEFAULT '',
|
paper_start_time TEXT,
|
||||||
exam_notice TEXT NOT NULL DEFAULT '',
|
paper_last_time TEXT,
|
||||||
exam_minutes INTEGER NOT NULL DEFAULT 0,
|
paper_submit_time TEXT,
|
||||||
start_time TEXT NOT NULL,
|
paper_end_time TEXT,
|
||||||
latest_end_time TEXT NOT NULL,
|
paper_status INTEGER NOT NULL DEFAULT 0, -- 试卷状态:0未开始,1进行中,2已交卷
|
||||||
end_time TEXT NOT NULL,
|
paper_score_real REAL DEFAULT 0,
|
||||||
exam_duration INTEGER NOT NULL 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,
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
|
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||||
);
|
);
|
||||||
`,
|
`,
|
||||||
examineePapers: `
|
question_choices: `
|
||||||
CREATE TABLE IF NOT EXISTS examinee_papers (
|
CREATE TABLE IF NOT EXISTS question_choices (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
examinee_id INTEGER NOT NULL,
|
question_id INTEGER NOT NULL,
|
||||||
exam_id INTEGER NOT NULL,
|
choice_description TEXT NOT NULL DEFAULT '',
|
||||||
paper_minutes INTEGER NOT NULL DEFAULT 0,
|
choice_type TEXT NOT NULL DEFAULT 'single',
|
||||||
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,
|
|
||||||
choice_options TEXT NOT NULL,
|
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,
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||||
FOREIGN KEY (paper_question_id) REFERENCES paper_questions(id)
|
|
||||||
);
|
);
|
||||||
`,
|
`,
|
||||||
paperQuestionBlanks: `
|
question_fill_blanks: `
|
||||||
CREATE TABLE IF NOT EXISTS paper_question_blanks (
|
CREATE TABLE IF NOT EXISTS question_fill_blanks (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
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,
|
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,
|
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||||
FOREIGN KEY (paper_question_id) REFERENCES paper_questions(id)
|
|
||||||
);
|
);
|
||||||
`,
|
`
|
||||||
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进行哈希
|
// 注意:在实际初始化数据库时,需要使用argon2对plainPassword进行哈希
|
||||||
// 这里只定义默认数据结构,哈希操作应在index.js中的初始化函数中完成
|
// 这里只定义默认数据结构,哈希操作应在index.js中的初始化函数中完成
|
||||||
const defaultData = {
|
export const defaultData = {
|
||||||
config: [
|
config: [
|
||||||
{ key: "admin_password", value: plainPassword, protected: 1 },
|
{ key: "admin_password", value: plainPassword, protected: 1 },
|
||||||
{ key: "question_bank_version", value: "1", protected: 1 },
|
{ key: "question_bank_version", value: "1", protected: 1 },
|
||||||
@ -368,7 +339,7 @@ const defaultData = {
|
|||||||
item_code: "fill_blank",
|
item_code: "fill_blank",
|
||||||
item_name: "填空题",
|
item_name: "填空题",
|
||||||
item_description: "填写空白处的答案",
|
item_description: "填写空白处的答案",
|
||||||
is_active: 0,
|
is_active: 1,
|
||||||
parent_code: "objective",
|
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),
|
updateFillBlankQuestion: (id, fillBlankData) => ipcRenderer.invoke('question-update-fill-blank', id, fillBlankData),
|
||||||
deleteFillBlankQuestion: (id) => ipcRenderer.invoke('question-delete-fill-blank', id),
|
deleteFillBlankQuestion: (id) => ipcRenderer.invoke('question-delete-fill-blank', id),
|
||||||
fetchFillBlankQuestionsByQuestionId: (questionId) => ipcRenderer.invoke('question-fetch-fill-blank-by-question-id', questionId),
|
fetchFillBlankQuestionsByQuestionId: (questionId) => ipcRenderer.invoke('question-fetch-fill-blank-by-question-id', questionId),
|
||||||
|
getQuestionsCountAndScore: () => ipcRenderer.invoke('question-get-count-and-score'),
|
||||||
// 考试管理相关API
|
// 考试管理相关API
|
||||||
createExam: (examData) => ipcRenderer.invoke('exam-create', examData),
|
createExam: (examData) => ipcRenderer.invoke('exam-create', examData),
|
||||||
fetchAllExams: () => ipcRenderer.invoke('exam-fetch-all'),
|
fetchAllExams: () => ipcRenderer.invoke('exam-fetch-all'),
|
||||||
|
@ -11,7 +11,8 @@ import {
|
|||||||
addFillBlankQuestion,
|
addFillBlankQuestion,
|
||||||
updateFillBlankQuestion,
|
updateFillBlankQuestion,
|
||||||
deleteFillBlankQuestion,
|
deleteFillBlankQuestion,
|
||||||
getFillBlankQuestionsByQuestionId
|
getFillBlankQuestionsByQuestionId,
|
||||||
|
getQuestionsCountAndScore
|
||||||
} from '../db/question.js';
|
} from '../db/question.js';
|
||||||
|
|
||||||
// 导入configService中的increaseQuestionBankVersion方法
|
// 导入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) {
|
export async function initQuestionIpc(ipcMain) {
|
||||||
// 题干管理相关IPC
|
// 题干管理相关IPC
|
||||||
@ -361,4 +375,14 @@ export async function initQuestionIpc(ipcMain) {
|
|||||||
throw error;
|
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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<span class="text-gray-500">待设置</span>
|
<span class="text-gray-500">{{ totalQuestions }}</span>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item>
|
<el-descriptions-item>
|
||||||
<template #label>
|
<template #label>
|
||||||
@ -96,7 +96,7 @@
|
|||||||
考试总分
|
考试总分
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<span class="text-gray-500">待设置</span>
|
<span class="text-gray-500">{{ totalScore }}</span>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
@ -120,6 +120,10 @@
|
|||||||
暂无考试须知
|
暂无考试须知
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -135,7 +139,6 @@
|
|||||||
import Header from '@/components/common/Header.vue'
|
import Header from '@/components/common/Header.vue'
|
||||||
import Footer from '@/components/common/Footer.vue'
|
import Footer from '@/components/common/Footer.vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
|
|
||||||
import { ref, computed, onMounted, watch } from 'vue' // 添加watch导入
|
import { ref, computed, onMounted, watch } from 'vue' // 添加watch导入
|
||||||
import { ElMessage, ElDescriptions, ElDescriptionsItem, ElIcon } from 'element-plus'
|
import { ElMessage, ElDescriptions, ElDescriptionsItem, ElIcon } from 'element-plus'
|
||||||
import { User, Postcard, Ticket, Clock, ScaleToOriginal, Timer } from '@element-plus/icons-vue'
|
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 lastExam = ref(null)
|
||||||
const examLoading = ref(true)
|
const examLoading = ref(true)
|
||||||
const examNotices = ref([])
|
const examNotices = ref([])
|
||||||
|
const totalQuestions = ref(0)
|
||||||
|
const totalScore = ref(0)
|
||||||
|
|
||||||
// 添加watch监听lastExam变化
|
// 添加watch监听lastExam变化
|
||||||
watch(lastExam, (newValue) => {
|
watch(lastExam, (newValue) => {
|
||||||
@ -195,6 +200,18 @@ const formatExamDuration = (minutes) => {
|
|||||||
return `${hours}小时${mins}分钟`
|
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 () => {
|
const fetchLastExam = async () => {
|
||||||
examLoading.value = true
|
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 () => {
|
const startExam = async () => {
|
||||||
if (!lastExam.value) {
|
if (!lastExam.value) {
|
||||||
@ -251,6 +281,7 @@ const startExam = async () => {
|
|||||||
// 组件挂载时获取最新考试信息
|
// 组件挂载时获取最新考试信息
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchLastExam()
|
fetchLastExam()
|
||||||
|
getQuestionsCountAndScore()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user