初始化数据库
This commit is contained in:
parent
9790a3bbd3
commit
f3b783bf86
4
.gitignore
vendored
4
.gitignore
vendored
@ -23,4 +23,6 @@ pnpm-debug.log*
|
||||
*.sw?
|
||||
|
||||
#Electron-builder output
|
||||
/dist_electron
|
||||
/dist_electron
|
||||
|
||||
/high_version
|
2
data/.gitignore
vendored
Normal file
2
data/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
@ -3,6 +3,7 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "vue-cli-service electron:serve",
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"electron:build": "vue-cli-service electron:build",
|
||||
@ -12,7 +13,7 @@
|
||||
"rebuild-deps": "electron-builder install-app-deps",
|
||||
"rebuild-sqlite3": "npm_config_runtime=electron npm_config_target=11.5.0 npm_config_disturl=https://electronjs.org/headers npm_config_build_from_source=true node-pre-gyp rebuild --target=11.5.0 --runtime=electron --fallback-to-build --directory=./node_modules/sqlite3/ --dist-url=https://electronjs.org/headers"
|
||||
},
|
||||
"main": "background.js",
|
||||
"main": "background/main.js",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "1.2.36",
|
||||
"@fortawesome/free-brands-svg-icons": "5.15.4",
|
||||
|
423
src/background/db/index.js
Normal file
423
src/background/db/index.js
Normal file
@ -0,0 +1,423 @@
|
||||
const { getSystemDbPath, getUserDbPath } = require('./path.js');
|
||||
const { systemSchema, userSchema, defaultData } = require('./schema.js');
|
||||
const { openDatabase, batchInsert } = require('./utils.js');
|
||||
const bcrypt = require('bcryptjs');
|
||||
|
||||
// 数据库连接池
|
||||
const dbConnections = new Map();
|
||||
|
||||
// 获取数据库连接
|
||||
exports.getDbConnection = async function getDbConnection(dbPath) {
|
||||
if (dbConnections.has(dbPath)) {
|
||||
console.log(`使用现有数据库连接: ${dbPath}`);
|
||||
return dbConnections.get(dbPath);
|
||||
}
|
||||
|
||||
const db = await openDatabase(dbPath);
|
||||
dbConnections.set(dbPath, db);
|
||||
return db;
|
||||
};
|
||||
|
||||
// 关闭所有数据库连接
|
||||
exports.closeAllConnections = function closeAllConnections() {
|
||||
dbConnections.forEach((db, path) => {
|
||||
try {
|
||||
db.close();
|
||||
console.log(`关闭数据库连接: ${path}`);
|
||||
} catch (error) {
|
||||
console.error(`关闭数据库连接失败: ${path}`, error);
|
||||
}
|
||||
});
|
||||
dbConnections.clear();
|
||||
};
|
||||
|
||||
// 检查数据库是否已初始化
|
||||
exports.checkDatabaseInitialized = async function checkDatabaseInitialized() {
|
||||
try {
|
||||
console.log('开始检查数据库初始化状态...');
|
||||
const systemDb = await exports.getDbConnection(getSystemDbPath());
|
||||
console.log('成功打开系统数据库');
|
||||
|
||||
const result = await systemDb.getAsync('SELECT value FROM config WHERE key = ?', ['initialized']);
|
||||
console.log('查询初始化状态结果:', result);
|
||||
|
||||
const isInitialized = result && result.value === 'true';
|
||||
console.log('数据库初始化状态:', isInitialized ? '已初始化' : '未初始化');
|
||||
return isInitialized;
|
||||
} catch (error) {
|
||||
console.error('检查数据库初始化状态失败:', error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化系统数据库
|
||||
async function initializeSystemDatabase() {
|
||||
console.log('开始初始化系统数据库...');
|
||||
const systemDbPath = getSystemDbPath();
|
||||
const systemDb = await exports.getDbConnection(systemDbPath);
|
||||
|
||||
// 记录成功和失败的操作
|
||||
const results = { success: [], failed: [] };
|
||||
|
||||
// 创建表结构
|
||||
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('开始插入默认数据...');
|
||||
|
||||
// 处理密码哈希
|
||||
try {
|
||||
const plainPassword = defaultData.config.find(item => item.key === 'admin_password').value;
|
||||
const hashedPassword = await bcrypt.hash(plainPassword, 10);
|
||||
|
||||
// 更新密码为哈希值
|
||||
const configData = defaultData.config.map(item => {
|
||||
if (item.key === 'admin_password') {
|
||||
return { ...item, value: hashedPassword };
|
||||
}
|
||||
return item;
|
||||
});
|
||||
|
||||
// 插入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 表数据成功');
|
||||
results.success.push('插入 dict_items 表数据');
|
||||
} catch (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;
|
||||
}
|
||||
|
||||
// 初始化用户数据库
|
||||
async function initializeUserDatabase() {
|
||||
console.log('开始初始化用户数据库...');
|
||||
const userDbPath = getUserDbPath();
|
||||
const userDb = await exports.getDbConnection(userDbPath);
|
||||
|
||||
// 记录成功和失败的操作
|
||||
const results = { success: [], failed: [] };
|
||||
|
||||
// 创建表结构
|
||||
console.log('开始创建用户数据库表结构...');
|
||||
|
||||
// 创建examinee表
|
||||
try {
|
||||
await userDb.execAsync(userSchema.examinee.trim());
|
||||
console.log('创建 examinee 表成功');
|
||||
results.success.push('创建 examinee 表');
|
||||
} catch (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;
|
||||
}
|
||||
|
||||
// 初始化数据库
|
||||
exports.initializeDatabase = async function initializeDatabase() {
|
||||
try {
|
||||
console.log('开始初始化数据库...');
|
||||
|
||||
// 确保只有一个初始化请求在执行
|
||||
if (global.isInitializing) {
|
||||
console.log('数据库初始化已在进行中,等待完成...');
|
||||
while (global.isInitializing) {
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
}
|
||||
return global.initResult;
|
||||
}
|
||||
|
||||
global.isInitializing = true;
|
||||
global.initResult = false;
|
||||
|
||||
// 先初始化系统数据库
|
||||
console.log('开始初始化系统数据库...');
|
||||
const systemResult = await initializeSystemDatabase();
|
||||
console.log('系统数据库初始化结果:', systemResult ? '成功' : '失败');
|
||||
|
||||
if (!systemResult) {
|
||||
throw new Error('系统数据库初始化失败');
|
||||
}
|
||||
|
||||
// 再初始化用户数据库
|
||||
console.log('开始初始化用户数据库...');
|
||||
const userResult = await initializeUserDatabase();
|
||||
console.log('用户数据库初始化结果:', userResult ? '成功' : '失败');
|
||||
|
||||
if (!userResult) {
|
||||
throw new Error('用户数据库初始化失败');
|
||||
}
|
||||
|
||||
// 更新初始化状态
|
||||
console.log('更新数据库初始化状态...');
|
||||
const systemDb = await exports.getDbConnection(getSystemDbPath());
|
||||
await systemDb.runAsync('UPDATE config SET value = ? WHERE key = ?', ['true', 'initialized']);
|
||||
console.log('数据库初始化状态更新成功');
|
||||
|
||||
console.log('数据库整体初始化成功');
|
||||
global.initResult = true;
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
console.error('数据库初始化失败:', error);
|
||||
global.initResult = false;
|
||||
return { success: false, error: error.message };
|
||||
} finally {
|
||||
global.isInitializing = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 应用退出时关闭所有连接
|
||||
process.on('exit', exports.closeAllConnections);
|
53
src/background/db/path.js
Normal file
53
src/background/db/path.js
Normal file
@ -0,0 +1,53 @@
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const { app } = require('electron');
|
||||
|
||||
// 判断是否为开发环境
|
||||
const isDev = process.env.NODE_ENV === 'development' || !app.isPackaged;
|
||||
|
||||
// 检测是否为便携模式
|
||||
let isPortable = false;
|
||||
const exePath = app.getPath('exe');
|
||||
const appDir = path.dirname(exePath);
|
||||
const portableFlagPath = path.join(appDir, 'portable.txt');
|
||||
|
||||
// 如果应用目录中存在portable.txt文件,则启用便携模式
|
||||
if (!isDev && fs.existsSync(portableFlagPath)) {
|
||||
isPortable = true;
|
||||
console.log('启用便携模式');
|
||||
}
|
||||
|
||||
// 根据模式选择数据目录
|
||||
let dataDir;
|
||||
if (isDev) {
|
||||
// 开发环境:数据存储在工程的data目录
|
||||
dataDir = path.join(process.cwd(), 'data');
|
||||
} else if (isPortable) {
|
||||
// 便携模式:数据存储在应用目录下的data文件夹
|
||||
dataDir = path.join(appDir, 'data');
|
||||
} else {
|
||||
// 非便携模式:数据存储在应用同级的data目录
|
||||
dataDir = path.join(appDir, 'data');
|
||||
}
|
||||
|
||||
// 确保数据目录存在
|
||||
if (!fs.existsSync(dataDir)) {
|
||||
fs.mkdirSync(dataDir, { recursive: true });
|
||||
console.log(`创建数据目录: ${dataDir}`);
|
||||
}
|
||||
|
||||
// 系统数据库路径
|
||||
function getSystemDbPath() {
|
||||
return path.join(dataDir, 'system.db');
|
||||
}
|
||||
|
||||
// 用户数据库路径
|
||||
function getUserDbPath() {
|
||||
return path.join(dataDir, 'user.db');
|
||||
}
|
||||
|
||||
// 导出函数供其他模块使用
|
||||
module.exports = {
|
||||
getSystemDbPath,
|
||||
getUserDbPath
|
||||
};
|
411
src/background/db/schema.js
Normal file
411
src/background/db/schema.js
Normal file
@ -0,0 +1,411 @@
|
||||
// 执行SQL语句的工具函数
|
||||
const runAsync = (db, sql, params = []) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.run(sql, params, function (err) {
|
||||
if (err) reject(err);
|
||||
else resolve(this);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// 系统数据库表结构
|
||||
systemSchema = {
|
||||
config: `
|
||||
CREATE TABLE IF NOT EXISTS config (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
key TEXT NOT NULL UNIQUE,
|
||||
value TEXT NOT NULL,
|
||||
protected INTEGER DEFAULT 0
|
||||
);
|
||||
`,
|
||||
dictTypes: `
|
||||
CREATE TABLE IF NOT EXISTS dict_types (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
type_code TEXT NOT NULL UNIQUE,
|
||||
type_name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
`,
|
||||
dictItems: `
|
||||
CREATE TABLE IF NOT EXISTS dict_items (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
type_code TEXT NOT NULL,
|
||||
item_code TEXT NOT NULL,
|
||||
item_name TEXT NOT NULL,
|
||||
item_description TEXT DEFAULT '',
|
||||
parent_code TEXT,
|
||||
is_active BOOLEAN DEFAULT 1,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(type_code, item_code),
|
||||
FOREIGN KEY (type_code) REFERENCES dict_types(type_code)
|
||||
);
|
||||
`,
|
||||
questions: `
|
||||
CREATE TABLE IF NOT EXISTS questions (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
question_type TEXT NOT NULL,
|
||||
question_name TEXT NOT NULL DEFAULT '',
|
||||
question_description TEXT NOT NULL DEFAULT '',
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (question_type) REFERENCES dict_types(type_code)
|
||||
);
|
||||
`,
|
||||
questionDatasets: `
|
||||
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,
|
||||
updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (question_id) REFERENCES questions(id)
|
||||
);
|
||||
`,
|
||||
questionImages: `
|
||||
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,
|
||||
FOREIGN KEY (question_id) REFERENCES questions(id)
|
||||
);
|
||||
`,
|
||||
questionFillTable: `
|
||||
CREATE TABLE IF NOT EXISTS question_fill_table (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
question_id INTEGER NOT NULL,
|
||||
table_name TEXT NOT NULL DEFAULT '',
|
||||
table_data TEXT NOT NULL,
|
||||
table_description TEXT NOT NULL DEFAULT '',
|
||||
score REAL,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (question_id) REFERENCES questions(id)
|
||||
);
|
||||
`,
|
||||
questionFillTableBlanks: `
|
||||
CREATE TABLE IF NOT EXISTS question_fill_table_blanks (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
question_id INTEGER NOT NULL,
|
||||
table_id INTEGER NOT NULL,
|
||||
cell_position TEXT NOT NULL,
|
||||
cell_type TEXT NOT NULL DEFAULT 'number',
|
||||
correct_answer TEXT NOT NULL DEFAULT '',
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (question_id) REFERENCES questions(id),
|
||||
FOREIGN KEY (table_id) REFERENCES question_fill_table(id)
|
||||
);
|
||||
`,
|
||||
questionChoices: `
|
||||
CREATE TABLE IF NOT EXISTS question_choices (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
question_id INTEGER NOT NULL,
|
||||
choice_description TEXT NOT NULL DEFAULT '',
|
||||
choice_type TEXT NOT NULL DEFAULT 'single',
|
||||
choice_options TEXT NOT NULL,
|
||||
correct_answers TEXT NOT NULL,
|
||||
score REAL,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (question_id) REFERENCES questions(id)
|
||||
);
|
||||
`,
|
||||
questionFillBlanks: `
|
||||
CREATE TABLE IF NOT EXISTS question_fill_blanks (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
question_id INTEGER NOT NULL,
|
||||
blank_description TEXT NOT NULL DEFAULT '',
|
||||
blank_count INTEGER NOT NULL DEFAULT 0,
|
||||
correct_answers TEXT NOT NULL DEFAULT '',
|
||||
score REAL,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (question_id) REFERENCES questions(id)
|
||||
);
|
||||
`,
|
||||
questionJudge: `
|
||||
CREATE TABLE IF NOT EXISTS question_judge (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
question_id INTEGER NOT NULL,
|
||||
judge_ask TEXT NOT NULL DEFAULT '',
|
||||
judge_answer INTEGER NOT NULL,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (question_id) REFERENCES questions(id)
|
||||
);
|
||||
`,
|
||||
questionShort: `
|
||||
CREATE TABLE IF NOT EXISTS question_short (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
question_id INTEGER NOT NULL,
|
||||
short_ask TEXT NOT NULL DEFAULT '',
|
||||
short_answer_ref TEXT NOT NULL DEFAULT '',
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (question_id) REFERENCES questions(id)
|
||||
);
|
||||
`,
|
||||
exam: `
|
||||
CREATE TABLE IF NOT EXISTS exam (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
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,
|
||||
exam_minutes_min INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
`,
|
||||
examinee: `
|
||||
CREATE TABLE IF NOT EXISTS examinee (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
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,
|
||||
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
`
|
||||
};
|
||||
|
||||
// 用户数据库表结构
|
||||
userSchema = {
|
||||
examinee: `
|
||||
CREATE TABLE IF NOT EXISTS examinee (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
examinee_name TEXT NOT NULL DEFAULT '',
|
||||
examinee_gender TEXT,
|
||||
examinee_unit TEXT,
|
||||
written_exam_room TEXT,
|
||||
written_exam_seat TEXT,
|
||||
computer_exam_room TEXT,
|
||||
computer_exam_seat TEXT,
|
||||
examinee_id_card TEXT NOT NULL DEFAULT '',
|
||||
examinee_admission_ticket TEXT NOT NULL DEFAULT '',
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
`,
|
||||
examinee_papers: `
|
||||
CREATE TABLE IF NOT EXISTS examinee_papers (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
examinee_id INTEGER NOT NULL,
|
||||
paper_minutes INTEGER NOT NULL DEFAULT 0,
|
||||
paper_minutes_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
|
||||
);
|
||||
`,
|
||||
question_choices: `
|
||||
CREATE TABLE IF NOT EXISTS question_choices (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
question_id INTEGER NOT NULL,
|
||||
choice_description TEXT NOT NULL DEFAULT '',
|
||||
choice_type TEXT NOT NULL DEFAULT 'single',
|
||||
choice_options TEXT NOT NULL,
|
||||
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
|
||||
);
|
||||
`,
|
||||
question_fill_blanks: `
|
||||
CREATE TABLE IF NOT EXISTS question_fill_blanks (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
question_id INTEGER NOT NULL,
|
||||
blank_description TEXT NOT NULL DEFAULT '',
|
||||
blank_count INTEGER NOT NULL DEFAULT 0,
|
||||
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
|
||||
);
|
||||
`
|
||||
};
|
||||
|
||||
// 初始化默认数据
|
||||
// 系统配置默认数据
|
||||
const plainPassword = "t2t6a9"; // 明文密码变量定义
|
||||
|
||||
// 注意:在实际初始化数据库时,需要使用bcryptjs对plainPassword进行哈希
|
||||
// 这里只定义默认数据结构,哈希操作应在index.js中的初始化函数中完成
|
||||
defaultData = {
|
||||
config: [
|
||||
{ key: "admin_password", value: plainPassword, protected: 1 },
|
||||
{ key: "question_bank_version", value: "1", protected: 1 },
|
||||
{ key: "exam_version", value: "1", protected: 1 },
|
||||
{ key: "initialized", value: "1", protected: 1 },
|
||||
],
|
||||
// 字典类型默认数据
|
||||
dictTypes: [
|
||||
{
|
||||
type_code: "question_category",
|
||||
type_name: "题型分类",
|
||||
description: "用于区分客观题和主观题",
|
||||
},
|
||||
{
|
||||
type_code: "question_type",
|
||||
type_name: "题型",
|
||||
description: "存储所有题型(选择题、填空题等)",
|
||||
},
|
||||
{
|
||||
type_code: "user_role",
|
||||
type_name: "用户角色",
|
||||
description: "区分不同用户类型",
|
||||
},
|
||||
],
|
||||
// 字典项默认数据
|
||||
dictItems: [
|
||||
// 题型分类
|
||||
{
|
||||
type_code: "question_category",
|
||||
item_code: "objective",
|
||||
item_name: "客观题",
|
||||
item_description: "有固定答案,机器可自动评分",
|
||||
is_active: 1,
|
||||
parent_code: null,
|
||||
},
|
||||
{
|
||||
type_code: "question_category",
|
||||
item_code: "subjective",
|
||||
item_name: "主观题",
|
||||
item_description: "需人工评分,答案不唯一",
|
||||
is_active: 1,
|
||||
parent_code: null,
|
||||
},
|
||||
// 题型
|
||||
{
|
||||
type_code: "question_type",
|
||||
item_code: "choice",
|
||||
item_name: "选择题",
|
||||
item_description: "包含单选和多选",
|
||||
is_active: 1,
|
||||
parent_code: "objective",
|
||||
},
|
||||
{
|
||||
type_code: "question_type",
|
||||
item_code: "fill_blank",
|
||||
item_name: "填空题",
|
||||
item_description: "填写空白处的答案",
|
||||
is_active: 1,
|
||||
parent_code: "objective",
|
||||
},
|
||||
{
|
||||
type_code: "question_type",
|
||||
item_code: "fill_table",
|
||||
item_name: "填表题",
|
||||
item_description: "填写表格内容",
|
||||
is_active: 0,
|
||||
parent_code: "objective",
|
||||
},
|
||||
{
|
||||
type_code: "question_type",
|
||||
item_code: "true_false",
|
||||
item_name: "判断题",
|
||||
item_description: "判断对错",
|
||||
is_active: 0,
|
||||
parent_code: "objective",
|
||||
},
|
||||
{
|
||||
type_code: "question_type",
|
||||
item_code: "short_answer",
|
||||
item_name: "问答题",
|
||||
item_description: "简短回答问题",
|
||||
is_active: 0,
|
||||
parent_code: "subjective",
|
||||
},
|
||||
{
|
||||
type_code: "question_type",
|
||||
item_code: "analysis",
|
||||
item_name: "分析题",
|
||||
item_description: "需要分析问题",
|
||||
is_active: 0,
|
||||
parent_code: "subjective",
|
||||
},
|
||||
{
|
||||
type_code: "question_type",
|
||||
item_code: "essay",
|
||||
item_name: "论述题",
|
||||
item_description: "详细论述",
|
||||
is_active: 0,
|
||||
parent_code: "subjective",
|
||||
},
|
||||
// 用户角色
|
||||
{
|
||||
type_code: "user_role",
|
||||
item_code: "admin",
|
||||
item_name: "管理员",
|
||||
item_description: "系统管理员",
|
||||
is_active: 1,
|
||||
parent_code: null,
|
||||
},
|
||||
{
|
||||
type_code: "user_role",
|
||||
item_code: "student",
|
||||
item_name: "考生",
|
||||
item_description: "参加考试的用户",
|
||||
is_active: 1,
|
||||
parent_code: null,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// 导出函数和常量供其他模块使用
|
||||
module.exports = {
|
||||
runAsync,
|
||||
systemSchema,
|
||||
userSchema,
|
||||
defaultData
|
||||
};
|
108
src/background/db/utils.js
Normal file
108
src/background/db/utils.js
Normal file
@ -0,0 +1,108 @@
|
||||
const sqlite3 = require('sqlite3');
|
||||
const { promisify } = require('util');
|
||||
|
||||
sqlite3.verbose();
|
||||
|
||||
// 数据库连接池简单实现
|
||||
const dbConnections = new Map();
|
||||
|
||||
// 打开数据库并添加到连接池
|
||||
async function openDatabase(dbPath) {
|
||||
console.log(`打开数据库连接: ${dbPath}`);
|
||||
|
||||
// 检查是否已有连接
|
||||
if (dbConnections.has(dbPath)) {
|
||||
console.log(`使用现有数据库连接: ${dbPath}`);
|
||||
return dbConnections.get(dbPath);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const db = new sqlite3.Database(dbPath, (err) => {
|
||||
if (err) {
|
||||
console.error(`打开数据库失败: ${err.message}`);
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`成功打开数据库: ${dbPath}`);
|
||||
|
||||
// promisify数据库方法
|
||||
db.getAsync = promisify(db.get).bind(db);
|
||||
db.allAsync = promisify(db.all).bind(db);
|
||||
|
||||
// 自定义实现runAsync以获取lastID
|
||||
db.runAsync = function(sql, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.run(sql, params, function(err) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve({
|
||||
lastID: this.lastID,
|
||||
changes: this.changes
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
db.execAsync = promisify(db.exec).bind(db);
|
||||
|
||||
// 添加到连接池
|
||||
dbConnections.set(dbPath, db);
|
||||
|
||||
resolve(db);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 添加重试机制的执行函数
|
||||
async function executeWithRetry(db, operation, maxRetries = 3) {
|
||||
let retries = 0;
|
||||
while (retries < maxRetries) {
|
||||
try {
|
||||
return await operation();
|
||||
} catch (error) {
|
||||
if (error.code === 'SQLITE_BUSY' && retries < maxRetries - 1) {
|
||||
retries++;
|
||||
console.log(`数据库忙,正在重试 (${retries}/${maxRetries})...`);
|
||||
await new Promise(resolve => setTimeout(resolve, 500 * retries)); // 指数退避
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 修改batchInsert函数使用重试机制
|
||||
async function batchInsert(db, table, data) {
|
||||
if (!data || data.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const columns = Object.keys(data[0]).join(', ');
|
||||
const placeholders = data.map(() => {
|
||||
return '(' + Object.keys(data[0]).map(() => '?').join(', ') + ')';
|
||||
}).join(', ');
|
||||
|
||||
const values = [];
|
||||
data.forEach(item => {
|
||||
Object.values(item).forEach(value => {
|
||||
values.push(value);
|
||||
});
|
||||
});
|
||||
|
||||
const sql = `INSERT INTO ${table} (${columns}) VALUES ${placeholders}`;
|
||||
|
||||
return executeWithRetry(db, async () => {
|
||||
await db.runAsync(sql, values);
|
||||
console.log(`成功插入 ${data.length} 条记录到 ${table} 表`);
|
||||
});
|
||||
}
|
||||
|
||||
// 导出函数供其他模块使用
|
||||
module.exports = {
|
||||
openDatabase,
|
||||
batchInsert,
|
||||
executeWithRetry
|
||||
};
|
BIN
src/background/font/SourceHanSansSC-Bold.otf
Normal file
BIN
src/background/font/SourceHanSansSC-Bold.otf
Normal file
Binary file not shown.
BIN
src/background/font/SourceHanSansSC-ExtraLight.otf
Normal file
BIN
src/background/font/SourceHanSansSC-ExtraLight.otf
Normal file
Binary file not shown.
BIN
src/background/font/SourceHanSansSC-Heavy.otf
Normal file
BIN
src/background/font/SourceHanSansSC-Heavy.otf
Normal file
Binary file not shown.
BIN
src/background/font/SourceHanSansSC-Light.otf
Normal file
BIN
src/background/font/SourceHanSansSC-Light.otf
Normal file
Binary file not shown.
BIN
src/background/font/SourceHanSansSC-Medium.otf
Normal file
BIN
src/background/font/SourceHanSansSC-Medium.otf
Normal file
Binary file not shown.
BIN
src/background/font/SourceHanSansSC-Normal.otf
Normal file
BIN
src/background/font/SourceHanSansSC-Normal.otf
Normal file
Binary file not shown.
BIN
src/background/font/SourceHanSansSC-Regular.otf
Normal file
BIN
src/background/font/SourceHanSansSC-Regular.otf
Normal file
Binary file not shown.
BIN
src/background/font/simsun.ttc
Normal file
BIN
src/background/font/simsun.ttc
Normal file
Binary file not shown.
BIN
src/background/font/simsun.ttf
Normal file
BIN
src/background/font/simsun.ttf
Normal file
Binary file not shown.
@ -7,6 +7,9 @@ import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
|
||||
const bcrypt = require('bcryptjs')
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production'
|
||||
|
||||
// 导入数据库相关函数
|
||||
const { checkDatabaseInitialized, initializeDatabase } = require('./db/index.js');
|
||||
|
||||
// Scheme must be registered before the app is ready
|
||||
protocol.registerSchemesAsPrivileged([
|
||||
{ scheme: 'app', privileges: { secure: true, standard: true } }
|
||||
@ -18,7 +21,11 @@ async function createWindow() {
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
// 修改这一行
|
||||
preload: require('path').join(__dirname, 'preload.js'),
|
||||
|
||||
// 改为使用绝对路径解析
|
||||
preload: require('path').join(process.cwd(), 'src/preload.js'),
|
||||
nodeIntegration: false,
|
||||
contextIsolation: true
|
||||
}
|
||||
@ -142,3 +149,22 @@ ipcMain.handle('hashTest', async (event, inputString) => {
|
||||
throw error
|
||||
}
|
||||
})
|
||||
|
||||
// 数据库相关IPC接口
|
||||
ipcMain.handle('check-database-initialized', async () => {
|
||||
try {
|
||||
return await checkDatabaseInitialized()
|
||||
} catch (error) {
|
||||
console.error('Failed to check database initialization:', error)
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.handle('initialize-database', async () => {
|
||||
try {
|
||||
return await initializeDatabase()
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize database:', error)
|
||||
return false
|
||||
}
|
||||
})
|
@ -1,7 +1,19 @@
|
||||
// Preload script runs in a context that has access to both Node.js and browser APIs
|
||||
const { contextBridge, ipcRenderer } = require('electron')
|
||||
|
||||
// Expose ipcRenderer to the renderer process through contextBridge
|
||||
// 暴露API给渲染进程
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
// 数据库相关
|
||||
checkDatabaseInitialized: () => ipcRenderer.invoke('check-database-initialized'),
|
||||
initializeDatabase: () => ipcRenderer.invoke('initialize-database'),
|
||||
|
||||
// 保留原有的ipcRenderer接口,确保兼容性
|
||||
ipcRenderer: {
|
||||
invoke: (channel, data) => ipcRenderer.invoke(channel, data)
|
||||
}
|
||||
})
|
||||
|
||||
// 也保留原来的electron对象,确保现有功能正常
|
||||
contextBridge.exposeInMainWorld('electron', {
|
||||
ipcRenderer: {
|
||||
invoke: (channel, data) => ipcRenderer.invoke(channel, data)
|
||||
|
@ -75,6 +75,61 @@
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 数据库初始化测试 -->
|
||||
<div class="database-test">
|
||||
<h3>数据库初始化测试</h3>
|
||||
<el-card class="card-test">
|
||||
<template slot="header">
|
||||
<div class="card-header">
|
||||
<span>数据库状态</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="database-status">
|
||||
<el-alert
|
||||
:title="`数据库状态: ${dbInitialized ? '已初始化' : '未初始化'}`"
|
||||
:type="dbInitialized ? 'success' : 'warning'"
|
||||
show-icon
|
||||
:closable="false"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="!dbInitialized" class="initialize-button-container">
|
||||
<el-button
|
||||
type="primary"
|
||||
size="large"
|
||||
@click="initializeDatabase"
|
||||
:loading="initializing"
|
||||
style="margin-top: 20px;"
|
||||
>
|
||||
{{ initializing ? '正在初始化...' : '初始化数据库' }}
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div v-if="dbInitResult" class="init-result">
|
||||
<el-alert
|
||||
:title="dbInitResult.success ? '初始化成功' : '初始化失败'"
|
||||
:type="dbInitResult.success ? 'success' : 'error'"
|
||||
show-icon
|
||||
:closable="false"
|
||||
>
|
||||
<template slot="desc" v-if="!dbInitResult.success">
|
||||
失败原因: {{ dbInitResult.error }}
|
||||
</template>
|
||||
</el-alert>
|
||||
</div>
|
||||
|
||||
<div v-if="dbInitError" class="init-error">
|
||||
<el-alert
|
||||
:title="`获取数据库状态失败: ${dbInitError}`"
|
||||
type="error"
|
||||
show-icon
|
||||
:closable="false"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap组件测试 -->
|
||||
<div class="bootstrap-test">
|
||||
<h3>Bootstrap 组件测试</h3>
|
||||
@ -200,7 +255,12 @@ export default {
|
||||
{ id: 'search', label: '搜索', elementIcon: 'el-icon-search' },
|
||||
{ id: 'edit', label: '编辑', elementIcon: 'el-icon-edit' },
|
||||
{ id: 'delete', label: '删除', elementIcon: 'el-icon-delete' }
|
||||
]
|
||||
],
|
||||
// 数据库相关状态
|
||||
dbInitialized: null,
|
||||
dbInitResult: null,
|
||||
dbInitError: null,
|
||||
initializing: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -243,7 +303,55 @@ export default {
|
||||
// 显示Bootstrap模态框
|
||||
showBootstrapModal() {
|
||||
$('#bootstrapModal').modal('show')
|
||||
},
|
||||
// 检查数据库初始化状态
|
||||
async checkDatabaseInitialized() {
|
||||
try {
|
||||
this.dbInitError = null
|
||||
|
||||
// 安全地检查 window.electronAPI 是否可用
|
||||
if (typeof window !== 'undefined' && window.electronAPI) {
|
||||
const initialized = await window.electronAPI.checkDatabaseInitialized()
|
||||
this.dbInitialized = initialized
|
||||
} else {
|
||||
throw new Error('Electron API 不可用')
|
||||
}
|
||||
} catch (err) {
|
||||
this.dbInitError = err.message
|
||||
console.error('检查数据库初始化状态失败:', err)
|
||||
}
|
||||
},
|
||||
|
||||
// 初始化数据库
|
||||
async initializeDatabase() {
|
||||
try {
|
||||
this.dbInitResult = null
|
||||
this.initializing = true
|
||||
|
||||
// 安全地检查 window.electronAPI 是否可用
|
||||
if (typeof window !== 'undefined' && window.electronAPI) {
|
||||
const result = await window.electronAPI.initializeDatabase()
|
||||
this.dbInitResult = result
|
||||
|
||||
// 如果初始化成功,更新状态
|
||||
if (result && result.success) {
|
||||
this.dbInitialized = true
|
||||
}
|
||||
} else {
|
||||
throw new Error('Electron API 不可用')
|
||||
}
|
||||
} catch (err) {
|
||||
this.dbInitResult = { success: false, error: err.message }
|
||||
console.error('数据库初始化失败:', err)
|
||||
} finally {
|
||||
this.initializing = false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 组件挂载后检查数据库状态
|
||||
async mounted() {
|
||||
await this.checkDatabaseInitialized()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -311,6 +419,26 @@ pre {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
/* 数据库测试样式 */
|
||||
.database-test {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.database-status {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.initialize-button-container {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.init-result,
|
||||
.init-error {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.bootstrap-test {
|
||||
margin-top: 40px;
|
||||
padding: 20px;
|
||||
|
@ -4,6 +4,8 @@ module.exports = {
|
||||
nodeIntegration: false,
|
||||
contextIsolation: true,
|
||||
preload: 'src/preload.js',
|
||||
// 添加这一行,指定主进程文件路径
|
||||
mainProcessFile: 'src/background/main.js',
|
||||
// If you want to use ESLint for your preload script,
|
||||
// set lintPreloadFiles to true
|
||||
lintPreloadFiles: false
|
||||
|
Loading…
Reference in New Issue
Block a user