后台首页、考试管理页,初始化数据逻辑变更,把当前所有数据都归入到初始化内容中

This commit is contained in:
chenqiang 2025-09-14 16:01:07 +08:00
parent e1685afeaf
commit 3bc310c066
24 changed files with 1283 additions and 728 deletions

View File

@ -180,6 +180,45 @@ async function deleteExaminee(id) {
});
}
/**
* 获取考生总数量
* @returns {Promise<number>} 考生总数量
*/
async function getExamineeCount() {
const db = await getDbConnection(getSystemDbPath());
return executeWithRetry(db, async () => {
const sql = 'SELECT COUNT(*) as count FROM examinee';
const result = await db.getAsync(sql);
return result ? result.count : 0;
});
}
/**
* 获取有效考生数量身份证号为18位的考生
* @returns {Promise<number>} 有效考生数量
*/
async function getValidExamineeCount() {
const db = await getDbConnection(getSystemDbPath());
return executeWithRetry(db, async () => {
const sql = 'SELECT COUNT(*) as count FROM examinee WHERE LENGTH(examinee_id_card) = 18';
const result = await db.getAsync(sql);
return result ? result.count : 0;
});
}
/**
* 获取测试考生数量身份证号不足18位的考生
* @returns {Promise<number>} 测试考生数量
*/
async function getTestExamineeCount() {
const db = await getDbConnection(getSystemDbPath());
return executeWithRetry(db, async () => {
const sql = 'SELECT COUNT(*) as count FROM examinee WHERE LENGTH(examinee_id_card) < 18';
const result = await db.getAsync(sql);
return result ? result.count : 0;
});
}
// 导出使用CommonJS格式
module.exports = {
getAllExaminees,
@ -187,5 +226,8 @@ module.exports = {
getExamineeByIdCardAndAdmissionTicket,
createExaminee,
updateExaminee,
deleteExaminee
deleteExaminee,
getExamineeCount,
getValidExamineeCount,
getTestExamineeCount
};

View File

@ -2,6 +2,15 @@ const { getSystemDbPath, getUserDbPath } = require('./path.js');
const { systemSchema, userSchema, defaultData } = require('./schema.js');
const { openDatabase, batchInsert } = require('./utils.js');
const bcrypt = require('bcryptjs');
const { configDataSql } = require('./systemdata/configData.js');
const { dictItemsDataSql } = require('./systemdata/dictItemsData.js');
const { dictTypesDataSql } = require('./systemdata/dictTypesData.js');
const { examDataSql } = require('./systemdata/examData.js');
const { examineeDataSql } = require('./systemdata/examineeData.js');
const { questionChoicesDataSql } = require('./systemdata/questionChoicesData.js');
const { questionImagesDataSql } = require('./systemdata/questionImagesData.js');
const { questionsDataSql } = require('./systemdata/questionsData.js');
const { questionFillBlanksDataSql } = require('./systemdata/questionFillBlanksData.js');
// 数据库连接池
const dbConnections = new Map();
@ -67,20 +76,20 @@ async function initializeSystemDatabase() {
console.error('创建 config 表失败:', error);
}
// 创建dict_types表
// 创建dict_types表 - 修正为驼峰命名
try {
await systemDb.execAsync(systemSchema.dict_types.trim());
console.log('创建 dict_types 表成功');
await systemDb.execAsync(systemSchema.dictTypes.trim());
console.log('创建 dictTypes 表成功');
} catch (error) {
console.error('创建 dict_types 表失败:', error);
console.error('创建 dictTypes 表失败:', error);
}
// 创建dict_items表
// 创建dict_items表 - 修正为驼峰命名
try {
await systemDb.execAsync(systemSchema.dict_items.trim());
console.log('创建 dict_items 表成功');
await systemDb.execAsync(systemSchema.dictItems.trim());
console.log('创建 dictItems 表成功');
} catch (error) {
console.error('创建 dict_items 表失败:', error);
console.error('创建 dictItems 表失败:', error);
}
// 创建questions表
@ -91,68 +100,68 @@ async function initializeSystemDatabase() {
console.error('创建 questions 表失败:', error);
}
// 创建question_datasets表
// 创建question_datasets表 - 修正为驼峰命名
try {
await systemDb.execAsync(systemSchema.question_datasets.trim());
console.log('创建 question_datasets 表成功');
await systemDb.execAsync(systemSchema.questionDatasets.trim());
console.log('创建 questionDatasets 表成功');
} catch (error) {
console.error('创建 question_datasets 表失败:', error);
console.error('创建 questionDatasets 表失败:', error);
}
// 创建question_images表
// 创建question_images表 - 修正为驼峰命名
try {
await systemDb.execAsync(systemSchema.question_images.trim());
console.log('创建 question_images 表成功');
await systemDb.execAsync(systemSchema.questionImages.trim());
console.log('创建 questionImages 表成功');
} catch (error) {
console.error('创建 question_images 表失败:', error);
console.error('创建 questionImages 表失败:', error);
}
// 创建question_fill_table表
// 创建question_fill_table表 - 修正为驼峰命名
try {
await systemDb.execAsync(systemSchema.question_fill_table.trim());
console.log('创建 question_fill_table 表成功');
await systemDb.execAsync(systemSchema.questionFillTable.trim());
console.log('创建 questionFillTable 表成功');
} catch (error) {
console.error('创建 question_fill_table 表失败:', error);
console.error('创建 questionFillTable 表失败:', error);
}
// 创建question_fill_table_blanks表
// 创建question_fill_table_blanks表 - 修正为驼峰命名
try {
await systemDb.execAsync(systemSchema.question_fill_table_blanks.trim());
console.log('创建 question_fill_table_blanks 表成功');
await systemDb.execAsync(systemSchema.questionFillTableBlanks.trim());
console.log('创建 questionFillTableBlanks 表成功');
} catch (error) {
console.error('创建 question_fill_table_blanks 表失败:', error);
console.error('创建 questionFillTableBlanks 表失败:', error);
}
// 创建question_choices表
// 创建question_choices表 - 修正为驼峰命名
try {
await systemDb.execAsync(systemSchema.question_choices.trim());
console.log('创建 question_choices 表成功');
await systemDb.execAsync(systemSchema.questionChoices.trim());
console.log('创建 questionChoices 表成功');
} catch (error) {
console.error('创建 question_choices 表失败:', error);
console.error('创建 questionChoices 表失败:', error);
}
// 创建question_fill_blanks表
// 创建question_fill_blanks表 - 修正为驼峰命名
try {
await systemDb.execAsync(systemSchema.question_fill_blanks.trim());
console.log('创建 question_fill_blanks 表成功');
await systemDb.execAsync(systemSchema.questionFillBlanks.trim());
console.log('创建 questionFillBlanks 表成功');
} catch (error) {
console.error('创建 question_fill_blanks 表失败:', error);
console.error('创建 questionFillBlanks 表失败:', error);
}
// 创建question_judge表
// 创建question_judge表 - 修正为驼峰命名
try {
await systemDb.execAsync(systemSchema.question_judge.trim());
console.log('创建 question_judge 表成功');
await systemDb.execAsync(systemSchema.questionJudge.trim());
console.log('创建 questionJudge 表成功');
} catch (error) {
console.error('创建 question_judge 表失败:', error);
console.error('创建 questionJudge 表失败:', error);
}
// 创建question_short表
// 创建question_short表 - 修正为驼峰命名
try {
await systemDb.execAsync(systemSchema.question_short.trim());
console.log('创建 question_short 表成功');
await systemDb.execAsync(systemSchema.questionShort.trim());
console.log('创建 questionShort 表成功');
} catch (error) {
console.error('创建 question_short 表失败:', error);
console.error('创建 questionShort 表失败:', error);
}
// 创建exam表
@ -171,60 +180,82 @@ async function initializeSystemDatabase() {
console.error('创建 examinee 表失败:', error);
}
// 插入默认数据
/// TODO: 初始化config表数据
try {
console.log('开始插入默认数据...');
// 插入admin用户
const adminPasswordHash = await bcrypt.hash('123456', 10);
await systemDb.runAsync(
'INSERT INTO examinee (id_card, name, role, password) VALUES (?, ?, ?, ?)',
['admin', '管理员', 'admin', adminPasswordHash]
);
console.log('插入管理员用户成功');
// 插入config表数据
await systemDb.runAsync(
'INSERT OR IGNORE INTO config (key, value, description) VALUES (?, ?, ?)',
['initialized', 'false', '数据库初始化状态']
);
console.log('插入config表数据成功');
// 批量插入dict_types数据
const dictTypes = defaultData.dictTypes;
for (const type of dictTypes) {
await systemDb.runAsync(
'INSERT INTO dict_types (code, name, description, sort_order) VALUES (?, ?, ?, ?)',
[type.code, type.name, type.description, type.sortOrder]
);
}
console.log('插入dict_types表数据成功');
// 批量插入dict_items数据
const dictItems = defaultData.dictItems;
for (const item of dictItems) {
await systemDb.runAsync(
'INSERT INTO dict_items (type_code, code, name, description, sort_order, is_active, parent_code) VALUES (?, ?, ?, ?, ?, ?, ?)',
[
item.typeCode,
item.code,
item.name,
item.description,
item.sortOrder,
item.isActive ? 1 : 0,
item.parentCode
]
);
}
console.log('插入dict_items表数据成功');
console.log('默认数据插入完成');
console.log('开始初始化config表数据...');
await systemDb.runAsync(configDataSql);
console.log('初始化config表数据成功');
} catch (error) {
console.error('插入默认数据失败:', error);
console.error('初始化config表数据失败:', error);
}
// 初始化dict_types表数据
try {
console.log('开始初始化dict_types表数据...');
await systemDb.runAsync(dictTypesDataSql);
console.log('初始化dict_types表数据成功');
} catch (error) {
console.error('初始化dict_types表数据失败:', error);
}
// 初始化dict_items表数据
try {
console.log('开始初始化dict_items表数据...');
await systemDb.runAsync(dictItemsDataSql);
console.log('初始化dict_items表数据成功');
} catch (error) {
console.error('初始化dict_items表数据失败:', error);
}
// 初始化questions表数据
try {
console.log('开始初始化questions表数据...');
await systemDb.runAsync(questionsDataSql);
console.log('初始化questions表数据成功');
} catch (error) {
console.error('初始化questions表数据失败:', error);
}
// 初始化question_fill_blanks表数据
try {
console.log('开始初始化question_fill_blanks表数据...');
await systemDb.runAsync(questionFillBlanksDataSql);
console.log('初始化question_fill_blanks表数据成功');
} catch (error) {
console.error('初始化question_fill_blanks表数据失败:', error);
}
// 初始化question_images表数据
try {
console.log('开始初始化question_images表数据...');
await systemDb.runAsync(questionImagesDataSql);
console.log('初始化question_images表数据成功');
} catch (error) {
console.error('初始化question_images表数据失败:', error);
}
// 初始化question_choices表数据
try {
console.log('开始初始化question_choices表数据...');
await systemDb.runAsync(questionChoicesDataSql);
console.log('初始化question_choices表数据成功');
} catch (error) {
console.error('初始化question_choices表数据失败:', error);
}
// 初始化exam表数据
try {
console.log('开始初始化exam表数据...');
await systemDb.runAsync(examDataSql);
console.log('初始化exam表数据成功');
} catch (error) {
console.error('初始化exam表数据失败:', error);
}
// 初始化examinee表数据
try {
console.log('开始初始化examinee表数据...');
await systemDb.runAsync(examineeDataSql);
console.log('初始化examinee表数据成功');
} catch (error) {
console.error('初始化examinee表数据失败:', error);
}
return { success: true };
}
};
// 初始化用户数据库 - 注意这里使用了exports导出
exports.initializeUserDatabase = async function initializeUserDatabase() {
@ -308,46 +339,6 @@ exports.initializeUserDatabase = async function initializeUserDatabase() {
results.failed.push({ operation: '创建 question_fill_blanks 表', error: error.message });
}
// 创建question_judge表
try {
await userDb.execAsync(userSchema.question_judge.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 userDb.execAsync(userSchema.question_short.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 });
}
// 创建question_fill_table表
try {
await userDb.execAsync(userSchema.question_fill_table.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 userDb.execAsync(userSchema.question_fill_table_blanks.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 });
}
console.log('用户数据库表结构创建完成');
console.log('成功操作:', results.success.length);
console.log('失败操作:', results.failed.length);

View File

@ -417,7 +417,19 @@ async function getQuestionsCountAndScore() {
});
}
// 导出使用CommonJS格式
/**
* 获取题干数量
* @returns {Promise<number>} 题干数量
*/
async function getQuestionCount() {
const db = await getDbConnection(getSystemDbPath());
return executeWithRetry(db, async () => {
const sql = 'SELECT COUNT(*) as count FROM questions';
const result = await db.getAsync(sql);
return result ? result.count : 0;
});
}
module.exports = {
addQuestion,
getAllQuestions,
@ -433,5 +445,6 @@ module.exports = {
updateFillBlankQuestion,
deleteFillBlankQuestion,
getFillBlankQuestionsByQuestionId,
getQuestionsCountAndScore
getQuestionsCountAndScore,
getQuestionCount
};

View File

@ -37,8 +37,7 @@ const systemSchema = {
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)
UNIQUE(type_code, item_code)
);
`,
questions: `
@ -48,8 +47,7 @@ const systemSchema = {
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)
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
);
`,
questionDatasets: `
@ -59,8 +57,7 @@ const systemSchema = {
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)
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
);
`,
questionImages: `
@ -70,8 +67,7 @@ const systemSchema = {
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)
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
);
`,
questionFillTable: `
@ -83,8 +79,7 @@ const systemSchema = {
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)
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
);
`,
questionFillTableBlanks: `
@ -96,9 +91,7 @@ const systemSchema = {
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)
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
);
`,
questionChoices: `
@ -111,8 +104,7 @@ const systemSchema = {
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)
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
);
`,
questionFillBlanks: `
@ -124,8 +116,7 @@ const systemSchema = {
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)
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
);
`,
questionJudge: `
@ -135,8 +126,7 @@ const systemSchema = {
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)
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
);
`,
questionShort: `
@ -146,8 +136,7 @@ const systemSchema = {
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)
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
);
`,
exam: `
@ -255,7 +244,7 @@ userSchema = {
correct_answers TEXT NOT NULL,
examinee_answers TEXT NOT NULL DEFAULT '',
score REAL,
score_real REAL DEFAULT 0, -- 本题得分
score_real REAL DEFAULT 0,
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
);
@ -269,144 +258,17 @@ userSchema = {
correct_answers TEXT NOT NULL DEFAULT '',
examinee_answers TEXT NOT NULL DEFAULT '',
score REAL,
score_real REAL DEFAULT 0, -- 本题得分
score_real REAL DEFAULT 0,
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
);
`
};
// 初始化默认数据
// 系统配置默认数据
const plainPassword = "t2t6a9"; // 明文密码变量定义
// 注意在实际初始化数据库时需要使用bcryptjs对plainPassword进行哈希
// 这里只定义默认数据结构哈希操作应在index.js中的初始化函数中完成
const 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
userSchema
};

View File

@ -0,0 +1,11 @@
const configDataSql = `
INSERT INTO config (id,"key",value,protected) VALUES
(5,'admin_password','$2a$10$1unsGZrsBkQrjo3/GaqCVOyQ3L90ODje8WDhwgytWjHVRndbPBUC2',1),
(6,'question_bank_version','26',1),
(7,'exam_version','1',1),
(8,'initialized','true',1);
`;
module.exports = {
configDataSql
};

View File

@ -0,0 +1,18 @@
const dictItemsDataSql = `
INSERT INTO dict_items (id,type_code,item_code,item_name,item_description,parent_code,is_active,created_at) VALUES
(1,'question_category','objective','客观题','有固定答案,机器可自动评分',NULL,1,'2025-08-07 14:20:34'),
(2,'question_category','subjective','主观题','需人工评分,答案不唯一',NULL,1,'2025-08-07 14:20:34'),
(3,'question_type','choice','选择题','包含单选和多选','objective',1,'2025-08-07 14:20:34'),
(4,'question_type','fill_blank','填空题','填写空白处的答案','objective',1,'2025-08-07 14:20:34'),
(5,'question_type','fill_table','填表题','填写表格内容','objective',0,'2025-08-07 14:20:34'),
(6,'question_type','true_false','判断题','判断对错','objective',0,'2025-08-07 14:20:34'),
(7,'question_type','short_answer','问答题','简短回答问题','subjective',0,'2025-08-07 14:20:34'),
(8,'question_type','analysis','分析题','需要分析问题','subjective',0,'2025-08-07 14:20:34'),
(9,'question_type','essay','论述题','详细论述','subjective',0,'2025-08-07 14:20:34'),
(10,'user_role','admin','管理员','系统管理员',NULL,1,'2025-08-07 14:20:34'),
(11,'user_role','student','考生','参加考试的用户',NULL,1,'2025-08-07 14:20:34');
`;
module.exports = {
dictItemsDataSql
};

View File

@ -0,0 +1,10 @@
const dictTypesDataSql = `
INSERT INTO dict_types (id,type_code,type_name,description,created_at) VALUES
(1,'question_category','题型分类','用于区分客观题和主观题','2025-08-07 14:20:34'),
(2,'question_type','题型','存储所有题型(选择题、填空题等)','2025-08-07 14:20:34'),
(3,'user_role','用户角色','区分不同用户类型','2025-08-07 14:20:34');
`;
module.exports = {
dictTypesDataSql
};

View File

@ -0,0 +1,8 @@
const examDataSql = `
INSERT INTO exam (id,exam_name,exam_description,exam_examinee_type,exam_notice,exam_minutes,exam_minutes_min,created_at,updated_at) VALUES
(1,'','','','["请认真核对姓名、座位号和准考证号等信息是否正确。","请保持安静,独立完成考试,不要交头接耳。","请勿使用任何作弊手段,一经发现将取消考试资格。","考试时间结束后,系统将自动提交试卷。","考试过程中如遇任何问题,请举手示意监考老师。","填空题计算结果保留两位小数。"]',120,30,'2025-08-08 12:15:47','2025-09-14 05:41:01');
`;
module.exports = {
examDataSql
};

View File

@ -0,0 +1,178 @@
const examineeDataSql = `
INSERT INTO examinee (id,examinee_name,examinee_gender,examinee_unit,written_exam_room,written_exam_seat,computer_exam_room,computer_exam_seat,examinee_id_card,examinee_admission_ticket,created_at,updated_at) VALUES
(1,'佟玲','女','抚顺市统计局','一考场','101','一考场','101','210422199112171921','210400001','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(2,'薛艳丽','女','抚顺市统计局','一考场','102','一考场','102','210402198303102427','210400002','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(3,'刘若暄','女','抚顺市统计局','一考场','103','一考场','103','210403200102081822','210400003','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(4,'苏博','男','抚顺市普查中心','一考场','104','一考场','104','210404198810192714','210400004','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(5,'李爽','女','抚顺市统计局','一考场','105','一考场','105','210422198512090624','210400005','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(6,'吴雨擎','女','抚顺市统计局','一考场','106','一考场','106','210421199708063028','210400006','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(7,'马云哲','男','抚顺市普查中心','一考场','107','一考场','107','210423200002180415','210400007','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(8,'沈丹','女','抚顺市统计局','一考场','108','一考场','108','210421198806244223','210400008','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(9,'高琳琳','女','抚顺市统计局','一考场','109','一考场','109','15042619980528002X','210400009','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(10,'张威鹏','男','抚顺市统计局','一考场','110','一考场','110','222401199412101214','210400010','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(11,'戴露','女','抚顺市统计局','一考场','111','一考场','111','210602199507241520','210400011','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(12,'张敬峰','男','抚顺市统计局','一考场','112','一考场','112','210403197704144515','210400012','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(13,'白雪妍','女','抚顺市统计局','一考场','113','一考场','113','210402198102200725','210400013','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(14,'温添尧','女','抚顺市统计局','一考场','114','一考场','114','21042319970712002X','210400014','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(15,'刘宇','女','抚顺市统计局','一考场','115','一考场','115','211202199307022525','210400015','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(16,'贾鲁','男','抚顺市统计局','一考场','201','二考场','201','210402197809242916','210400016','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(17,'肖峰','男','抚顺市统计局','一考场','202','二考场','202','210502198409111212','210400017','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(18,'张天禹','男','抚顺市统计局','一考场','203','二考场','203','210402199612240510','210400018','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(19,'张鹏昊','男','抚顺市统计局','一考场','204','二考场','204','210423198707270015','210400019','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(20,'侯静一','女','抚顺市统计局','一考场','205','二考场','205','210402198603040926','210400020','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(21,'李彬斌','女','抚顺市统计局','一考场','206','二考场','206','230203198706040821','210400021','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(22,'袁芳','女','抚顺市普查中心','一考场','207','二考场','207','210422198801062726','210400022','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(23,'王桐菲','女','抚顺市统计局','一考场','208','二考场','208','210103199501104524','210400023','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(24,'高云鹏','男','抚顺市普查中心','一考场','209','二考场','209','210411199809300413','210400024','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(25,'刘伟婧','女','抚顺市统计局','一考场','210','二考场','210','152201198601021041','210400025','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(26,'郭一琪','女','抚顺市统计局','一考场','211','二考场','211','210411200006042428','210400026','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(27,'王美珠','女','抚顺市统计局','一考场','212','二考场','212','21041119901007382X','210400027','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(28,'田恬','女','抚顺市统计局','一考场','213','二考场','213','220421199803301428','210400028','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(29,'李冠秋','女','东洲区统计局','','','','','210402199608070221','210403001','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(30,'张楚珺','女','东洲区统计局','','','','','210102199808293423','210403002','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(31,'李君杰','女','东洲区统计局','','','','','210411199505123825','210403003','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(32,'张轩赫','男','抚顺市东洲区搭连街道办事处','','','','','210402199507060518','210403101','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(33,'唐家臻','男','抚顺市东洲区兰山乡人民政府','','','','','210283199502070511','210403102','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(34,'王露路','女','东洲区龙凤街道办事处','','','','','210403198510182366','210403103','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(35,'董冬','女','碾盘乡人民政府','','','','','210403198509210921','210403104','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(36,'钟函岐','女','抚顺市东洲区万新街道办事处','','','','','210402199906040928','210403105','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(37,'孙琦','女','抚顺市东洲区新屯街道新和社区居民委员会','','','','','210403198011161827','210403106','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(38,'佟艳红','女','抚顺市东洲区章党街道办事处','','','','','210411197606181822','210403107','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(39,'宋晓文','女','抚顺矿业集团有限责任公司老虎台矿','','','','','210403199706070926','210403901','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(40,'韩婷婷','女','抚顺县统计局','','','','','65400119850922032X','210421001','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(41,'刘光征','男','抚顺县统计局','','','','','210403198411272374','210421002','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(42,'姜大庆','男','抚顺县统计局','','','','','210423197807230032','210421003','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(43,'曲云翀','男','抚顺县统计局','','','','','210402198301303516','210421004','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(44,'郭维','女','抚顺县统计局','','','','','210402198810190249','210421005','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(45,'王茁','男','抚顺县统计局','','','','','210422199904160016','210421006','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(46,'杨爽','女','抚顺县统计局','','','','','210411198612234163','210421007','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(47,'于智广','男','抚顺县住建局','','','','','370911200006064418','210421101','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(48,'李晓牧','男','抚顺县工业和信息化局','','','','','210402198105082939','210421102','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(49,'丁洁','女','抚顺县发展和改革局','','','','','211322199808316266','210421103','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(50,'张妍','女','抚顺县发展和改革局','','','','','210422198509140029','210421104','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(51,'苏展鹏','男','抚顺县人力资源和社会保障局','','','','','210411200103152418','210421105','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(52,'白青卉','女','抚顺县工业和信息化局','','','','','210411199308030427','210421106','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(53,'陈寿花','女','抚顺市博瑞特科技有限公司','','','','','370126198101277121','210421901','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(54,'尹峥玉','女','辽宁三友农业生物科技集团有限公司','','','','','210403199110283322','210421902','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(55,'邱菊','女','辽宁洺远建筑工程有限公司','','','','','210402198810261529','210421903','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(56,'李振','男','抚顺高新区经济发展局','','','','','210403199107122712','210403101','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(57,'李婷玉','女','抚顺高新区经济发展局','','','','','210403199702033028','210403102','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(58,'曹瑾','女','抚顺高新区经济发展局','','','','','210402197912122429','210403103','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(59,'柴宛含','女','抚顺市东方碳素有限公司','','','会计','','210726198911136724','210403901','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(60,'刘嘉垚','女','辽宁昆仑汉兴氢能源科技有限公司','','','会计','','210421198705223028','210403902','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(61,'李晓阳','女','抚顺石化北天化工有限公司','','','统计员','','210404199301202448','210403903','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(62,'董红','女','辽宁同德环保科技有限公司','','','经理','','211222197901275441','210403904','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(63,'张莹','女','抚顺伊科思新材料有限公司','','','中级会计师','','21041119880120182X','210403905','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(64,'牛虹','女','辽宁祥顺气体有限公司','','','合同管理员','','210421199701032421','210403906','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(65,'鹿佳瑶','女','抚顺齐隆化工有限公司','','','统计员','','21040419870828214X','210403907','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(66,'徐 奇','男','清原满族自治县统计局','','','','','210423200005012214','210423001','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(67,'刘小稚','女','清原满族自治县普查中心','','','','','210423199607240040','210423002','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(68,'胡英名','女','清原满族自治县统计局','','','','','210423199912262043','210423003','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(69,'崔东辉','男','清原满族自治县土口子乡人民政府','','','','','210423199604010012','210423101','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(70,'韩 颖','女','清原满族自治县敖家堡乡人民政府','','','','','21062419961001392X','210423102','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(71,'黄新平','女','清原满族自治县南山城镇人民政府','','','','','210423199107150022','210423103','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(72,'李东月','女','清原满族自治县草市镇人民政府','','','','','220521199303160089','210423104','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(73,'曹一萌','女','清原满族自治县农业农村局','','','','','210423200108240025','210423105','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(74,'于新阳','男','清原满族自治县发展改革局','','','','','210113200010050013','210423106','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(75,'周涌沅','男','清原满族自治县住房城乡建设局','','','','','21042320000626005X','210423107','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(76,'何君','女','清原满族自治宏运有机肥有限公司','','','','','210423198209262821','210423901','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(77,'常畅','女','清原满族自治宏运有机肥有限公司','','','','','210423199007150068','210423902','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(78,'崔红佳','女','辽宁实强机械制造有限公司','','','','','210112199609201023','210423903','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(79,'李博辰','女','辽宁实强机械制造有限公司','','','','','210411200205031844','210423904','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(80,'苏珈','女','辽宁省沈抚改革创新示范区管理委员会发展改革局','','','','','211303199603161222','210424001','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(81,'曹维','女','辽宁省沈抚改革创新示范区管理委员会发展改革局','','','','','210104198605200344','210424002','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(82,'马昕宇','女','辽宁省沈抚改革创新示范区管理委员会发展改革局','','','','','220211199405114228','210424003','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(83,'张先亮','男','辽宁省沈抚改革创新示范区管理委员会产业发展和科技创新局','','','','','210423199206062212','210424004','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(84,'华蕾','女','保融盛维(沈阳)科技有限公司','','','','','211321199111194266','210424901','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(85,'姜莎莎','女','保融盛维(沈阳)科技有限公司','','','','','210282198408096626','210424902','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(86,'田秀丽','女','保融盛维(沈阳)科技有限公司','','','','','211223199002020627','210424903','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(87,'姚勇','男','抚顺市顺城区普查中心','','','','','210403198602060331','210411001','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(88,'张英伟','男','抚顺市顺城区普查中心','','','','','21138119891001645X','210411002','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(89,'刘畅','女','抚顺市顺城区普查中心','','','','','210403199602041549','210411003','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(90,'关凯俊','男','抚顺市顺城区普查中心','','','','','210411199504063517','210411004','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(91,'刘书豪','男','抚顺市顺城区普查中心','','','','','210402199902251314','210411005','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(92,'李佳轩','女','抚顺市顺城区商务局','','','','','210411200206233528','210411101','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(93,'王诗佳','女','抚顺市顺城区发展和改革局','','','','','210402199608182223','210411102','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(94,'李敏仪','女','抚顺市顺城区工业和信息化局','','','','','211224199902185140','210411103','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(95,'王思淼','女','抚顺市顺城区抚顺城街道办事处','','','','','21040219970926202X','210411104','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(96,'蒋松妮','女','抚顺市顺城区葛布街道办事处','','','','','210411199505233821','210411105','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(97,'于博洋','女','抚顺市顺城区新华街道办事处','','','','','211224200011187121','210411106','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(98,'徐春红','女','辽宁清原第一缓冲器制造有限公司','','','','','211224198004201028','210411901','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(99,'霍晓雷','男','抚顺市朗日亮化牌匾加工厂','','','','','210403199305120611','210411902','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(100,'胡波','男','抚顺市庆隆土石方有限公司','','','','','210411196909210218','210411903','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(101,'刘晓丹','女','抚顺市兴达汽车贸易有限公司','','','','','210402198905131727','210411904','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(102,'潘恒阳','女','抚顺市顺城区龙盛神盾子金盛宴酒店','','','','','210411199103210029','210411905','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(103,'李生','','','','','','','210403198008073316','210411906','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(104,'周雪','','','','','','','210402198308232028','210411906','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(105,'江岩','女','望花区普查中心','','','','','210404198307131826','210404001','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(106,'李丽','女','望花区普查中心','','','','','210404197706023924','210404002','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(107,'张谨肃','男','望花区普查中心','','','','','210404198109241231','210404003','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(108,'崔丽芬','女','望花区普查中心','','','','','210404198007183325','210404004','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(109,'关昕','女','望花区普查中心','','','','','210422199806230228','210404005','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(110,'秦元玲','女','望花区普查中心','','','','','210404197108091820','210404006','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(111,'王若寒','女','望花区普查中心','','','','','210623200105081461','210404007','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(112,'杨欣悦','女','望花区商务事务服务中心','','','','','210403199710260925','210404101','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(113,'孙笑凡','女','望花区商务事务服务中心','','','','','210623200006260026','210404102','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(114,'王泓晓','女','望花区演武街道办事处','','','','','210404200004161825','210404103','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(115,'宁伯文','男','望花区建设街道办事处','','','','','21040220010308093X','210404104','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(116,'刘慧言','女','望花区光明街道办事处','','','','','210421199512014224','210404105','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(117,'杨丰源','女','望花区工农街道办事处','','','','','21010419930906432X','210404106','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(118,'刘姝廷','女','望花区和平街道办事处','','','','','21021319900712152X','210404107','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(119,'范金垚','女','望花区朴屯街道海城社区','','','','','210404198702202444','210404108','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(120,'林笑竹','女','望花区工业和信息化局','','','','','21040419831119212X','210404109','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(121,'苏博','女','望花区发展和改革局','','','','','210423198808230063','210404110','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(122,'方智文','男','望花区发展和改革局','','','','','210404199504072110','210404111','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(123,'段君豪','男','望花区农业农村局','','','','','210404200009292111','210404112','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(124,'刘健升','男','望花区住房和城乡建设局','','','','','210402198806301719','210404113','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(125,'韩仁凤','女','望花区塔峪镇人民政府','','','','','211321198207020688','210404114','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(126,'乔多','女','抚顺市琥珀纸业有限责任公司','','','','','210283199511116622','210404901','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(127,'关莹','女','抚顺中星置业有限公司','','','','','210404199203031825','210404902','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(128,'王杨','女','抚顺科隆化工实业有限公司','','','','','210403199108120321','210404903','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(129,'董巍','女','抚顺华晟铝标准样品研发有限公司','','','','','210404198107082126','210404904','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(130,'尹晓彤','女','抚顺奥福特酒店管理企业(有限合伙)','','','','','210402199101170928','210404905','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(131,'张鑫','男','新抚区普查中心','','','','','220581199708230977','210402001','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(132,'李欣桐','女','新抚区普查中心','','','','','210403200203315528','210402002','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(133,'于淼','女','抚顺市新抚区统计局','','','','','210104199505194340','210402003','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(134,'郭元成','男','新抚区普查中心','','','','','210402199204221716','210402004','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(135,'于涵羽','女','抚顺市新抚区统计局','','','','','211422199912195623','210402005','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(136,'马凯','男','抚顺市新抚区民政局','','','','','210411198511072417','210402101','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(137,'王保权','男','抚顺市新抚区工业和信息化局','','','','','210404197301280017','210402102','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(138,'苗帅','男','抚顺市新抚区住房和城乡建设局','','','','','220182199110118213','210402103','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(139,'王宇浩','男','抚顺市新抚区发展和改革局','','','','','230229200109304511','210402104','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(140,'杜帛原','男','抚顺市新抚区发展和改革局','','','','','220721199301010811','210402105','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(141,'曹旭阳','男','抚顺市天胜电器经贸有限公司','','','','','210402197112090510','210402901','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(142,'李逍','女','亚朵酒店','','','','','210404200103220624','210402902','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(143,'李喆','男','抚顺石化工程建设有限公司','','','','','210411199711302912','210402903','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(144,'周思宇','女','抚顺城市燃气发展有限公司','','','','','210411199706174127','210402904','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(145,'唐艳阳','女','抚顺中油优艺环保服务有限公司','','','','','210403199705301825','210402905','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(146,'张勇锋','男','抚顺市水利勘测设计研究院有限公司','','','','','210411198907183236','210402906','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(147,'刘彦君','女','中国石油天然气股份有限公司辽宁抚顺销售分公司','','','','','210402198506250948','210402907','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(148,'于东生','男','新宾县统计局','科员','','','','210422199307300017','210422001','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(149,'韩珑','男','新宾县统计局','科员','','','','21042219870612241X','210422002','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(150,'崔若曦','女','新宾县统计局','科员','','','','210422199702200024','210422003','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(151,'李少龙','男','新宾县统计局','科员','','','','210422198802093110','210422004','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(152,'叶兴','女','新宾县统计局','科员','','','','210422198112020029','210422005','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(153,'郭晶','女','新宾县统计局','科员','','','','210422198710032136','210422006','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(154,'郑斯文','女','上夹河镇政府','统计助理','','','','210422200110020025','210422101','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(155,'孟宏扬','女','红庙子乡政府','统计助理','','','','21042219960417212X','210422102','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(156,'王思语','女','新宾镇政府','统计助理','','','','21042219900527292X','210422103','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(157,'英鑫','女','平顶山镇政府','统计助理','','','','210422199310180028','210422104','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(158,'周品一','女','榆树乡政府','统计助理','','','','210422199407180024','210422105','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(159,'陈艳','女','瑞隆工艺品有限公司','会计','','','','210422198502130223','210422901','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(160,'刘艳新','女','民族贸易有限公司','会计','','','','210422197505050224','210422902','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(161,'于长云','女','百货商场有限公司','劳资员','','','','210422197805052125','210422903','2025-08-08 13:03:51','2025-08-08 13:03:51'),
(163,'试考者1','','','','','','','1','1','2025-08-09 07:23:09','2025-08-12 10:28:44'),
(164,'丁敬雯','','','','','','','22052420010825122X','210400030','2025-08-12 03:14:49','2025-08-12 03:14:49'),
(165,'路浚宇','','','','','','','210423200003072029','210400030','2025-08-12 03:15:15','2025-08-12 03:15:15'),
(166,'试考者2','','','','','','','2','2','2025-08-12 10:28:55','2025-08-12 10:28:55'),
(167,'试考者3','','','','','','','3','3','2025-08-12 10:29:04','2025-08-12 10:29:04'),
(168,'试考者4','','','','','','','4','4','2025-08-12 10:29:13','2025-08-12 10:29:13'),
(169,'试考者5','','','','','','','5','5','2025-08-12 10:29:21','2025-08-12 10:29:21'),
(170,'试考者6','','','','','','','6','6','2025-08-12 12:57:00','2025-08-12 12:57:00'),
(171,'试考者7','','','','','','','7','7','2025-08-12 12:57:10','2025-08-12 12:57:10'),
(172,'式考者8','','','','','','','8','8','2025-08-31 03:07:47','2025-09-14 05:41:39');
`;
module.exports = {
examineeDataSql
};

View File

@ -0,0 +1,18 @@
const questionChoicesDataSql = `
INSERT INTO question_choices (id,question_id,choice_description,choice_type,choice_options,correct_answers,score,created_at,updated_at) VALUES
(1,7,'建立产量对单位成本的线性回归方程( )。','single','["y=76.86+0.93x","y=76.86-0.93x","y=76.86+1.64x","y=76.86-1.64x"]','["y=76.86-1.64x"]',6.0,'2025-08-08 21:40:36','2025-08-08 23:06:32'),
(2,7,'如果2026年产量为7千件则单位成本为 )元/件。','single','["65.38","63.34","83.37","70.35"]','["65.38"]',4.0,'2025-08-08 21:50:14','2025-08-08 23:06:38'),
(3,8,'该公司全年销量最大的产品是( )。','single','["甲产品","乙产品","丙产品","丁产品"]','["丙产品"]',5.0,'2025-08-08 21:52:21','2025-08-08 23:06:03'),
(4,8,'对于丁产品,季度销售额占全年销售额比重最大的是( )。','single','["第一季度","第二季度","第三季度","第四季度"]','["第二季度"]',5.0,'2025-08-08 21:53:11','2025-08-08 23:06:12'),
(5,9,'2014年全国棉花单位面积产量比上年 )。','single','["提高了5.1%","提高了0.7%","降低了5.1%","降低了0.7%"]','["提高了0.7%"]',5.0,'2025-08-08 21:54:58','2025-08-08 23:05:40'),
(6,9,'2014年棉花产量最高的省播种面积占全国的比重为 )。','single','["52%","60%","40%","46%"]','["46%"]',5.0,'2025-08-08 21:56:08','2025-08-08 23:05:45'),
(7,10,'2019年煤炭产量比2018年同比增长速度为 )。','single','["8.03%","8.65%","9.14%","10.02%"]','["8.65%"]',5.0,'2025-08-08 21:57:59','2025-08-08 23:05:17'),
(8,10,'2015年-2019煤炭产量年平均增长速度为 )。','single','["8.33%","8.05%","8.86%","9.22%"]','["8.86%"]',5.0,'2025-08-08 21:58:50','2025-08-08 23:05:24'),
(9,11,'税收收入占一般公共预算收入比重最大的是( )。','single','["上海","江苏","浙江","福建"]','["上海"]',3.0,'2025-08-08 22:00:11','2025-08-08 23:04:09'),
(10,11,'一般公共预算收入占GDP比重大于10%的省(市)有( )。','single','["4个","5个","6个","7个"]','["5个"]',3.0,'2025-08-08 22:00:51','2025-08-08 23:04:19'),
(11,11,'江苏、浙江、江西三省的税收收入平均增速是( )。','single','["8.01%","8.15%","9.38%","10.02%"]','["9.38%"]',4.0,'2025-08-08 22:01:41','2025-08-08 23:04:59');
`;
module.exports = {
questionChoicesDataSql
};

View File

@ -0,0 +1,15 @@
const questionFillBlanksDataSql = `
INSERT INTO question_fill_blanks (id,question_id,blank_description,blank_count,correct_answers,score,created_at,updated_at) VALUES
(1,1,'该企业日产量的平均值是( )吨。',1,'["26.36"]',2.0,'2025-08-08 21:28:28','2025-09-05 02:42:16'),
(2,1,'该企业日产量的中位数是( )。',1,'["26.00"]',4.0,'2025-08-08 21:31:39','2025-09-05 02:42:22'),
(3,1,'该企业日产量的标准差是( )。',1,'["1.95"]',4.0,'2025-08-08 21:32:12','2025-08-08 21:32:12'),
(4,2,'该企业7月成品价值为 )千元。',1,'["59.82"]',4.0,'2025-08-08 21:33:40','2025-08-08 21:33:40'),
(5,2,'该企业7月总产值为 )千元。',1,'["77.82"]',6.0,'2025-08-08 21:34:06','2025-08-08 21:34:06'),
(6,3,'某企业本年固定资产投资额为( )万元。',1,'["10000.33"]',10.0,'2025-08-08 21:35:17','2025-08-08 21:35:17'),
(7,4,'该地区地区生产总值与社会消费品零售总额的相关系数是( )。',1,'["0.94"]',10.0,'2025-08-08 21:36:34','2025-08-08 21:36:34'),
(8,6,'在置信水平α=0.05情况下(对应显著水平α=0.05的临界值为-1.64总体均值检验统计量z= ',1,'["-2.97"]',10.0,'2025-08-08 21:38:37','2025-08-08 21:38:37');
`;
module.exports = {
questionFillBlanksDataSql
};

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,17 @@
const questionsDataSql = `
INSERT INTO questions (id,question_type,question_name,question_description,created_at,updated_at) VALUES
(1,'fill_blank','','某企业6月1日至14日产量分别如下','2025-08-08 16:47:23','2025-08-08 16:47:23'),
(2,'fill_blank','','某企业为工业企业7月其自备原材料生产半成品A共50吨其中30吨生产出B产品10吨并对外出售10吨A产品B产品在本企业没有下一步生产工序A产品对外销售不含税单价为2000元/吨B产品对外销售含税单价为4500元/吨税率13.0%另外该企业受委托加工B产品5吨原材料为委托企业提供结算其加工费400元/吨该企业核算6月末A产品成本余额3600千元7月末余额3616千元。','2025-08-08 21:33:10','2025-08-08 21:33:10'),
(3,'fill_blank','','某企业提供当年的科目余额表中借方累计发生额在建工程科目中建筑工程为1150.33万元安装工程为550万元在安装设备为900万元固定资产科目购置设备400万元预付账款9000万元无形资产中土地购置费用5000万元商标权300万元著作权500万元采矿权2000万元。在贷方累计发生额中应付账款2000万元应付职工薪酬500万元应交税费450万元。','2025-08-08 21:34:39','2025-08-08 21:34:39'),
(4,'fill_blank','','某地区2011-2017年地区生产总值x)与社会消费品零售总额y有关资料如下','2025-08-08 21:36:06','2025-08-08 21:36:06'),
(6,'fill_blank','','商场里的白糖一般包装都是400克一袋有一位顾客买了一袋白糖称重发现仅有396克于是他找到相关质量监督部门进行投诉质量监督部门找到相同品牌相同包装的白糖80袋进行称重.计算这80袋白糖的平均重量为398.55克标准差为4.36克。','2025-08-08 21:38:15','2025-08-08 21:38:15'),
(7,'choice','','某企业生产的某种产品产量x单位成本y的数据如下','2025-08-08 21:39:28','2025-08-08 21:39:28'),
(8,'choice','','某公司全年销售甲乙丙丁四种产品,如下图:','2025-08-08 21:51:31','2025-08-08 21:51:31'),
(9,'choice','','2014年全国棉花播种面积421.9万公顷比2013年减少2.9%棉花总产量616.1万吨比2013年减少2.2%。','2025-08-08 21:54:05','2025-08-08 21:54:05'),
(10,'choice','','某企业2015年至2019年煤炭产量分别如下','2025-08-08 21:56:52','2025-08-08 21:56:52'),
(11,'choice','','2016年全国及部分省一般公共预算收入、GDP如下','2025-08-08 21:59:26','2025-08-08 21:59:26');
`;
module.exports = {
questionsDataSql
};

View File

@ -1,6 +1,13 @@
"use strict";
const { app, protocol, BrowserWindow, ipcMain, dialog, shell } = require("electron");
const {
app,
protocol,
BrowserWindow,
ipcMain,
dialog,
shell,
} = require("electron");
const { createProtocol } = require("vue-cli-plugin-electron-builder/lib");
// 替换argon2为bcryptjs
const bcrypt = require("bcryptjs");
@ -33,6 +40,8 @@ const { initExamingIpc } = require("./service/examingService.js");
const { initFileIpc } = require("./service/fileService.js");
// 试卷
const { initPaperIpc } = require("./service/paperService.js");
// 导入 package.json 获取系统信息
const packageInfo = require("../package.json");
// Scheme must be registered before the app is ready
protocol.registerSchemesAsPrivileged([
@ -50,7 +59,7 @@ async function createWindow() {
show: false, // 先隐藏窗口,避免闪烁
webPreferences: {
// 修改使用更可靠的方式获取preload路径避免依赖process.cwd()
preload: path.join(__dirname, 'preload.js'),
preload: path.join(__dirname, "preload.js"),
nodeIntegration: false,
contextIsolation: true,
},
@ -67,10 +76,10 @@ async function createWindow() {
// 移除之前的便携模式检测逻辑,直接打开开发者工具
// 这样在任何模式下都能查看控制台报错信息
try {
console.log('打开开发者工具');
console.log("打开开发者工具");
mainWindow.webContents.openDevTools();
} catch (error) {
console.error('打开开发者工具时出错:', error);
console.error("打开开发者工具时出错:", error);
}
// 添加窗口关闭事件监听
@ -184,7 +193,7 @@ app.on("before-quit", (event) => {
// 在文件顶部添加
const sqlite3 = require("sqlite3").verbose();
// 在app.on('ready')事件中添加
// 在app.on('ready')事件中添加获取package.json的IPC处理程序
app.on("ready", async () => {
// 禁用Vue DevTools扩展
/*
@ -198,6 +207,171 @@ app.on("ready", async () => {
}
*/
// 添加获取package.json的IPC处理程序
ipcMain.handle("get-package-info", async () => {
try {
return {
success: true,
data: packageInfo,
};
} catch (error) {
console.error("获取package.json信息失败:", error);
return {
success: false,
message: "获取package.json信息失败",
data: null,
};
}
});
// 实现hashTest接口替换原来的argon2Test
ipcMain.handle("hashTest", async (event, inputString) => {
try {
// 使用bcrypt.hash方法计算哈希值
const salt = await bcrypt.genSalt(10);
const hash = await bcrypt.hash(inputString, salt);
return hash;
} catch (error) {
console.error("Error in hashTest calculation:", error);
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;
}
});
// 检查user.db是否存在
ipcMain.handle("checkUserDbExists", async () => {
try {
const userDbPath = getUserDbPath();
return fs.existsSync(userDbPath);
} catch (error) {
console.error("检查user.db文件是否存在失败:", error);
return false;
}
});
// 静默初始化用户数据库
ipcMain.handle("initializeUserDatabaseSilently", async () => {
try {
console.log("开始静默初始化用户数据库...");
const result = await initializeUserDatabase();
console.log("静默初始化用户数据库完成:", result);
return { success: true, result };
} catch (error) {
console.error("静默初始化用户数据库失败:", error);
return { success: false, error: error.message };
}
});
// 检测是否为便携模式运行
let isPortableMode = false;
let appDataPath = "";
// 初始化应用路径 - 兼容Node.js 12和Windows 7
function initializeAppPaths() {
// 检查应用根目录是否存在data文件夹如果存在则认为是便携模式
// Windows路径兼容处理
const appRoot = process.cwd();
const portableDataPath = path.join(appRoot, "data");
const defaultDataPath = path.join(app.getPath("userData"), "data");
// 检查是否为便携模式
if (fs.existsSync(portableDataPath)) {
isPortableMode = true;
appDataPath = portableDataPath;
console.log("检测到便携模式使用当前目录的data文件夹:", appDataPath);
} else {
isPortableMode = false;
appDataPath = defaultDataPath;
console.log("使用默认数据目录:", appDataPath);
// 确保默认数据目录存在
if (!fs.existsSync(appDataPath)) {
// 递归创建目录兼容Windows路径
try {
fs.mkdirSync(appDataPath, { recursive: true });
} catch (error) {
console.error("创建默认数据目录失败:", error);
}
}
}
}
// 添加全局函数获取数据目录
global.getAppDataPath = function () {
return appDataPath;
};
global.isPortableMode = function () {
return isPortableMode;
};
// 在应用ready事件前初始化路径
initializeAppPaths();
// 新增添加获取路径信息的IPC处理程序
ipcMain.handle("get-exe-path", (event) => {
try {
const exePath = app.getPath("exe");
console.log("获取exe路径:", exePath);
return exePath;
} catch (error) {
console.error("获取exe路径失败:", error);
return null;
}
});
ipcMain.handle("get-database-paths", (event) => {
try {
const systemDbPath = getSystemDbPath();
const userDbPath = getUserDbPath();
console.log("获取数据库路径:");
console.log("system.db:", systemDbPath);
console.log("user.db:", userDbPath);
return { systemDbPath, userDbPath };
} catch (error) {
console.error("获取数据库路径失败:", error);
return { systemDbPath: "获取失败", userDbPath: "获取失败" };
}
});
// 在现有的IPC处理程序后面添加
ipcMain.handle("file-open-file", async (event, filePath) => {
try {
console.log("尝试打开文件:", filePath);
// 使用shell.openPath打开文件这会使用系统默认应用打开指定文件
const result = await shell.openPath(filePath);
// 在Windows上result是打开的文件路径在macOS和Linux上成功时返回空字符串
if (process.platform === "win32" || result === "") {
console.log("文件打开成功:", filePath);
return { success: true, message: "文件打开成功" };
} else {
console.error("文件打开失败:", result);
return { success: false, message: result };
}
} catch (error) {
console.error("打开文件时发生错误:", error);
return { success: false, message: error.message };
}
});
// 初始化配置相关的IPC处理程序
initConfigIpc(ipcMain);
// 初始化字典相关的IPC处理程序
@ -216,14 +390,14 @@ app.on("ready", async () => {
initPaperIpc(ipcMain);
// 检查数据库是否初始化
try {
const isInitialized = await checkDatabaseInitialized();
if (!isInitialized) {
await initializeDatabase();
}
} catch (error) {
console.error("数据库初始化失败:", error);
}
// try {
// const isInitialized = await checkDatabaseInitialized();
// if (!isInitialized) {
// await initializeDatabase();
// }
// } catch (error) {
// console.error("数据库初始化失败:", error);
// }
createWindow();
});
@ -242,151 +416,3 @@ if (isDevelopment) {
});
}
}
// 实现hashTest接口替换原来的argon2Test
ipcMain.handle("hashTest", async (event, inputString) => {
try {
// 使用bcrypt.hash方法计算哈希值
const salt = await bcrypt.genSalt(10);
const hash = await bcrypt.hash(inputString, salt);
return hash;
} catch (error) {
console.error("Error in hashTest calculation:", error);
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;
}
});
// 检查user.db是否存在
ipcMain.handle("checkUserDbExists", async () => {
try {
const userDbPath = getUserDbPath();
return fs.existsSync(userDbPath);
} catch (error) {
console.error("检查user.db文件是否存在失败:", error);
return false;
}
});
// 静默初始化用户数据库
ipcMain.handle("initializeUserDatabaseSilently", async () => {
try {
console.log("开始静默初始化用户数据库...");
const result = await initializeUserDatabase();
console.log("静默初始化用户数据库完成:", result);
return { success: true, result };
} catch (error) {
console.error("静默初始化用户数据库失败:", error);
return { success: false, error: error.message };
}
});
// 检测是否为便携模式运行
let isPortableMode = false;
let appDataPath = "";
// 初始化应用路径 - 兼容Node.js 12和Windows 7
function initializeAppPaths() {
// 检查应用根目录是否存在data文件夹如果存在则认为是便携模式
// Windows路径兼容处理
const appRoot = process.cwd();
const portableDataPath = path.join(appRoot, "data");
const defaultDataPath = path.join(app.getPath("userData"), "data");
// 检查是否为便携模式
if (fs.existsSync(portableDataPath)) {
isPortableMode = true;
appDataPath = portableDataPath;
console.log("检测到便携模式使用当前目录的data文件夹:", appDataPath);
} else {
isPortableMode = false;
appDataPath = defaultDataPath;
console.log("使用默认数据目录:", appDataPath);
// 确保默认数据目录存在
if (!fs.existsSync(appDataPath)) {
// 递归创建目录兼容Windows路径
try {
fs.mkdirSync(appDataPath, { recursive: true });
} catch (error) {
console.error("创建默认数据目录失败:", error);
}
}
}
}
// 添加全局函数获取数据目录
global.getAppDataPath = function () {
return appDataPath;
};
global.isPortableMode = function () {
return isPortableMode;
};
// 在应用ready事件前初始化路径
initializeAppPaths();
// 新增添加获取路径信息的IPC处理程序
ipcMain.handle("get-exe-path", (event) => {
try {
const exePath = app.getPath('exe');
console.log('获取exe路径:', exePath);
return exePath;
} catch (error) {
console.error('获取exe路径失败:', error);
return null;
}
});
ipcMain.handle("get-database-paths", (event) => {
try {
const systemDbPath = getSystemDbPath();
const userDbPath = getUserDbPath();
console.log('获取数据库路径:');
console.log('system.db:', systemDbPath);
console.log('user.db:', userDbPath);
return { systemDbPath, userDbPath };
} catch (error) {
console.error('获取数据库路径失败:', error);
return { systemDbPath: '获取失败', userDbPath: '获取失败' };
}
});
// 在现有的IPC处理程序后面添加
ipcMain.handle("file-open-file", async (event, filePath) => {
try {
console.log('尝试打开文件:', filePath);
// 使用shell.openPath打开文件这会使用系统默认应用打开指定文件
const result = await shell.openPath(filePath);
// 在Windows上result是打开的文件路径在macOS和Linux上成功时返回空字符串
if (process.platform === 'win32' || result === '') {
console.log('文件打开成功:', filePath);
return { success: true, message: '文件打开成功' };
} else {
console.error('文件打开失败:', result);
return { success: false, message: result };
}
} catch (error) {
console.error('打开文件时发生错误:', error);
return { success: false, message: error.message };
}
});

View File

@ -24,6 +24,8 @@ contextBridge.exposeInMainWorld("electronAPI", {
configFetchById: (id) => ipcRenderer.invoke("config-fetch-by-id", id),
configSave: (key, value) => ipcRenderer.invoke("config-save", { key, value }),
configDelete: (id) => ipcRenderer.invoke("config-delete", id),
// 添加获取package.json的接口
getPackageInfo: () => ipcRenderer.invoke("get-package-info"),
// 字典服务相关接口
dictFetchTypes: () => ipcRenderer.invoke("dict-fetch-types"),
@ -89,6 +91,8 @@ contextBridge.exposeInMainWorld("electronAPI", {
ipcRenderer.invoke("question-get-count-and-score"),
questionGetQuestionById: (questionId) =>
ipcRenderer.invoke("question-get-question-by-id", questionId),
// 新增:获取题干数量接口
questionGetCount: () => ipcRenderer.invoke("question-get-count"),
// 考试服务相关接口
examCreate: (examData) => ipcRenderer.invoke("exam-create", examData),
@ -109,6 +113,11 @@ contextBridge.exposeInMainWorld("electronAPI", {
examineeUpdate: (id, examineeData) =>
ipcRenderer.invoke("examinee-update", { id, examineeData }),
examineeDelete: (id) => ipcRenderer.invoke("examinee-delete", id),
examineeGetCount: () => ipcRenderer.invoke("examinee-get-count"),
// 新增:获取有效考生数量接口
examineeGetValidCount: () => ipcRenderer.invoke("examinee-get-valid-count"),
// 新增:获取测试考生数量接口
examineeGetTestCount: () => ipcRenderer.invoke("examinee-get-test-count"),
// 在"考生考试服务相关接口"部分添加getPaper接口
examingGetPaper: ({ paperId }) =>

View File

@ -1,10 +1,13 @@
const {
getAllExaminees,
getExamineeById,
getExamineeByIdCardAndAdmissionTicket,
createExaminee,
updateExaminee,
deleteExaminee,
getExamineeByIdCardAndAdmissionTicket
getExamineeCount,
getValidExamineeCount,
getTestExamineeCount
} = require('../db/examinee.js');
/**
@ -97,6 +100,19 @@ async function deleteExamineeService(id) {
}
}
/**
* 服务层获取考生总数量
* @returns {Promise<number>} 考生总数量
*/
async function getExamineeCountService() {
try {
return await getExamineeCount();
} catch (error) {
console.error('服务层: 获取考生数量失败', error);
return 0;
}
}
/**
* 服务层考生登录
* @param {string} idCard 身份证号
@ -173,6 +189,63 @@ function initExamineeIpc(ipcMain) {
return null;
}
});
// 添加获取考生数量的IPC处理程序
ipcMain.handle("examinee-get-count", async (event) => {
try {
return await getExamineeCountService();
} catch (error) {
console.error("Failed to get examinee count:", error);
return 0;
}
});
// 在initExamineeIpc函数中添加新的IPC处理程序
ipcMain.handle("examinee-get-valid-count", async () => {
try {
const count = await getValidExamineeCountService();
return count;
} catch (error) {
console.error("获取有效考生数量失败:", error);
throw error;
}
});
ipcMain.handle("examinee-get-test-count", async () => {
try {
const count = await getTestExamineeCountService();
return count;
} catch (error) {
console.error("获取测试考生数量失败:", error);
throw error;
}
});
}
/**
* 服务层获取有效考生数量
* @returns {Promise<number>} 有效考生数量
*/
async function getValidExamineeCountService() {
try {
return await getValidExamineeCount();
} catch (error) {
console.error("服务层: 获取有效考生数量失败", error);
throw error;
}
}
/**
* 服务层获取测试考生数量
* @returns {Promise<number>} 测试考生数量
*/
async function getTestExamineeCountService() {
try {
return await getTestExamineeCount();
} catch (error) {
console.error("服务层: 获取测试考生数量失败", error);
throw error;
}
}
// 导出使用CommonJS格式
@ -182,6 +255,9 @@ module.exports = {
createExamineeService,
updateExamineeService,
deleteExamineeService,
getExamineeCountService,
getValidExamineeCountService,
getTestExamineeCountService,
fetchExamineeByIdCardAndAdmissionTicketService,
initExamineeIpc
};

View File

@ -13,13 +13,12 @@ const {
updateFillBlankQuestion,
deleteFillBlankQuestion,
getFillBlankQuestionsByQuestionId,
getQuestionsCountAndScore
} = require('../db/question.js');
getQuestionsCountAndScore,
getQuestionCount,
} = require("../db/question.js");
// 导入configService中的increaseQuestionBankVersion方法
const {
increaseQuestionBankVersion
} = require('./configService.js');
const { increaseQuestionBankVersion } = require("./configService.js");
/**
* 服务层添加题干
@ -33,7 +32,7 @@ async function createQuestion(questionData) {
await increaseQuestionBankVersion();
return result;
} catch (error) {
console.error('服务层: 添加题干失败', error);
console.error("服务层: 添加题干失败", error);
throw error;
}
}
@ -46,7 +45,7 @@ async function fetchAllQuestions() {
try {
return await getAllQuestions();
} catch (error) {
console.error('服务层: 获取所有题干失败', error);
console.error("服务层: 获取所有题干失败", error);
throw error;
}
}
@ -59,7 +58,7 @@ async function fetchAllQuestionsWithRelations() {
try {
return await getAllQuestionsWithRelations();
} catch (error) {
console.error('服务层: 获取所有题干及其关联信息失败', error);
console.error("服务层: 获取所有题干及其关联信息失败", error);
throw error;
}
}
@ -73,7 +72,7 @@ async function fetchQuestionById(id) {
try {
return await getQuestionById(id);
} catch (error) {
console.error('服务层: 根据ID获取题干失败', error);
console.error("服务层: 根据ID获取题干失败", error);
throw error;
}
}
@ -91,7 +90,7 @@ async function modifyQuestion(id, questionData) {
await increaseQuestionBankVersion();
return result;
} catch (error) {
console.error('服务层: 更新题干失败', error);
console.error("服务层: 更新题干失败", error);
throw error;
}
}
@ -109,7 +108,7 @@ async function modifyQuestionDescription(id, questionDescription) {
await increaseQuestionBankVersion();
return result;
} catch (error) {
console.error('服务层: 更新题干描述失败', error);
console.error("服务层: 更新题干描述失败", error);
throw error;
}
}
@ -126,7 +125,7 @@ async function removeQuestion(id) {
await increaseQuestionBankVersion();
return result;
} catch (error) {
console.error('服务层: 删除题干失败', error);
console.error("服务层: 删除题干失败", error);
throw error;
}
}
@ -143,7 +142,7 @@ async function createChoiceQuestion(choiceData) {
await increaseQuestionBankVersion();
return result;
} catch (error) {
console.error('服务层: 添加选择题失败', error);
console.error("服务层: 添加选择题失败", error);
throw error;
}
}
@ -161,7 +160,7 @@ async function modifyChoiceQuestion(id, choiceData) {
await increaseQuestionBankVersion();
return result;
} catch (error) {
console.error('服务层: 更新选择题失败', error);
console.error("服务层: 更新选择题失败", error);
throw error;
}
}
@ -178,7 +177,7 @@ async function removeChoiceQuestion(id) {
await increaseQuestionBankVersion();
return result;
} catch (error) {
console.error('服务层: 删除选择题失败', error);
console.error("服务层: 删除选择题失败", error);
throw error;
}
}
@ -195,7 +194,7 @@ async function createFillBlankQuestion(fillBlankData) {
await increaseQuestionBankVersion();
return result;
} catch (error) {
console.error('服务层: 添加填空题失败', error);
console.error("服务层: 添加填空题失败", error);
throw error;
}
}
@ -213,7 +212,7 @@ async function modifyFillBlankQuestion(id, fillBlankData) {
await increaseQuestionBankVersion();
return result;
} catch (error) {
console.error('服务层: 更新填空题失败', error);
console.error("服务层: 更新填空题失败", error);
throw error;
}
}
@ -230,7 +229,7 @@ async function removeFillBlankQuestion(id) {
await increaseQuestionBankVersion();
return result;
} catch (error) {
console.error('服务层: 删除填空题失败', error);
console.error("服务层: 删除填空题失败", error);
throw error;
}
}
@ -244,7 +243,7 @@ async function fetchFillBlankQuestionsByQuestionId(questionId) {
try {
return await getFillBlankQuestionsByQuestionId(questionId);
} catch (error) {
console.error('服务层: 根据题干ID查询填空题失败', error);
console.error("服务层: 根据题干ID查询填空题失败", error);
throw error;
}
}
@ -257,7 +256,20 @@ async function fetchQuestionsCountAndScore() {
try {
return await getQuestionsCountAndScore();
} catch (error) {
console.error('服务层: 查询试题总数和总分失败', error);
console.error("服务层: 查询试题总数和总分失败", error);
throw error;
}
}
/**
* 服务层获取题干数量
* @returns {Promise<number>} 题干数量
*/
async function getQuestionCountService() {
try {
return await getQuestionCount();
} catch (error) {
console.error("服务层: 获取题干数量失败", error);
throw error;
}
}
@ -267,7 +279,7 @@ async function fetchQuestionsCountAndScore() {
* @param {Electron.IpcMain} ipcMain - IPC主进程实例
*/
function initQuestionIpc(ipcMain) {
// 题干管理相关IPC
// 题干管理相关IPC
ipcMain.handle("question-create", async (event, questionData) => {
try {
return await createQuestion(questionData);
@ -324,7 +336,9 @@ function initQuestionIpc(ipcMain) {
});
// 添加更新题干描述的 IPC 处理程序
ipcMain.handle("question-update-description", async (event, id, questionDescription) => {
ipcMain.handle(
"question-update-description",
async (event, id, questionDescription) => {
try {
return await modifyQuestionDescription(id, questionDescription);
} catch (error) {
@ -335,11 +349,11 @@ function initQuestionIpc(ipcMain) {
);
// 添加选择题问题的IPC处理程序
ipcMain.handle('question-update-choice', async (event, id, choiceData) => {
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);
console.error("Failed to update choice question:", error);
throw error;
}
});
@ -355,27 +369,30 @@ function initQuestionIpc(ipcMain) {
});
// 添加填空题问题的IPC处理程序
ipcMain.handle('question-create-fill-blank', async (event, fillBlankData) => {
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);
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;
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) => {
ipcMain.handle("question-delete-fill-blank", async (event, id) => {
try {
return await removeFillBlankQuestion(id);
} catch (error) {
@ -385,7 +402,7 @@ function initQuestionIpc(ipcMain) {
});
// 添加删除选择题问题的IPC处理程序
ipcMain.handle('question-delete-choice', async (event, id) => {
ipcMain.handle("question-delete-choice", async (event, id) => {
try {
return await removeChoiceQuestion(id);
} catch (error) {
@ -395,21 +412,38 @@ function initQuestionIpc(ipcMain) {
});
// 根据题干ID查询填空题问题的IPC处理程序
ipcMain.handle('question-fetch-fill-blank-by-question-id', async (event, questionId) => {
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("question-get-count-and-score", async () => {
try {
return await fetchFillBlankQuestionsByQuestionId(questionId);
return await fetchQuestionsCountAndScore();
} catch (error) {
console.error(`Failed to fetch fill blank questions by question id ${questionId}:`, error);
console.error("Failed to fetch questions count and score:", error);
throw error;
}
});
// 注册查询试题总数和总分的IPC处理程序
ipcMain.handle('question-get-count-and-score', async () => {
// 在initQuestionIpc函数中添加新的IPC处理程序
ipcMain.handle("question-get-count", async () => {
try {
return await fetchQuestionsCountAndScore();
const count = await getQuestionCountService();
return count;
} catch (error) {
console.error('Failed to fetch questions count and score:', error);
console.error("获取题干数量失败:", error);
throw error;
}
});
@ -432,5 +466,6 @@ module.exports = {
removeFillBlankQuestion,
fetchFillBlankQuestionsByQuestionId,
fetchQuestionsCountAndScore,
initQuestionIpc
};
initQuestionIpc,
getQuestionCountService,
};

View File

@ -162,14 +162,14 @@ export default {
}
//
try {
// API
console.log('尝试获取数据库路径信息...');
//
await window.electronAPI.checkDatabaseInitialized();
} catch (error) {
console.error('触发数据库检查失败:', error);
}
// try {
// // API
// console.log('...');
// //
// await window.electronAPI.checkDatabaseInitialized();
// } catch (error) {
// console.error(':', error);
// }
// system.dbuser.db
if (window.electronAPI.getDatabasePaths) {

View File

@ -2,48 +2,172 @@
<div class="dashboard-container">
<!-- 页面标题 -->
<div class="mb-4">
<h1 class="text-primary">系统管理首页</h1>
<p class="text-muted">欢迎管理员登录系统后台管理界面</p>
<h3>系统管理首页</h3>
</div>
<!-- 数据概览卡片 -->
<div class="row mb-4">
<div class="col-md-3">
<div class="card bg-primary text-white">
<div class="card-body">
<h5 class="card-title">总考生数</h5>
<p class="card-text text-4xl">{{ examineeCount }}</p>
<a href="#" class="text-white">查看详情</a>
<!-- 数据概览卡片 - 使用 Element UI 卡片 -->
<div class="mb-4">
<!-- 系统信息卡片 -->
<el-card class="mb-4">
<div slot="header" class="clearfix">
<span class="card-title">系统信息</span>
</div>
<div class="row">
<div class="col-md-6 text-center">
<span>系统版本</span>
<p class="stat-number text-info">{{ systemVersion }}</p>
</div>
<div class="col-md-6 text-center">
<span>题库版本</span>
<p class="stat-number text-info">{{ questionBankVersion }}</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-success text-white">
<div class="card-body">
<h5 class="card-title">总题目数</h5>
<p class="card-text text-4xl">{{ questionCount }}</p>
<a href="#" class="text-white">查看详情</a>
</el-card>
<!-- 试题统计卡片 -->
<el-card class="mb-4">
<div slot="header" class="clearfix">
<span class="card-title">试题统计</span>
<router-link to="/admin/question" class="btn-link">查看详情</router-link>
</div>
<!-- 总计行 -->
<div class="row">
<div class="col-md-12 text-left font-weight-bold mb-2">总计</div>
</div>
<div class="row">
<div class="col-md-4 text-center">
<span>题干数量</span>
<p class="stat-number text-success">{{ questionCount }}</p>
</div>
<div class="col-md-4 text-center">
<span>试题数量</span>
<p class="stat-number text-success">{{ totalQuestionsCount }}</p>
</div>
<div class="col-md-4 text-center">
<span>试题总分</span>
<p class="stat-number text-success">
{{ totalQuestionsScore }}
<span class="stat-unit"></span>
</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-warning text-white">
<div class="card-body">
<h5 class="card-title">总考试数</h5>
<p class="card-text text-4xl">{{ examCount }}</p>
<a href="#" class="text-white">查看详情</a>
<!-- 使用Element UI分割线 -->
<el-divider></el-divider>
<!-- 选择题统计行 -->
<div class="row">
<div class="col-md-12 text-left font-weight-bold mb-2">选择题</div>
</div>
<div class="row">
<div class="col-md-4 text-center">
<span>选择题题干</span>
<p class="stat-number text-success">{{ choiceQuestionStemCount || 0 }}</p>
</div>
<div class="col-md-4 text-center">
<span>选择题数量</span>
<p class="stat-number text-success">{{ choiceQuestionCount || 0 }}</p>
</div>
<div class="col-md-4 text-center">
<span>选择题总分</span>
<p class="stat-number text-success">
{{ choiceQuestionScore || 0 }}
<span class="stat-unit"></span>
</p>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-info text-white">
<div class="card-body">
<h5 class="card-title">已完成考试</h5>
<p class="card-text text-4xl">{{ completedExamCount }}</p>
<a href="#" class="text-white">查看详情</a>
<!-- 使用Element UI分割线 -->
<el-divider></el-divider>
<!-- 填空题统计行 -->
<div class="row">
<div class="col-md-12 text-left font-weight-bold mb-2">填空题</div>
</div>
<div class="row">
<div class="col-md-4 text-center">
<span>填空题题干</span>
<p class="stat-number text-success">{{ fillQuestionStemCount || 0 }}</p>
</div>
<div class="col-md-4 text-center">
<span>填空题数量</span>
<p class="stat-number text-success">{{ fillQuestionCount || 0 }}</p>
</div>
<div class="col-md-4 text-center">
<span>填空题总分</span>
<p class="stat-number text-success">
{{ fillQuestionScore || 0 }}
<span class="stat-unit"></span>
</p>
</div>
</div>
</div>
</el-card>
<!-- 考生统计卡片 -->
<el-card class="mb-4">
<div slot="header" class="clearfix">
<span class="card-title">考生统计</span>
<router-link to="/admin/examinee" class="btn-link">查看详情</router-link>
</div>
<div class="row">
<div class="col-md-4 text-center">
<span>考生总数</span>
<p class="stat-number text-primary">{{ examineeCount }}</p>
</div>
<div class="col-md-4 text-center">
<span>有效考生</span>
<p class="stat-number text-primary">{{ validExamineeCount }}</p>
</div>
<div class="col-md-4 text-center">
<span>测试考生</span>
<p class="stat-number text-primary">{{ testExamineeCount }}</p>
</div>
</div>
</el-card>
<!-- 考试信息卡片 -->
<el-card class="mb-4">
<div slot="header" class="clearfix">
<span class="card-title">考试信息</span>
<router-link to="/admin/exam" class="btn-link">查看详情</router-link>
</div>
<div class="row">
<div class="col-md-6 text-center">
<span>考试总时长</span>
<p class="stat-number text-warning">
{{ examTotalMinutes }}
<span class="stat-unit">分钟</span>
</p>
</div>
<div class="col-md-6 text-center">
<span>允许交卷时长</span>
<p class="stat-number text-warning">
{{ examMinMinutes }}
<span class="stat-unit">分钟</span>
</p>
</div>
</div>
</el-card>
<!-- 试卷统计卡片 -->
<el-card class="mb-4">
<div slot="header" class="clearfix">
<span class="card-title">试卷统计</span>
<router-link to="/admin/userPaper" class="btn-link">查看详情</router-link>
</div>
<div class="row">
<div class="col-md-6 text-center">
<span>试卷数量</span>
<p class="stat-number text-info">{{ totalPaperCount }}</p>
</div>
<div class="col-md-6 text-center">
<span>已完成数量</span>
<p class="stat-number text-info">{{ completedPaperCount }}</p>
</div>
</div>
</el-card>
</div>
</div>
</template>
@ -54,35 +178,37 @@ export default {
components: {
ElButton: require('element-ui').Button,
ElTable: require('element-ui').Table,
ElTableColumn: require('element-ui').TableColumn
ElTableColumn: require('element-ui').TableColumn,
ElCard: require('element-ui').Card,
ElDivider: require('element-ui').Divider
},
data() {
return {
//
systemVersion: '',
questionBankVersion: '',
//
examineeCount: 0,
validExamineeCount: 0,
testExamineeCount: 0,
//
questionCount: 0,
examCount: 0,
completedExamCount: 0,
recentActivities: [
//
{
time: '2025-08-28 09:30',
user: 'admin',
action: '登录',
details: '管理员成功登录系统'
},
{
time: '2025-08-27 16:45',
user: 'system',
action: '更新',
details: '系统题库已更新至最新版本'
},
{
time: '2025-08-27 14:20',
user: 'admin',
action: '添加',
details: '添加了10名新考生'
}
]
totalQuestionsCount: 0,
totalQuestionsScore: 0,
//
choiceQuestionStemCount: 0,
choiceQuestionCount: 0,
choiceQuestionScore: 0,
//
fillQuestionStemCount: 0,
fillQuestionCount: 0,
fillQuestionScore: 0,
//
examTotalMinutes: 0,
examMinMinutes: 0,
//
totalPaperCount: 0,
completedPaperCount: 0
}
},
mounted() {
@ -91,18 +217,130 @@ export default {
methods: {
async fetchDashboardData() {
try {
//
// 使
console.log('获取仪表盘数据...')
// API
await new Promise(resolve => setTimeout(resolve, 500))
//
this.examineeCount = 120
this.questionCount = 500
this.examCount = 5
this.completedExamCount = 3
//
try {
// 使getPackageInfo
try {
const packageInfo = await window.electronAPI.getPackageInfo();
this.systemVersion = packageInfo?.data?.version || '未知版本';
} catch (apiError) {
console.error('通过API获取系统版本失败:', apiError);
this.systemVersion = '未知版本';
}
// - 使systemGetConfig()
try {
// electronAPI
const configs = await window.electronAPI.systemGetConfig();
// console.warn(':', configs); //
// question_bank_version
this.questionBankVersion = configs?.question_bank_version || '1.0.0';
} catch (dbError) {
console.error('获取题库版本失败:', dbError);
this.questionBankVersion = '1.0.0'; //
}
console.log('获取系统信息数据成功:', {
systemVersion: this.systemVersion,
questionBankVersion: this.questionBankVersion
})
} catch (systemError) {
console.error('获取系统信息数据失败:', systemError)
this.systemVersion = '未知版本'
this.questionBankVersion = '1.0.0'
}
// 1.
try {
this.examineeCount = await window.electronAPI.examineeGetCount() || 0
this.validExamineeCount = await window.electronAPI.examineeGetValidCount() || 0
this.testExamineeCount = await window.electronAPI.examineeGetTestCount() || 0
console.log('获取考生统计数据成功:', {
examineeCount: this.examineeCount,
validExamineeCount: this.validExamineeCount,
testExamineeCount: this.testExamineeCount
})
} catch (examineeError) {
console.error('获取考生统计数据失败:', examineeError)
this.examineeCount = 0
this.validExamineeCount = 0
this.testExamineeCount = 0
}
// 2.
try {
this.questionCount = await window.electronAPI.questionGetCount() || 0
const questionStats = await window.electronAPI.questionGetStatistics()
this.totalQuestionsCount = questionStats?.totalQuestions || 0
this.totalQuestionsScore = questionStats?.totalScore || 0
//
this.choiceQuestionStemCount = 5 //
this.choiceQuestionCount = 10 //
this.choiceQuestionScore = 50 //
this.fillQuestionStemCount = 5 //
this.fillQuestionCount = 9 //
this.fillQuestionScore = 50 //
console.log('获取试题统计数据成功:', {
questionCount: this.questionCount,
totalQuestionsCount: this.totalQuestionsCount,
totalQuestionsScore: this.totalQuestionsScore,
choiceQuestionStemCount: this.choiceQuestionStemCount,
choiceQuestionCount: this.choiceQuestionCount,
choiceQuestionScore: this.choiceQuestionScore,
fillQuestionStemCount: this.fillQuestionStemCount,
fillQuestionCount: this.fillQuestionCount,
fillQuestionScore: this.fillQuestionScore
})
} catch (questionError) {
console.error('获取试题统计数据失败:', questionError)
this.questionCount = 0
this.totalQuestionsCount = 0
this.totalQuestionsScore = 0
this.choiceQuestionStemCount = 0
this.choiceQuestionCount = 0
this.choiceQuestionScore = 0
this.fillQuestionStemCount = 0
this.fillQuestionCount = 0
this.fillQuestionScore = 0
}
// 3.
try {
const lastExam = await window.electronAPI.examFetchLast()
this.examTotalMinutes = lastExam?.exam_minutes || 0
this.examMinMinutes = lastExam?.exam_minutes_min || 0
console.log('获取考试信息数据成功:', {
examTotalMinutes: this.examTotalMinutes,
examMinMinutes: this.examMinMinutes
})
} catch (examError) {
console.error('获取考试信息数据失败:', examError)
this.examTotalMinutes = 0
this.examMinMinutes = 0
}
// 4.
try {
const allPapers = await window.electronAPI.paperGetAll()
this.totalPaperCount = allPapers?.data?.length || 0
const completedPapers = await window.electronAPI.paperGetByStatus(2) // 2
this.completedPaperCount = completedPapers?.data?.length || 0
console.log('获取试卷统计数据成功:', {
totalPaperCount: this.totalPaperCount,
completedPaperCount: this.completedPaperCount
})
} catch (paperError) {
console.error('获取试卷统计数据失败:', paperError)
this.totalPaperCount = 0
this.completedPaperCount = 0
}
} catch (error) {
console.error('获取仪表盘数据失败:', error)
this.$message.error('获取数据失败,请稍后重试')
@ -114,37 +352,25 @@ export default {
<style scoped>
.dashboard-container {
height: 100%;
padding: 20px;
}
.card {
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
margin-bottom: 20px;
}
.card-body {
padding: 15px;
}
.card-title {
margin-bottom: 10px;
font-weight: 600;
font-weight: bold;
font-size: 1.25rem;
}
.text-4xl {
font-size: 2.5rem;
font-weight: 700;
.btn-link {
float: right;
text-decoration: none;
}
/* 适配移动设备 */
@media (max-width: 768px) {
.row > div {
margin-bottom: 15px;
}
.text-4xl {
font-size: 2rem;
}
.stat-number {
font-size: 1.75rem;
font-weight: bold;
margin: 10px 0;
}
.stat-unit {
color: #000;
font-size: 1rem;
font-weight: normal;
margin-left: 4px;
}
</style>

View File

@ -1,55 +1,65 @@
<template>
<div class="exam-management-container">
<div class="exam-header">
<h1>考试管理</h1>
<!-- <el-button type="primary" @click="handleAddExam">+ 添加考试</el-button> -->
<h3>考试管理</h3>
</div>
<div class="exam-content">
<el-table :data="examList" style="width: 100%" v-loading="loading">
<el-table-column prop="id" label="ID" width="80" />
<el-table-column prop="exam_minutes" label="考试时长(分钟)" width="180" />
<el-table-column prop="exam_minutes_min" label="最短考试时长(分钟)" width="180" />
<el-table-column label="考试须知" min-width="200">
<template slot-scope="scope">
<div class="exam-notice-cell" v-if="scope.row.exam_notice">
<div v-if="Array.isArray(scope.row.exam_notice)" class="notice-list">
<div v-for="(item, index) in scope.row.exam_notice" :key="index" class="notice-item">
<div class="exam-card" v-if="currentExam" v-loading="loading">
<div class="card-item">
<span class="card-label">考试时长(分钟)</span>
<span class="card-value">{{ currentExam.exam_minutes }}</span>
</div>
<div class="card-item">
<span class="card-label">最短考试时长(分钟)</span>
<span class="card-value">{{ currentExam.exam_minutes_min }}</span>
</div>
<div class="card-item" v-if="currentExam.exam_name">
<span class="card-label">考试名称</span>
<span class="card-value">{{ currentExam.exam_name }}</span>
</div>
<div class="card-item" v-if="currentExam.exam_description">
<span class="card-label">考试描述</span>
<span class="card-value">{{ currentExam.exam_description }}</span>
</div>
<div class="card-item" v-if="currentExam.exam_notice">
<span class="card-label">考试须知</span>
<div class="card-value">
<div v-if="Array.isArray(currentExam.exam_notice)" class="notice-list">
<div v-for="(item, index) in currentExam.exam_notice" :key="index" class="notice-item">
{{ item }}
</div>
</div>
<div v-else-if="typeof currentExam.exam_notice === 'string'">
<!-- 尝试将字符串按换行符分割显示 -->
<div v-if="currentExam.exam_notice.includes('\n')" class="notice-list">
<div v-for="(item, index) in currentExam.exam_notice.split('\n')" :key="index" class="notice-item">
{{ item }}
</div>
</div>
<div v-else-if="typeof scope.row.exam_notice === 'string'">
<!-- 尝试将字符串按换行符分割显示 -->
<div v-if="scope.row.exam_notice.includes('\n')" class="notice-list">
<div v-for="(item, index) in scope.row.exam_notice.split('\n')" :key="index" class="notice-item">
{{ item }}
</div>
</div>
<!-- 普通字符串直接显示 -->
<div v-else :title="scope.row.exam_notice" class="ellipsis-cell">
{{ scope.row.exam_notice }}
</div>
<!-- 普通字符串直接显示 -->
<div v-else class="notice-item">
{{ currentExam.exam_notice }}
</div>
</div>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column prop="created_at" label="创建时间" width="180" />
<el-table-column prop="updated_at" label="更新时间" width="180" />
<el-table-column label="操作" width="180" fixed="right">
<template slot-scope="scope">
<el-button type="primary" size="small" @click="handleEditExam(scope.row)">
编辑
</el-button>
<!-- <el-button
type="danger"
size="small"
@click="handleDeleteExam(scope.row.id)"
>
删除
</el-button> -->
</template>
</el-table-column>
</el-table>
</div>
</div>
<div class="card-item" v-if="currentExam.created_at">
<span class="card-label">创建时间</span>
<span class="card-value">{{ formatDate(currentExam.created_at) }}</span>
</div>
<div class="card-item" v-if="currentExam.updated_at">
<span class="card-label">更新时间</span>
<span class="card-value">{{ formatDate(currentExam.updated_at) }}</span>
</div>
<div class="card-action">
<el-button type="primary" @click="handleEditExam(currentExam)">
编辑
</el-button>
</div>
</div>
<div v-else-if="!loading" class="empty-state">
暂无考试数据
</div>
</div>
<!-- 添加/编辑考试弹窗 -->
@ -86,7 +96,7 @@ export default {
name: 'ExamManagementView',
data () {
return {
examList: [],
currentExam: null, //
loading: false,
dialogVisible: false,
dialogTitle: '添加考试',
@ -107,34 +117,30 @@ export default {
},
methods: {
//
// fetchExams
async fetchExams () {
this.loading = true
try {
const result = await window.electronAPI.examFetchAll()
//
if (Array.isArray(result)) {
// result
//
const formattedExams = result.map(exam => ({
...exam
// created_at: this.formatDate(exam.created_at),
// updated_at: this.formatDate(exam.updated_at)
}))
this.examList = formattedExams
if (Array.isArray(result) && result.length > 0) {
//
const exam = { ...result[0] }
this.currentExam = exam
} else if (result && !result.success) {
// resultsuccess: falseerror
this.$message.error('获取考试列表失败: ' + result.error)
console.error('获取考试列表失败', result.error)
this.currentExam = null
} else {
//
this.$message.error('获取考试列表失败: 返回格式异常')
console.error('获取考试列表失败,返回格式异常', result)
//
console.log('暂无考试数据')
this.currentExam = null
}
} catch (error) {
this.$message.error('获取考试列表失败: ' + error.message)
console.error('获取考试列表失败', error)
this.currentExam = null
} finally {
this.loading = false
}
@ -160,7 +166,7 @@ export default {
this.$message.success('考试添加成功')
}
this.dialogVisible = false
this.fetchExams() //
this.fetchExams() //
} catch (error) {
this.$message.error('保存考试失败: ' + error.message)
console.error('保存考试失败', error)
@ -180,9 +186,9 @@ export default {
)
.then(async () => {
try {
await window.electronAPI.examDelete(id)
await window.electronAPI.deleteExam(id)
this.$message.success('考试删除成功')
this.fetchExams() //
this.fetchExams() //
} catch (error) {
this.$message.error('删除考试失败: ' + error.message)
console.error('删除考试失败', error)
@ -192,12 +198,6 @@ export default {
//
})
},
//
formatDate (dateString) {
if (!dateString) return ''
const date = new Date(dateString)
return date.toLocaleString()
},
//
handleAddExam () {
@ -253,59 +253,11 @@ export default {
this.dialogVisible = true
},
//
async handleSaveExam () {
try {
//
const examData = { ...this.formData }
//
if (examData.exam_notice) {
const noticeArray = examData.exam_notice.split('\n').filter(item => item.trim() !== '')
examData.exam_notice = JSON.stringify(noticeArray)
}
if (this.isEdit) {
// APIexamUpdate
await window.electronAPI.examUpdate(examData.id, examData)
this.$message.success('考试更新成功')
} else {
// APIexamCreate
await window.electronAPI.examCreate(examData)
this.$message.success('考试添加成功')
}
this.dialogVisible = false
this.fetchExams() //
} catch (error) {
this.$message.error('保存考试失败: ' + error.message)
console.error('保存考试失败', error)
}
},
//
handleDeleteExam (id) {
this.$confirm(
'确定要删除该考试吗?',
'确认删除',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
)
.then(async () => {
try {
await window.electronAPI.deleteExam(id)
this.$message.success('考试删除成功')
this.fetchExams() //
} catch (error) {
this.$message.error('删除考试失败: ' + error.message)
console.error('删除考试失败', error)
}
})
.catch(() => {
//
})
//
formatDate (dateString) {
if (!dateString) return ''
const date = new Date(dateString)
return date.toLocaleString()
}
}
}
@ -331,13 +283,44 @@ export default {
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
/* 考试须知样式 */
.exam-notice-cell {
padding: 5px 0;
.exam-card {
padding: 20px;
background-color: #f8f9fa;
border-radius: 8px;
border: 1px solid #e9ecef;
}
.card-item {
display: flex;
padding: 10px 0;
border-bottom: 1px solid #e9ecef;
}
.card-item:last-child:not(.card-action) {
border-bottom: none;
}
.card-label {
font-weight: bold;
color: #495057;
min-width: 150px;
}
.card-value {
color: #333;
flex: 1;
}
.card-action {
margin-top: 20px;
text-align: center;
padding-top: 20px;
border-top: 2px solid #e9ecef;
}
/* 考试须知样式 */
.notice-list {
max-height: 100px;
max-height: 200px;
overflow-y: auto;
}
@ -347,9 +330,9 @@ export default {
word-break: break-all;
}
.ellipsis-cell {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
.empty-state {
text-align: center;
padding: 40px;
color: #999;
}
</style>

View File

@ -1,7 +1,7 @@
<template>
<div class="examinee-management-container">
<div class="examinee-header">
<h1>考生管理</h1>
<h3>考生管理</h3>
<el-button type="primary" @click="handleAddExaminee">+ 添加考生</el-button>
</div>
<div class="examinee-content">

View File

@ -18,7 +18,6 @@
<el-tag :type="getTypeColor(question.question_type_name)" class="question-type-tag">
{{ question.question_type_name }}
</el-tag>
<strong>ID: {{ question.id }}</strong>
<strong>{{ question.question_description }}</strong>
</p>
</div>

View File

@ -1,6 +1,6 @@
<template>
<div class="user-paper-management">
<h2>试卷管理</h2>
<h3>试卷管理</h3>
<el-card>
<div slot="header" class="clearfix">

View File

@ -3,12 +3,12 @@
欢迎使用统计技能考试系统!
一、系统概述
本系统是一款专为统计技能考试设计的桌面应用程序,支持选择题和填空题等多种题型,提供考试管理、考生管理、试题管理等功能。
本系统是一款专为抚顺市统计局定制的统计技能考试设计的桌面应用程序,支持选择题和填空题等多种题型,提供考试管理、考生管理、试题管理等功能。
二、系统要求
- 操作系统Windows 7或更高版本
- 内存要求至少4GB RAM
- 硬盘空间:至少100MB可用空间
- 硬盘空间:至少700MB可用空间
- 显示器分辨率1024x768或更高
三、安装说明
@ -16,31 +16,35 @@
1. 解压下载的安装包
2. 双击"统计技能考试系统.exe"运行程序
四、使用方法
1. **管理员登录**:系统启动后,使用管理员账号登录
四、管理后台使用方法
1. **管理员登录**:系统启动后,使用管理员密码登录管理密码t2t6a9
2. **试题管理**:在"试题管理"模块添加、编辑和删除试题
3. **考试管理**:在"考试管理"模块创建和管理考试
4. **考生管理**:在"考生管理"模块添加和管理考生信息
5. **用户试卷**:在"用户试卷"模块查看和导出考生的答题情况
五、注意事项
五、考生考试使用方法
1. **考生登录**:系统启动后,使用考生身份证号和准考证号进入考试系统
2. **开始考试**:考生登录成功后可以“开始考试”
3. **交卷预览**:当考试时间超过最小考试时间后,可能通过“交卷预览”查看整张试卷,并在确认后交卷
4. **意外退出**:如果在未完成考试之前程序意外退出了,可以重新打开软件进入考试后继续之前未完成的考试
5. **重新考试**:无论意外退出还是已完成交卷,考生都可以重新登录并选择重新考试
六、注意事项
1. 确保以管理员身份运行程序,以获得完整功能
2. 请勿删除或修改程序目录下的文件,以免影响系统正常运行
3. 重要数据会保存在程序目录下的data文件夹中请定期备份
4. 如需卸载,直接删除整个文件夹即可
六、常见问题
、常见问题
Q: 程序无法启动怎么办?
A: 请确认您的电脑满足系统要求,并尝试以管理员身份运行
Q: 数据保存在哪里?
A: 数据保存在程序目录下的data文件夹中
、联系方式
、联系方式
如有任何问题或建议,请联系技术支持:
电话XXX-XXXXXXX
邮箱support@example.com
邮箱272023290@qq.com
版本信息:
版本号0.1.0
发布日期2025年9月