661 lines
18 KiB
JavaScript
661 lines
18 KiB
JavaScript
// 确保所有导入都使用 ES 模块语法
|
|
import { app, BrowserWindow, ipcMain } from "electron";
|
|
import path from "path";
|
|
import { fileURLToPath } from "url";
|
|
import { checkDatabaseInitialized, initializeDatabase } from "./db/index.js";
|
|
// 导入配置项服务
|
|
import {
|
|
fetchAllConfigs,
|
|
fetchConfigById,
|
|
saveConfig,
|
|
removeConfig,
|
|
getSystemConfig,
|
|
updateSystemConfig,
|
|
increaseQuestionBankVersion,
|
|
initAuthIpc,
|
|
} from "./service/configService.js";
|
|
// 导入字典服务 - 使用实际导出的函数名称
|
|
import {
|
|
fetchDictTypes,
|
|
fetchDictItemsByTypeCode,
|
|
createDictType,
|
|
modifyDictType,
|
|
removeDictType,
|
|
createDictItem,
|
|
modifyDictItem,
|
|
removeDictItem,
|
|
fetchDictItemsWithTypes,
|
|
checkDictParentCode, // 添加这一行
|
|
checkDictChildReferences, // 添加这一行
|
|
} from "./service/dictService.js";
|
|
// 导入题干服务
|
|
import {
|
|
createQuestion,
|
|
fetchAllQuestions,
|
|
fetchQuestionById,
|
|
modifyQuestion,
|
|
removeQuestion,
|
|
fetchAllQuestionsWithRelations,
|
|
modifyQuestionDescription,
|
|
createChoiceQuestion,
|
|
modifyChoiceQuestion,
|
|
createFillBlankQuestion,
|
|
modifyFillBlankQuestion,
|
|
removeFillBlankQuestion,
|
|
fetchFillBlankQuestionsByQuestionId
|
|
} from './service/questionService.js';
|
|
import {
|
|
createNewExam,
|
|
fetchAllExams,
|
|
fetchExamById,
|
|
modifyExam,
|
|
removeExam,
|
|
fetchLastExam, // 添加这一行
|
|
} from "./service/examService.js";
|
|
|
|
// 添加考生服务导入
|
|
// 在文件开头的导入语句中添加新函数
|
|
import {
|
|
fetchAllExaminees,
|
|
fetchExamineeById,
|
|
createExamineeService,
|
|
updateExamineeService,
|
|
deleteExamineeService,
|
|
fetchExamineeByIdCardAndAdmissionTicket,
|
|
} from "./service/examineeService.js";
|
|
|
|
// 定义 __dirname 和 __filename
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
// 确保在应用最开始处添加单实例锁检查
|
|
// 尝试获取单实例锁
|
|
const gotTheLock = app.requestSingleInstanceLock();
|
|
|
|
// 如果获取锁失败,说明已有实例在运行,直接退出
|
|
if (!gotTheLock) {
|
|
app.quit();
|
|
} else {
|
|
// 设置第二个实例启动时的处理
|
|
app.on("second-instance", (event, commandLine, workingDirectory) => {
|
|
// 当用户尝试启动第二个实例时,聚焦到已有的主窗口
|
|
const mainWindow = BrowserWindow.getAllWindows()[0];
|
|
if (mainWindow) {
|
|
if (mainWindow.isMinimized()) mainWindow.restore();
|
|
mainWindow.focus();
|
|
}
|
|
});
|
|
}
|
|
|
|
// 保存主窗口引用
|
|
let mainWindow = null;
|
|
|
|
function createWindow() {
|
|
// 如果已经有窗口,直接返回
|
|
if (mainWindow) {
|
|
return;
|
|
}
|
|
|
|
mainWindow = new BrowserWindow({
|
|
fullscreen: true,
|
|
webPreferences: {
|
|
preload: path.join(__dirname, "../electron/preload.js"),
|
|
nodeIntegration: false,
|
|
contextIsolation: true,
|
|
},
|
|
});
|
|
|
|
if (process.env.NODE_ENV === "development") {
|
|
mainWindow.loadURL("http://localhost:5173/");
|
|
mainWindow.webContents.openDevTools();
|
|
} else {
|
|
mainWindow.loadFile(path.join(__dirname, "../dist/index.html"));
|
|
}
|
|
|
|
// 当窗口关闭时,清空引用
|
|
mainWindow.on("closed", () => {
|
|
mainWindow = null;
|
|
});
|
|
}
|
|
|
|
// Initalize app
|
|
app.whenReady().then(() => {
|
|
setupApp();
|
|
createWindow();
|
|
setupIpcMain();
|
|
});
|
|
|
|
app.on("window-all-closed", () => {
|
|
if (process.platform !== "darwin") {
|
|
app.quit();
|
|
}
|
|
});
|
|
|
|
app.on("activate", () => {
|
|
// 只有当没有窗口时才创建新窗口
|
|
if (BrowserWindow.getAllWindows().length === 0) {
|
|
createWindow();
|
|
}
|
|
});
|
|
|
|
// Check database initialization status
|
|
async function setupApp() {
|
|
try {
|
|
console.log("应用启动 - 检查数据库初始化状态...");
|
|
|
|
// 使用全局变量防止重复初始化检查
|
|
if (global.dbInitCheck) {
|
|
console.log("数据库初始化检查已完成");
|
|
return;
|
|
}
|
|
global.dbInitCheck = true;
|
|
|
|
const isInitialized = await checkDatabaseInitialized();
|
|
console.log("数据库初始化状态:", isInitialized);
|
|
|
|
// 只检查状态,不自动初始化
|
|
} catch (error) {
|
|
console.error("数据库检查过程中出错:", error);
|
|
}
|
|
}
|
|
|
|
function setupIpcMain() {
|
|
// 考生登录IPC
|
|
ipcMain.handle("user-login", async (event, {idCard, admissionTicket}) => {
|
|
// return {data: 'hello world'};
|
|
try {
|
|
const examinee = await fetchExamineeByIdCardAndAdmissionTicket(idCard, admissionTicket);
|
|
console.log(examinee);
|
|
// const examinee = 'hello world';
|
|
if (examinee) {
|
|
return { success: true, data: examinee };
|
|
} else {
|
|
return { success: false, error: "未找到匹配的考生信息" };
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to login examinee:", error);
|
|
return { success: false, error: error.message };
|
|
}
|
|
});
|
|
// 数据库相关
|
|
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;
|
|
}
|
|
});
|
|
|
|
// 系统相关
|
|
ipcMain.handle("system-get-config", async () => {
|
|
try {
|
|
return await getSystemConfig();
|
|
} catch (error) {
|
|
console.error("Failed to get system config:", error);
|
|
return null;
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("system-update-config", async (event, config) => {
|
|
try {
|
|
return await updateSystemConfig(config);
|
|
} catch (error) {
|
|
console.error("Failed to update system config:", error);
|
|
return false;
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("system-increase-question-band-version", async () => {
|
|
try {
|
|
return await increaseQuestionBankVersion();
|
|
} catch (error) {
|
|
console.error("Failed to increase question band version:", error);
|
|
return false;
|
|
}
|
|
});
|
|
|
|
// 初始化认证相关IPC
|
|
initAuthIpc(ipcMain);
|
|
|
|
// 配置项管理相关IPC
|
|
ipcMain.handle("config-fetch-all", async () => {
|
|
try {
|
|
return await fetchAllConfigs();
|
|
} catch (error) {
|
|
console.error("Failed to fetch all configs:", error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("config-fetch-by-id", async (event, id) => {
|
|
try {
|
|
return await fetchConfigById(id);
|
|
} catch (error) {
|
|
console.error(`Failed to fetch config by id ${id}:`, error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("config-save", async (event, { key, value }) => {
|
|
try {
|
|
await saveConfig(key, value);
|
|
return true;
|
|
} catch (error) {
|
|
console.error(`Failed to save config ${key}:`, error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("config-delete", async (event, id) => {
|
|
try {
|
|
await removeConfig(id);
|
|
return true;
|
|
} catch (error) {
|
|
console.error(`Failed to delete config ${id}:`, error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
// 字典管理相关IPC - 使用正确的函数名称
|
|
ipcMain.handle("dict-fetch-types", async () => {
|
|
try {
|
|
return await fetchDictTypes();
|
|
} catch (error) {
|
|
console.error("Failed to fetch dict types:", error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
ipcMain.handle(
|
|
"dict-fetch-items-by-type",
|
|
async (event, typeCode, isActive = undefined) => {
|
|
try {
|
|
return await fetchDictItemsByTypeCode(typeCode, isActive);
|
|
} catch (error) {
|
|
console.error(`Failed to fetch dict items by type ${typeCode}:`, error);
|
|
throw error;
|
|
}
|
|
}
|
|
);
|
|
|
|
ipcMain.handle("dict-create-type", async (event, dictType) => {
|
|
try {
|
|
return await createDictType(dictType);
|
|
} catch (error) {
|
|
console.error("Failed to create dict type:", error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
// 将 updateDictType 改为 modifyDictType
|
|
ipcMain.handle("dict-update-type", async (event, dictType) => {
|
|
try {
|
|
return await modifyDictType(dictType.id, dictType);
|
|
} catch (error) {
|
|
console.error("Failed to update dict type:", error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
// 将 deleteDictType 改为 removeDictType
|
|
ipcMain.handle("dict-delete-type", async (event, typeCode) => {
|
|
try {
|
|
return await removeDictType(typeCode);
|
|
} catch (error) {
|
|
console.error(`Failed to delete dict type ${typeCode}:`, error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("dict-create-item", async (event, dictItem) => {
|
|
try {
|
|
return await createDictItem(dictItem);
|
|
} catch (error) {
|
|
console.error("Failed to create dict item:", error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
// 将 updateDictItem 改为 modifyDictItem
|
|
ipcMain.handle("dict-update-item", async (event, dictItem) => {
|
|
try {
|
|
return await modifyDictItem(dictItem.id, dictItem);
|
|
} catch (error) {
|
|
console.error("Failed to update dict item:", error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
// 将 deleteDictItem 改为 removeDictItem
|
|
ipcMain.handle("dict-delete-item", async (event, id) => {
|
|
try {
|
|
return await removeDictItem(id);
|
|
} catch (error) {
|
|
console.error(`Failed to delete dict item ${id}:`, error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
// 将 fetchAllDictItemsWithTypes 改为 fetchDictItemsWithTypes
|
|
ipcMain.handle("dict-fetch-all-items-with-types", async () => {
|
|
try {
|
|
return await fetchDictItemsWithTypes();
|
|
} catch (error) {
|
|
console.error("Failed to fetch all dict items with types:", error);
|
|
throw error;
|
|
}
|
|
});
|
|
// 添加在setupIpcMain函数中
|
|
// 检查parent_code是否存在
|
|
ipcMain.handle("dict-check-parent-code", async (event, parentCode) => {
|
|
try {
|
|
return await checkDictParentCode(parentCode); // 修改这一行
|
|
} catch (error) {
|
|
console.error("检查parent_code失败:", error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
// 检查是否有子引用
|
|
ipcMain.handle("dict-check-child-references", async (event, itemCode) => {
|
|
try {
|
|
return await checkDictChildReferences(itemCode); // 修改这一行
|
|
} catch (error) {
|
|
console.error("检查子引用失败:", error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
// 题干管理相关IPC
|
|
ipcMain.handle("question-create", async (event, questionData) => {
|
|
try {
|
|
return await createQuestion(questionData);
|
|
} catch (error) {
|
|
console.error("Failed to create question:", error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("question-fetch-all", async () => {
|
|
try {
|
|
return await fetchAllQuestions();
|
|
} catch (error) {
|
|
console.error("Failed to fetch questions:", error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("question-fetch-by-id", async (event, id) => {
|
|
try {
|
|
return await fetchQuestionById(id);
|
|
} catch (error) {
|
|
console.error(`Failed to fetch question by id ${id}:`, error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("question-update", async (event, id, questionData) => {
|
|
try {
|
|
return await modifyQuestion(id, questionData);
|
|
} catch (error) {
|
|
console.error("Failed to update question:", error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("question-delete", async (event, id) => {
|
|
try {
|
|
return await removeQuestion(id);
|
|
} catch (error) {
|
|
console.error(`Failed to delete question ${id}:`, error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
// 在已有的 question 相关 IPC 处理程序区域添加
|
|
ipcMain.handle("question-fetch-all-with-relations", async (event) => {
|
|
try {
|
|
return await fetchAllQuestionsWithRelations();
|
|
} catch (error) {
|
|
console.error("Failed to fetch all questions with relations:", error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
// 添加更新题干描述的 IPC 处理程序
|
|
ipcMain.handle(
|
|
"question-update-description",
|
|
async (event, id, questionDescription) => {
|
|
try {
|
|
return await modifyQuestionDescription(id, questionDescription);
|
|
} catch (error) {
|
|
console.error("Failed to update question description:", error);
|
|
throw error;
|
|
}
|
|
}
|
|
);
|
|
|
|
// 添加选择题问题的IPC处理程序
|
|
ipcMain.handle('question-update-choice', async (event, id, choiceData) => {
|
|
try {
|
|
return await modifyChoiceQuestion(id, choiceData);
|
|
} catch (error) {
|
|
console.error('Failed to update choice question:', error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
// 添加选择题问题的IPC处理程序
|
|
ipcMain.handle("question-create-choice", async (event, choiceData) => {
|
|
try {
|
|
return await createChoiceQuestion(choiceData);
|
|
} catch (error) {
|
|
console.error("Failed to create choice question:", error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
// 添加填空题问题的IPC处理程序
|
|
ipcMain.handle('question-create-fill-blank', async (event, fillBlankData) => {
|
|
try {
|
|
return await createFillBlankQuestion(fillBlankData);
|
|
} catch (error) {
|
|
console.error('Failed to create fill blank question:', error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
// 更新填空题问题的IPC处理程序
|
|
ipcMain.handle('question-update-fill-blank', async (event, id, fillBlankData) => {
|
|
try {
|
|
return await modifyFillBlankQuestion(id, fillBlankData);
|
|
} catch (error) {
|
|
console.error('Failed to update fill blank question:', error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
// 删除填空题问题的IPC处理程序
|
|
ipcMain.handle('question-delete-fill-blank', async (event, id) => {
|
|
try {
|
|
return await removeFillBlankQuestion(id);
|
|
} catch (error) {
|
|
console.error(`Failed to delete fill blank question ${id}:`, error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
// 根据题干ID查询填空题问题的IPC处理程序
|
|
ipcMain.handle('question-fetch-fill-blank-by-question-id', async (event, questionId) => {
|
|
try {
|
|
return await fetchFillBlankQuestionsByQuestionId(questionId);
|
|
} catch (error) {
|
|
console.error(`Failed to fetch fill blank questions by question id ${questionId}:`, error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
// 考试管理相关IPC
|
|
ipcMain.handle("exam-create", async (event, examData) => {
|
|
try {
|
|
// 确保exam_notice是序列化的JSON字符串
|
|
if (examData.exam_notice && typeof examData.exam_notice === "object") {
|
|
examData.exam_notice = JSON.stringify(examData.exam_notice);
|
|
}
|
|
return await createNewExam(examData);
|
|
} catch (error) {
|
|
console.error("Failed to create exam:", error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("exam-update", async (event, { id, examData }) => {
|
|
try {
|
|
// 确保exam_notice是序列化的JSON字符串
|
|
if (examData.exam_notice && typeof examData.exam_notice === "object") {
|
|
examData.exam_notice = JSON.stringify(examData.exam_notice);
|
|
}
|
|
return await modifyExam(id, examData);
|
|
} catch (error) {
|
|
console.error("Failed to update exam:", error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("exam-fetch-last", async () => {
|
|
try {
|
|
const exam = await fetchLastExam();
|
|
// 将exam_notice字符串解析为数组
|
|
if (exam && exam.exam_notice) {
|
|
try {
|
|
exam.exam_notice = JSON.parse(exam.exam_notice);
|
|
} catch (e) {
|
|
console.error("解析考试须知失败:", e);
|
|
exam.exam_notice = [];
|
|
}
|
|
}
|
|
return exam;
|
|
} catch (error) {
|
|
console.error("Failed to fetch last exam:", error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("exam-fetch-all", async () => {
|
|
try {
|
|
return { success: true, data: await fetchAllExams() };
|
|
} catch (error) {
|
|
console.error("Failed to fetch all exams:", error);
|
|
return { success: false, error: error.message };
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("exam-fetch-last", async () => {
|
|
try {
|
|
return { success: true, data: await fetchLastExam() };
|
|
} catch (error) {
|
|
console.error("Failed to fetch last exam:", error);
|
|
return { success: false, error: error.message };
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("exam-fetch-by-id", async (event, id) => {
|
|
try {
|
|
return { success: true, data: await fetchExamById(id) };
|
|
} catch (error) {
|
|
console.error(`Failed to fetch exam by id ${id}:`, error);
|
|
return { success: false, error: error.message };
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("exam-update", async (event, { id, examData }) => {
|
|
try {
|
|
const result = await modifyExam(id, examData);
|
|
return { success: result, data: { id, ...examData } };
|
|
} catch (error) {
|
|
console.error(`Failed to update exam ${id}:`, error);
|
|
return { success: false, error: error.message };
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("exam-delete", async (event, id) => {
|
|
try {
|
|
const result = await removeExam(id);
|
|
return { success: result, data: { id } };
|
|
} catch (error) {
|
|
console.error(`Failed to delete exam ${id}:`, error);
|
|
return { success: false, error: error.message };
|
|
}
|
|
});
|
|
|
|
// 考生管理相关IPC
|
|
ipcMain.handle("examinee-create", async (event, examineeData) => {
|
|
try {
|
|
return await createExamineeService(examineeData);
|
|
} catch (error) {
|
|
console.error("Failed to create examinee:", error);
|
|
throw error;
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("examinee-fetch-all", async () => {
|
|
try {
|
|
return await fetchAllExaminees();
|
|
} catch (error) {
|
|
console.error("Failed to fetch all examinees:", error);
|
|
return [];
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("examinee-fetch-by-id", async (event, id) => {
|
|
try {
|
|
return await fetchExamineeById(id);
|
|
} catch (error) {
|
|
console.error("Failed to fetch examinee by id:", error);
|
|
return null;
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("examinee-update", async (event, id, examineeData) => {
|
|
try {
|
|
return await updateExamineeService(id, examineeData);
|
|
} catch (error) {
|
|
console.error("Failed to update examinee:", error);
|
|
return false;
|
|
}
|
|
});
|
|
|
|
ipcMain.handle("examinee-delete", async (event, id) => {
|
|
try {
|
|
return await deleteExamineeService(id);
|
|
} catch (error) {
|
|
console.error("Failed to delete examinee:", error);
|
|
return false;
|
|
}
|
|
});
|
|
|
|
}
|
|
|
|
// 确保在 app.whenReady() 中调用 setupIpcMain()
|
|
app.whenReady().then(() => {
|
|
setupApp();
|
|
createWindow();
|
|
setupIpcMain();
|
|
});
|
|
|
|
// 在应用退出前关闭所有数据库连接
|
|
app.on("will-quit", () => {
|
|
console.log("应用即将退出...");
|
|
// closeAllConnections();
|
|
});
|