整理main.js把ipc注册方法分别写到各个service中,StudentHomeView改名为ExamineeHomeView

This commit is contained in:
chenqiang 2025-08-09 16:17:24 +08:00
parent 637906b241
commit 31b8f81aa3
12 changed files with 593 additions and 604 deletions

View File

@ -8,7 +8,7 @@ import * as argon2 from "argon2";
const dbConnections = new Map();
// 获取数据库连接
async function getDbConnection(dbPath) {
export async function getDbConnection(dbPath) {
if (dbConnections.has(dbPath)) {
console.log(`使用现有数据库连接: ${dbPath}`);
return dbConnections.get(dbPath);
@ -33,7 +33,7 @@ function closeAllConnections() {
}
// 检查数据库是否已初始化
async function checkDatabaseInitialized() {
export async function checkDatabaseInitialized() {
try {
console.log('开始检查数据库初始化状态...');
const systemDb = await getDbConnection(getSystemDbPath());
@ -198,7 +198,7 @@ async function initializeUserDatabase() {
}
// 初始化数据库
async function initializeDatabase() {
export async function initializeDatabase() {
try {
console.log('开始初始化数据库...');
@ -252,10 +252,3 @@ async function initializeDatabase() {
// 应用退出时关闭所有连接
process.on('exit', closeAllConnections);
// 替换module.exports为export
export {
initializeDatabase,
checkDatabaseInitialized,
getDbConnection,
};

View File

@ -2,66 +2,29 @@
import { app, BrowserWindow, ipcMain } from "electron";
import path from "path";
import { fileURLToPath } from "url";
import { checkDatabaseInitialized, initializeDatabase } from "./db/index.js";
import {
checkDatabaseInitialized,
initializeDatabase,
} from "./db/index.js";
// 导入配置项服务
import {
fetchAllConfigs,
fetchConfigById,
saveConfig,
removeConfig,
getSystemConfig,
updateSystemConfig,
increaseQuestionBankVersion,
initAuthIpc,
initConfigIpc,
} from "./service/configService.js";
// 导入字典服务 - 使用实际导出的函数名称
import {
fetchDictTypes,
fetchDictItemsByTypeCode,
createDictType,
modifyDictType,
removeDictType,
createDictItem,
modifyDictItem,
removeDictItem,
fetchDictItemsWithTypes,
checkDictParentCode, // 添加这一行
checkDictChildReferences, // 添加这一行
initDictIpc,
} from "./service/dictService.js";
// 导入题干服务
import {
createQuestion,
fetchAllQuestions,
fetchQuestionById,
modifyQuestion,
removeQuestion,
fetchAllQuestionsWithRelations,
modifyQuestionDescription,
createChoiceQuestion,
modifyChoiceQuestion,
createFillBlankQuestion,
modifyFillBlankQuestion,
removeFillBlankQuestion,
fetchFillBlankQuestionsByQuestionId
initQuestionIpc,
} from './service/questionService.js';
import {
createNewExam,
fetchAllExams,
fetchExamById,
modifyExam,
removeExam,
fetchLastExam, // 添加这一行
initExamIpc,
} from "./service/examService.js";
// 添加考生服务导入
// 在文件开头的导入语句中添加新函数
import {
fetchAllExaminees,
fetchExamineeById,
createExamineeService,
updateExamineeService,
deleteExamineeService,
fetchExamineeByIdCardAndAdmissionTicket,
initExamineeIpc
} from "./service/examineeService.js";
// 定义 __dirname 和 __filename
@ -160,23 +123,7 @@ async function setupApp() {
}
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 {
@ -196,454 +143,20 @@ function setupIpcMain() {
}
});
// 系统相关
ipcMain.handle("system-get-config", async () => {
try {
return await getSystemConfig();
} catch (error) {
console.error("Failed to get system config:", error);
return null;
}
});
// 初始化config相关IPC
initConfigIpc(ipcMain);
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;
}
});
// 初始化dict相关IPC
initDictIpc(ipcMain);
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;
}
});
// 初始化exam相关IPC
initExamIpc(ipcMain);
// 初始化认证相关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;
}
});
// 初始化question相关IPC
initQuestionIpc(ipcMain);
// 初始化考生相关IPC
initExamineeIpc(ipcMain);
}
// 确保在 app.whenReady() 中调用 setupIpcMain()
@ -656,5 +169,4 @@ app.whenReady().then(() => {
// 在应用退出前关闭所有数据库连接
app.on("will-quit", () => {
console.log("应用即将退出...");
// closeAllConnections();
});

View File

@ -55,11 +55,12 @@ contextBridge.exposeInMainWorld('electronAPI', {
fetchExamById: (id) => ipcRenderer.invoke('exam-fetch-by-id', id),
updateExam: (id, examData) => ipcRenderer.invoke('exam-update', { id, examData }),
deleteExam: (id) => ipcRenderer.invoke('exam-delete', id),
fetchLastExam: () => ipcRenderer.invoke('exam-fetch-last'), // 添加这一行
fetchLastExam: () => ipcRenderer.invoke('exam-fetch-last'),
// 考生管理相关API
fetchAllExaminees: () => ipcRenderer.invoke('examinee-fetch-all'),
fetchExamineeById: (id) => ipcRenderer.invoke('examinee-fetch-by-id', id),
createExaminee: (examineeData) => ipcRenderer.invoke('examinee-create', examineeData),
updateExaminee: (id, examineeData) => ipcRenderer.invoke('examinee-update', id, examineeData),
updateExaminee: (id, examineeData) => ipcRenderer.invoke('examinee-update', { id, examineeData }),
deleteExaminee: (id) => ipcRenderer.invoke('examinee-delete', id),
userLogin: (idCard, admissionTicket) => ipcRenderer.invoke('user-login', { idCard, admissionTicket })
});

View File

@ -1,6 +1,12 @@
// 导入数据库操作方法
import { getConfig, setConfig, getAllConfigs, getConfigById, deleteConfig } from '../db/config.js';
import argon2 from 'argon2';
import {
getConfig,
setConfig,
getAllConfigs,
getConfigById,
deleteConfig,
} from "../db/config.js";
import argon2 from "argon2";
// 原有接口保持不变
/**
@ -12,7 +18,7 @@ export async function fetchConfig(key) {
try {
return await getConfig(key);
} catch (error) {
console.error('服务层: 获取配置项失败', error);
console.error("服务层: 获取配置项失败", error);
throw error;
}
}
@ -25,7 +31,7 @@ export async function fetchAllConfigs() {
try {
return await getAllConfigs();
} catch (error) {
console.error('服务层: 获取所有配置项失败', error);
console.error("服务层: 获取所有配置项失败", error);
throw error;
}
}
@ -39,7 +45,7 @@ export async function fetchConfigById(id) {
try {
return await getConfigById(id);
} catch (error) {
console.error('服务层: 通过ID获取配置项失败', error);
console.error("服务层: 通过ID获取配置项失败", error);
throw error;
}
}
@ -54,7 +60,7 @@ export async function saveConfig(key, value) {
try {
await setConfig(key, value);
} catch (error) {
console.error('服务层: 保存配置项失败', error);
console.error("服务层: 保存配置项失败", error);
throw error;
}
}
@ -68,12 +74,11 @@ export async function removeConfig(id) {
try {
await deleteConfig(id);
} catch (error) {
console.error('服务层: 删除配置项失败', error);
console.error("服务层: 删除配置项失败", error);
throw error;
}
}
// 从 system.js 整合的接口
/**
* 获取系统配置并转为Map
* @returns {Promise<{[key: string]: string}>}
@ -82,12 +87,12 @@ export async function getSystemConfig() {
try {
const configs = await getAllConfigs();
const configMap = {};
configs.forEach(config => {
configs.forEach((config) => {
configMap[config.key] = config.value;
});
return configMap;
} catch (error) {
console.error('获取系统配置失败:', error);
console.error("获取系统配置失败:", error);
throw error;
}
}
@ -104,7 +109,7 @@ export async function updateSystemConfig(config) {
}
return true;
} catch (error) {
console.error('更新系统配置失败:', error);
console.error("更新系统配置失败:", error);
throw error;
}
}
@ -115,17 +120,16 @@ export async function updateSystemConfig(config) {
*/
export async function increaseQuestionBankVersion() {
try {
const currentVersion = await getConfig('question_bank_version');
const currentVersion = await getConfig("question_bank_version");
const newVersion = currentVersion ? parseInt(currentVersion.value) + 1 : 1;
await setConfig('question_bank_version', newVersion.toString());
await setConfig("question_bank_version", newVersion.toString());
return true;
} catch (error) {
console.error('增加题库版本号失败:', error);
console.error("增加题库版本号失败:", error);
throw error;
}
}
// 从 auth.service.js 整合的接口
/**
* 管理员登录验证
* @param {string} password - 用户输入的密码
@ -133,30 +137,102 @@ export async function increaseQuestionBankVersion() {
*/
export async function verifyAdminPassword(password) {
try {
const config = await getConfig('admin_password');
const config = await getConfig("admin_password");
if (!config || !config.value) {
return { success: false, message: '管理员密码未设置' };
return { success: false, message: "管理员密码未设置" };
}
const isMatch = await argon2.verify(config.value, password);
if (isMatch) {
return { success: true, message: '登录成功' };
return { success: true, message: "登录成功" };
} else {
return { success: false, message: '密码错误' };
return { success: false, message: "密码错误" };
}
} catch (error) {
console.error('验证管理员密码失败:', error);
return { success: false, message: '验证过程发生错误' };
console.error("验证管理员密码失败:", error);
return { success: false, message: "验证过程发生错误" };
}
}
/**
* 初始化认证相关的IPC处理程序
* 初始化配置相关的IPC处理程序
* @param {import('electron').IpcMain} ipcMain - IPC主进程实例
*/
export function initAuthIpc(ipcMain) {
export function initConfigIpc(ipcMain) {
// 管理员登录验证
ipcMain.handle('admin-login', async (event, credentials) => {
ipcMain.handle("admin-login", async (event, credentials) => {
try {
return await verifyAdminPassword(credentials.password);
} catch (error) {
console.error("Failed to verify admin password:", error);
return { success: false, message: "验证过程发生错误" };
}
});
// 系统相关
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
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;
}
});
}

View File

@ -12,8 +12,8 @@ import {
deleteDictType,
deleteDictItem,
checkParentCodeExists, // 添加这一行
hasChildReferences // 添加这一行
} from '../db/dict.js';
hasChildReferences, // 添加这一行
} from "../db/dict.js";
/**
* 服务层查询字典项及其类型
@ -23,7 +23,7 @@ export async function fetchDictItemsWithTypes() {
try {
return await getDictItemsWithTypes();
} catch (error) {
console.error('服务层: 查询字典项及其类型失败', error);
console.error("服务层: 查询字典项及其类型失败", error);
throw error;
}
}
@ -36,7 +36,7 @@ export async function fetchDictTypes() {
try {
return await getDictTypes();
} catch (error) {
console.error('服务层: 查询字典类型列表失败', error);
console.error("服务层: 查询字典类型列表失败", error);
throw error;
}
}
@ -50,7 +50,7 @@ export async function createDictType(typeData) {
try {
return await addDictType(typeData);
} catch (error) {
console.error('服务层: 添加字典类型失败', error);
console.error("服务层: 添加字典类型失败", error);
throw error;
}
}
@ -64,7 +64,7 @@ export async function createDictItem(itemData) {
try {
return await addDictItem(itemData);
} catch (error) {
console.error('服务层: 添加字典项失败', error);
console.error("服务层: 添加字典项失败", error);
throw error;
}
}
@ -78,7 +78,7 @@ export async function fetchDictTypeById(id) {
try {
return await getDictTypeById(id);
} catch (error) {
console.error('服务层: 根据ID查询字典类型失败', error);
console.error("服务层: 根据ID查询字典类型失败", error);
throw error;
}
}
@ -92,7 +92,7 @@ export async function fetchDictItemById(id) {
try {
return await getDictItemById(id);
} catch (error) {
console.error('服务层: 根据ID查询字典项失败', error);
console.error("服务层: 根据ID查询字典项失败", error);
throw error;
}
}
@ -107,7 +107,7 @@ export async function fetchDictItemsByTypeCode(typeCode, isActive = undefined) {
try {
return await getDictItemsByTypeCode(typeCode, isActive);
} catch (error) {
console.error('服务层: 根据类型编码查询字典项失败', error);
console.error("服务层: 根据类型编码查询字典项失败", error);
throw error;
}
}
@ -122,7 +122,7 @@ export async function modifyDictType(id, typeData) {
try {
return await updateDictType(id, typeData);
} catch (error) {
console.error('服务层: 更新字典类型失败', error);
console.error("服务层: 更新字典类型失败", error);
throw error;
}
}
@ -137,7 +137,7 @@ export async function modifyDictItem(id, itemData) {
try {
return await updateDictItem(id, itemData);
} catch (error) {
console.error('服务层: 更新字典项失败', error);
console.error("服务层: 更新字典项失败", error);
throw error;
}
}
@ -151,7 +151,7 @@ export async function removeDictType(id) {
try {
return await deleteDictType(id);
} catch (error) {
console.error('服务层: 删除字典类型失败', error);
console.error("服务层: 删除字典类型失败", error);
throw error;
}
}
@ -165,7 +165,7 @@ export async function removeDictItem(id) {
try {
return await deleteDictItem(id);
} catch (error) {
console.error('服务层: 删除字典项失败', error);
console.error("服务层: 删除字典项失败", error);
throw error;
}
}
@ -180,7 +180,7 @@ export async function checkDictParentCode(parentCode) {
try {
return await checkParentCodeExists(parentCode);
} catch (error) {
console.error('服务层: 检查父级编码失败', error);
console.error("服务层: 检查父级编码失败", error);
throw error;
}
}
@ -194,7 +194,119 @@ export async function checkDictChildReferences(itemCode) {
try {
return await hasChildReferences(itemCode);
} catch (error) {
console.error('服务层: 检查子引用失败', error);
console.error("服务层: 检查子引用失败", error);
throw error;
}
}
export async function initDictIpc(ipcMain) {
// 字典管理相关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;
}
});
}

View File

@ -4,8 +4,8 @@ import {
getExamById,
updateExam,
deleteExam,
getLastExam // 添加这一行
} from '../db/exam.js';
getLastExam, // 添加这一行
} from "../db/exam.js";
/**
* 服务层创建考试
@ -16,22 +16,22 @@ export async function createNewExam(examData) {
try {
// 数据验证 - 修改为exam_minutes和exam_minutes_min必填
if (!examData.exam_minutes || !examData.exam_minutes_min) {
throw new Error('考试时长和最少考试时间为必填项');
throw new Error("考试时长和最少考试时间为必填项");
}
// 移除默认值设置,因为现在是必填项
if (typeof examData.exam_minutes_min !== 'number') {
throw new Error('最少考试时间必须是数字');
if (typeof examData.exam_minutes_min !== "number") {
throw new Error("最少考试时间必须是数字");
}
// 确保最少考试时间不大于考试时长
if (examData.exam_minutes_min > examData.exam_minutes) {
throw new Error('最少考试时间不能大于考试时长');
throw new Error("最少考试时间不能大于考试时长");
}
return await createExam(examData);
} catch (error) {
console.error('服务层: 创建考试失败', error);
console.error("服务层: 创建考试失败", error);
throw error;
}
}
@ -44,7 +44,7 @@ export async function fetchAllExams() {
try {
return await getAllExams();
} catch (error) {
console.error('服务层: 查询所有考试失败', error);
console.error("服务层: 查询所有考试失败", error);
throw error;
}
}
@ -57,17 +57,17 @@ export async function fetchAllExams() {
export async function fetchExamById(id) {
try {
if (!id) {
throw new Error('考试ID不能为空');
throw new Error("考试ID不能为空");
}
const exam = await getExamById(id);
if (!exam) {
throw new Error('未找到指定考试');
throw new Error("未找到指定考试");
}
return exam;
} catch (error) {
console.error('服务层: 根据ID查询考试失败', error);
console.error("服务层: 根据ID查询考试失败", error);
throw error;
}
}
@ -81,33 +81,33 @@ export async function fetchExamById(id) {
export async function modifyExam(id, examData) {
try {
if (!id) {
throw new Error('考试ID不能为空');
throw new Error("考试ID不能为空");
}
// 验证考试是否存在
const existingExam = await getExamById(id);
if (!existingExam) {
throw new Error('未找到指定考试');
throw new Error("未找到指定考试");
}
// 数据验证 - 修改为exam_minutes和exam_minutes_min必填
if (!examData.exam_minutes || !examData.exam_minutes_min) {
throw new Error('考试时长和最少考试时间为必填项');
throw new Error("考试时长和最少考试时间为必填项");
}
// 移除默认值设置,因为现在是必填项
if (typeof examData.exam_minutes_min !== 'number') {
throw new Error('最少考试时间必须是数字');
if (typeof examData.exam_minutes_min !== "number") {
throw new Error("最少考试时间必须是数字");
}
// 确保最少考试时间不大于考试时长
if (examData.exam_minutes_min > examData.exam_minutes) {
throw new Error('最少考试时间不能大于考试时长');
throw new Error("最少考试时间不能大于考试时长");
}
return await updateExam(id, examData);
} catch (error) {
console.error('服务层: 更新考试失败', error);
console.error("服务层: 更新考试失败", error);
throw error;
}
}
@ -120,18 +120,18 @@ export async function modifyExam(id, examData) {
export async function removeExam(id) {
try {
if (!id) {
throw new Error('考试ID不能为空');
throw new Error("考试ID不能为空");
}
// 验证考试是否存在
const existingExam = await getExamById(id);
if (!existingExam) {
throw new Error('未找到指定考试');
throw new Error("未找到指定考试");
}
return await deleteExam(id);
} catch (error) {
console.error('服务层: 删除考试失败', error);
console.error("服务层: 删除考试失败", error);
throw error;
}
}
@ -144,7 +144,102 @@ export async function fetchLastExam() {
try {
return await getLastExam();
} catch (error) {
console.error('服务层: 查询ID最大的考试失败', error);
console.error("服务层: 查询ID最大的考试失败", error);
throw error;
}
}
export async function initExamIpc(ipcMain) {
// 考试管理相关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 };
}
});
}

View File

@ -12,7 +12,7 @@ import {
* 服务层获取所有考生列表
* @returns {Promise<Array>} 考生列表
*/
export async function fetchAllExaminees() {
export async function fetchAllExamineesService() {
try {
return await getAllExaminees();
} catch (error) {
@ -27,7 +27,7 @@ export async function fetchAllExaminees() {
* @param {number} id 考生ID
* @returns {Promise<Object|null>} 考生数据
*/
export async function fetchExamineeById(id) {
export async function fetchExamineeByIdService(id) {
try {
return await getExamineeById(id);
} catch (error) {
@ -62,6 +62,8 @@ export async function createExamineeService(examineeData) {
* @returns {Promise<boolean>} 是否更新成功
*/
export async function updateExamineeService(id, examineeData) {
console.log(id);
console.log(examineeData);
try {
if (!id) {
throw new Error('考生ID不能为空');
@ -105,7 +107,7 @@ export async function deleteExamineeService(id) {
* @param {string} admissionTicket 准考证号
* @returns {Promise<Object|null>} 考生数据或null
*/
export async function fetchExamineeByIdCardAndAdmissionTicket(idCard, admissionTicket) {
export async function fetchExamineeByIdCardAndAdmissionTicketService(idCard, admissionTicket) {
try {
if (!idCard || !admissionTicket) {
throw new Error('身份证号和准考证号不能为空');
@ -116,3 +118,54 @@ export async function fetchExamineeByIdCardAndAdmissionTicket(idCard, admissionT
throw error;
}
}
export async function initExamineeIpc(ipcMain) {
ipcMain.handle("examinee-fetch-all", async () => {
try {
return await fetchAllExamineesService();
} catch (error) {
console.error("Failed to fetch all examinees:", error);
return [];
}
});
ipcMain.handle("user-login", async (event, {idCard, admissionTicket}) => {
try {
return await fetchExamineeByIdCardAndAdmissionTicketService(idCard, admissionTicket);
} catch (error) {
console.error("Failed to login examinee:", error);
return null;
}
});
ipcMain.handle("examinee-fetch-by-id", async (event, id) => {
try {
return await fetchExamineeByIdService(id);
} catch (error) {
console.error("Failed to fetch examinee by id:", error);
return null;
}
});
ipcMain.handle("examinee-create", async (event, examineeData) => {
try {
return await createExamineeService(examineeData);
} catch (error) {
console.error("Failed to create examinee:", 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 null;
}
});
ipcMain.handle("examinee-delete", async (event, id) => {
try {
return await deleteExamineeService(id);
} catch (error) {
console.error("Failed to delete examinee:", error);
return null;
}
});
}

View File

@ -229,3 +229,136 @@ export async function fetchFillBlankQuestionsByQuestionId(questionId) {
throw error;
}
}
/**
* 初始化question相关IPC
* @param {*} ipcMain
*/
export async function initQuestionIpc(ipcMain) {
// 题干管理相关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;
}
});
}

View File

@ -1,6 +1,6 @@
import { createRouter, createWebHistory } from 'vue-router'
import WelcomeView from '@/views/WelcomeView.vue'
import StudentHomeView from '@/views/user/StudentHomeView.vue'
import ExamineeHomeView from '@/views/user/ExamineeHomeView.vue'
import AdminHomeView from '@/views/admin/AdminHomeView.vue'
// 导入QuestionManagementView
import QuestionManagementView from '@/views/admin/QuestionManagementView.vue'
@ -22,9 +22,9 @@ const router = createRouter({
component: WelcomeView,
},
{
path: '/student/home',
name: 'student-home',
component: StudentHomeView,
path: '/examinee/home',
name: 'examinee-home',
component: ExamineeHomeView,
},
// admin/AdminHomeView路由
{

View File

@ -196,18 +196,19 @@ const handleExamineeLogin = async () => {
try {
// API
const result = await window.electronAPI.userLogin(idCard, admissionTicket);
console.log(result);
if (result.success) {
console.log('考生登录 - 成功', result.data);
if (result && result.id) {
console.log('考生登录 - 成功', result);
// store -
userStore.setExaminee({
...result.data
...result
});
ElMessage.success('登录成功');
//
router.push('/student/home');
router.push('/examinee/home');
} else {
console.warn('考生登录 - 失败:', result.error);
console.warn('考生登录 - 失败:', result);
ElMessage.error(result.error || '登录失败,请检查身份证号和准考证号');
}
} catch (error) {

View File

@ -152,6 +152,7 @@ const handleSaveExaminee = async () => {
const examineeData = {...formData.value};
if (isEdit.value) {
console.log(examineeData);
await window.electronAPI.updateExaminee(examineeData.id, examineeData)
ElMessage.success('考生更新成功')
} else {

View File

@ -53,7 +53,7 @@
<h2 class="text-2xl font-bold text-primary">考试信息</h2>
</div>
<div class="space-y-4">
<el-descriptions class="margin-top" :column="3" :size="size" border>
<el-descriptions class="margin-top" :column="2" :size="size" border>
<el-descriptions-item>
<template #label>
<div class="cell-item">
@ -65,13 +65,24 @@
</template>
{{ formatExamDuration(lastExam?.exam_minutes) }}
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="cell-item">
<el-icon :style="iconStyle">
<Timer />
</el-icon>
最短考试时长
</div>
</template>
{{ formatExamDuration(lastExam?.exam_minutes_min) }}
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<div class="cell-item">
<el-icon :style="iconStyle">
<ScaleToOriginal />
</el-icon>
考试总分
题数量
</div>
</template>
<span class="text-gray-500">待设置</span>
@ -80,13 +91,14 @@
<template #label>
<div class="cell-item">
<el-icon :style="iconStyle">
<Timer />
<ScaleToOriginal />
</el-icon>
最短考试时长
考试总分
</div>
</template>
{{ formatExamDuration(lastExam?.exam_minutes_min) }}
<span class="text-gray-500">待设置</span>
</el-descriptions-item>
</el-descriptions>
</div>
<el-divider />