完成了考试全流程,包括答题、交卷、抢卷、判分、生成pdf
This commit is contained in:
parent
1da167638a
commit
e2b5844fec
2
.gitignore
vendored
2
.gitignore
vendored
@ -29,3 +29,5 @@ dist-electron
|
||||
*.sw?
|
||||
|
||||
*.tsbuildinfo
|
||||
|
||||
*.pdf
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -203,7 +203,7 @@ export const userSchema = {
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
examinee_id INTEGER NOT NULL,
|
||||
paper_minutes INTEGER NOT NULL DEFAULT 0,
|
||||
paper_minuts_min INTEGER NOT NULL DEFAULT 0,
|
||||
paper_minutes_min INTEGER NOT NULL DEFAULT 0,
|
||||
paper_start_time TEXT,
|
||||
paper_last_time TEXT,
|
||||
paper_submit_time TEXT,
|
||||
|
BIN
electron/font/SourceHanSansSC-Bold.otf
Normal file
BIN
electron/font/SourceHanSansSC-Bold.otf
Normal file
Binary file not shown.
BIN
electron/font/SourceHanSansSC-ExtraLight.otf
Normal file
BIN
electron/font/SourceHanSansSC-ExtraLight.otf
Normal file
Binary file not shown.
BIN
electron/font/SourceHanSansSC-Heavy.otf
Normal file
BIN
electron/font/SourceHanSansSC-Heavy.otf
Normal file
Binary file not shown.
BIN
electron/font/SourceHanSansSC-Light.otf
Normal file
BIN
electron/font/SourceHanSansSC-Light.otf
Normal file
Binary file not shown.
BIN
electron/font/SourceHanSansSC-Medium.otf
Normal file
BIN
electron/font/SourceHanSansSC-Medium.otf
Normal file
Binary file not shown.
BIN
electron/font/SourceHanSansSC-Normal.otf
Normal file
BIN
electron/font/SourceHanSansSC-Normal.otf
Normal file
Binary file not shown.
BIN
electron/font/SourceHanSansSC-Regular.otf
Normal file
BIN
electron/font/SourceHanSansSC-Regular.otf
Normal file
Binary file not shown.
BIN
electron/font/simsun.ttc
Normal file
BIN
electron/font/simsun.ttc
Normal file
Binary file not shown.
BIN
electron/font/simsun.ttf
Normal file
BIN
electron/font/simsun.ttf
Normal file
Binary file not shown.
@ -31,6 +31,10 @@ import {
|
||||
initExamingIpc
|
||||
} from "./service/examingService.js";
|
||||
|
||||
import {
|
||||
initFileIpc
|
||||
} from "./service/fileService.js";
|
||||
|
||||
// 定义 __dirname 和 __filename
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
@ -163,6 +167,8 @@ function setupIpcMain() {
|
||||
initExamineeIpc(ipcMain);
|
||||
|
||||
initExamingIpc(ipcMain);
|
||||
|
||||
initFileIpc(ipcMain);
|
||||
}
|
||||
|
||||
// 确保在 app.whenReady() 中调用 setupIpcMain()
|
||||
|
@ -1,6 +1,7 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron');
|
||||
|
||||
// 暴露API给渲染进程
|
||||
// 在contextBridge.exposeInMainWorld中添加以下方法
|
||||
contextBridge.exposeInMainWorld('electronAPI', {
|
||||
// 数据库相关
|
||||
checkDatabaseInitialized: () => ipcRenderer.invoke('check-database-initialized'),
|
||||
@ -64,9 +65,20 @@ contextBridge.exposeInMainWorld('electronAPI', {
|
||||
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 }),
|
||||
|
||||
// 考试进行相关API
|
||||
generateExamineePaper: (examineeData, examData) => ipcRenderer.invoke('examing-generate-paper', { examineeData, examData }),
|
||||
getExamineePaperStatus: (examineeId) => ipcRenderer.invoke('examing-get-paper-status', examineeId),
|
||||
updatePaperStatus: (paperId, statusData) => ipcRenderer.invoke('examing-update-paper-status', { paperId, statusData }),
|
||||
loadPaperSerial: (paperId) => ipcRenderer.invoke('examing-load-paper-serial', paperId),
|
||||
getQuestionByRelatedId: (tableName, id) => ipcRenderer.invoke('examing-get-question-by-related-id', { tableName, id }),
|
||||
updateExamineeAnswer: (tableName, id, answers) => ipcRenderer.invoke('examing-update-answer', { tableName, id, answers }),
|
||||
startPaper: (paperId) => ipcRenderer.invoke('examing-start-paper', paperId),
|
||||
submitPaper: (paperId) => ipcRenderer.invoke('examing-submit-paper', paperId),
|
||||
endPaper: (paperId) => ipcRenderer.invoke('examing-end-paper', paperId),
|
||||
processPaper: (paperId) => ipcRenderer.invoke('examing-process-paper', paperId),
|
||||
checkPaperAnswers: (paperId) => ipcRenderer.invoke('examing-check-paper-answers', paperId), // 添加暴露接口
|
||||
// 文件相关API
|
||||
generatePdf: (pdfData, fileName) => ipcRenderer.invoke('file-generate-pdf', pdfData, fileName),
|
||||
fileTest: () => ipcRenderer.invoke('file-test'),
|
||||
generatePaperPdf: (jsonString) => ipcRenderer.invoke('file-generate-paper-pdf', jsonString),
|
||||
});
|
@ -1,7 +1,17 @@
|
||||
// 导入数据库操作函数
|
||||
import { generateExamineePaper } from '../db/examing.js';
|
||||
import { getDbConnection, closeAllConnections } from '../db/index.js';
|
||||
import { getUserDbPath } from '../db/path.js';
|
||||
import {
|
||||
generateExamineePaper,
|
||||
loadPaperSerial,
|
||||
getQuestionByRelatedId,
|
||||
updateExamineeAnswer,
|
||||
startPaper,
|
||||
submitPaper,
|
||||
endPaper,
|
||||
processPaper,
|
||||
checkPaperAnswers, // 添加导入
|
||||
} from "../db/examing.js";
|
||||
import { getDbConnection, closeAllConnections } from "../db/index.js";
|
||||
import { getUserDbPath } from "../db/path.js";
|
||||
|
||||
/**
|
||||
* 服务层:生成考生试卷
|
||||
@ -14,24 +24,27 @@ export async function generateExamineePaperService(examineeData, examData) {
|
||||
try {
|
||||
// 数据验证
|
||||
if (!examineeData || !examineeData.id || !examineeData.examinee_name) {
|
||||
throw new Error('考生数据不完整,必须包含ID和姓名');
|
||||
throw new Error("考生数据不完整,必须包含ID和姓名");
|
||||
}
|
||||
|
||||
if (!examData || !examData.exam_minutes || examData.exam_minutes <= 0) {
|
||||
throw new Error('考试时长必须为正数');
|
||||
throw new Error("考试时长必须为正数");
|
||||
}
|
||||
|
||||
if (examData.exam_minutes_min === undefined || examData.exam_minutes_min < 0) {
|
||||
throw new Error('最短考试时长必须为非负数');
|
||||
if (
|
||||
examData.exam_minutes_min === undefined ||
|
||||
examData.exam_minutes_min < 0
|
||||
) {
|
||||
throw new Error("最短考试时长必须为非负数");
|
||||
}
|
||||
|
||||
const result = await generateExamineePaper(examineeData, examData);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error('服务层: 生成考生试卷失败', error);
|
||||
console.error("服务层: 生成考生试卷失败", error);
|
||||
return {
|
||||
success: false,
|
||||
message: `生成试卷失败: ${error.message}`
|
||||
message: `生成试卷失败: ${error.message}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -44,18 +57,18 @@ export async function generateExamineePaperService(examineeData, examData) {
|
||||
export async function getExamineePaperStatusService(examineeId) {
|
||||
try {
|
||||
if (!examineeId || examineeId <= 0) {
|
||||
throw new Error('考生ID必须为正数');
|
||||
throw new Error("考生ID必须为正数");
|
||||
}
|
||||
|
||||
const userDb = await getDbConnection(getUserDbPath());
|
||||
const paperStatus = await userDb.getAsync(
|
||||
'SELECT * FROM examinee_papers WHERE examinee_id = ?',
|
||||
"SELECT * FROM examinee_papers WHERE examinee_id = ?",
|
||||
[examineeId]
|
||||
);
|
||||
|
||||
return paperStatus;
|
||||
} catch (error) {
|
||||
console.error('服务层: 获取考生试卷状态失败', error);
|
||||
console.error("服务层: 获取考生试卷状态失败", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@ -69,7 +82,7 @@ export async function getExamineePaperStatusService(examineeId) {
|
||||
export async function updatePaperStatusService(paperId, statusData) {
|
||||
try {
|
||||
if (!paperId || paperId <= 0) {
|
||||
throw new Error('试卷ID必须为正数');
|
||||
throw new Error("试卷ID必须为正数");
|
||||
}
|
||||
|
||||
const userDb = await getDbConnection(getUserDbPath());
|
||||
@ -79,32 +92,32 @@ export async function updatePaperStatusService(paperId, statusData) {
|
||||
const values = [];
|
||||
|
||||
if (statusData.paper_start_time !== undefined) {
|
||||
fields.push('paper_start_time = ?');
|
||||
fields.push("paper_start_time = ?");
|
||||
values.push(statusData.paper_start_time);
|
||||
}
|
||||
|
||||
if (statusData.paper_last_time !== undefined) {
|
||||
fields.push('paper_last_time = ?');
|
||||
fields.push("paper_last_time = ?");
|
||||
values.push(statusData.paper_last_time);
|
||||
}
|
||||
|
||||
if (statusData.paper_submit_time !== undefined) {
|
||||
fields.push('paper_submit_time = ?');
|
||||
fields.push("paper_submit_time = ?");
|
||||
values.push(statusData.paper_submit_time);
|
||||
}
|
||||
|
||||
if (statusData.paper_end_time !== undefined) {
|
||||
fields.push('paper_end_time = ?');
|
||||
fields.push("paper_end_time = ?");
|
||||
values.push(statusData.paper_end_time);
|
||||
}
|
||||
|
||||
if (statusData.paper_status !== undefined) {
|
||||
fields.push('paper_status = ?');
|
||||
fields.push("paper_status = ?");
|
||||
values.push(statusData.paper_status);
|
||||
}
|
||||
|
||||
if (statusData.paper_score_real !== undefined) {
|
||||
fields.push('paper_score_real = ?');
|
||||
fields.push("paper_score_real = ?");
|
||||
values.push(statusData.paper_score_real);
|
||||
}
|
||||
|
||||
@ -115,51 +128,365 @@ export async function updatePaperStatusService(paperId, statusData) {
|
||||
// 添加WHERE条件的值
|
||||
values.push(paperId);
|
||||
|
||||
const sql = `UPDATE examinee_papers SET ${fields.join(', ')} WHERE id = ?`;
|
||||
const sql = `UPDATE examinee_papers SET ${fields.join(", ")} WHERE id = ?`;
|
||||
await userDb.runAsync(sql, values);
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('服务层: 更新试卷状态失败', error);
|
||||
console.error("服务层: 更新试卷状态失败", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务层:加载试卷试题序列
|
||||
* @param {number} paperId - 试卷ID
|
||||
* @returns {Promise<Array>} - 包含试题序列的数组
|
||||
*/
|
||||
export async function loadPaperSerialService(paperId) {
|
||||
try {
|
||||
if (!paperId || paperId <= 0) {
|
||||
throw new Error("试卷ID必须为正数");
|
||||
}
|
||||
|
||||
const result = await loadPaperSerial(paperId);
|
||||
return {
|
||||
success: true,
|
||||
data: result,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("服务层: 加载试卷试题序列失败", error);
|
||||
return {
|
||||
success: false,
|
||||
message: `加载试卷试题序列失败: ${error.message}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务层:根据表名和ID获取完整的试题数据
|
||||
* @param {string} tableName - 表名 (question_choices 或 question_fill_blanks)
|
||||
* @param {number} id - 记录ID
|
||||
* @returns {Promise<Object>} - 包含试题数据的对象
|
||||
*/
|
||||
export async function getQuestionByRelatedIdService(tableName, id) {
|
||||
try {
|
||||
// if (!tableName || !['question_choices', 'question_fill_blanks'].includes(tableName)) {
|
||||
// throw new Error('无效的表名,只能是 question_choices 或 question_fill_blanks');
|
||||
// }
|
||||
|
||||
// if (!id || id <= 0) {
|
||||
// throw new Error('记录ID必须为正数');
|
||||
// }
|
||||
|
||||
const result = await getQuestionByRelatedId(tableName, id);
|
||||
return {
|
||||
success: true,
|
||||
data: result,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("服务层: 获取试题数据失败", error);
|
||||
return {
|
||||
success: false,
|
||||
message: `获取试题数据失败: ${error.message}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务层:更新考生答案
|
||||
* @param {string} tableName - 表名 (question_choices 或 question_fill_blanks)
|
||||
* @param {number} id - 记录ID
|
||||
* @param {Array|string} answers - 考生答案
|
||||
* @returns {Promise<Object>} - 包含更新结果的对象
|
||||
*/
|
||||
export async function updateExamineeAnswerService(tableName, id, answers) {
|
||||
try {
|
||||
if (!["question_choices", "question_fill_blanks"].includes(tableName)) {
|
||||
throw new Error(
|
||||
"无效的表名,只能是 question_choices 或 question_fill_blanks"
|
||||
);
|
||||
}
|
||||
|
||||
if (!id || id <= 0) {
|
||||
throw new Error("记录ID必须为正数");
|
||||
}
|
||||
|
||||
const result = await updateExamineeAnswer(tableName, id, answers);
|
||||
return {
|
||||
success: true,
|
||||
message: "答案更新成功",
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("服务层: 更新考生答案失败", error);
|
||||
return {
|
||||
success: false,
|
||||
message: `更新答案失败: ${error.message}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务层:开始考试
|
||||
* @param {number} paperId - 试卷ID
|
||||
* @returns {Promise<Object>} - 包含操作结果的对象
|
||||
*/
|
||||
export async function startPaperService(paperId) {
|
||||
try {
|
||||
if (!paperId || paperId <= 0) {
|
||||
throw new Error("试卷ID必须为正数");
|
||||
}
|
||||
|
||||
const result = await startPaper(paperId);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error("服务层: 开始考试失败", error);
|
||||
return {
|
||||
success: false,
|
||||
message: `开始考试失败: ${error.message}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务层:提交考试
|
||||
* @param {number} paperId - 试卷ID
|
||||
* @returns {Promise<Object>} - 包含操作结果的对象
|
||||
*/
|
||||
export async function submitPaperService(paperId) {
|
||||
try {
|
||||
if (!paperId || paperId <= 0) {
|
||||
throw new Error("试卷ID必须为正数");
|
||||
}
|
||||
|
||||
const result = await submitPaper(paperId);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error("服务层: 提交考试失败", error);
|
||||
return {
|
||||
success: false,
|
||||
message: `提交考试失败: ${error.message}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务层:结束考试
|
||||
* @param {number} paperId - 试卷ID
|
||||
* @returns {Promise<Object>} - 包含操作结果的对象
|
||||
*/
|
||||
export async function endPaperService(paperId) {
|
||||
try {
|
||||
if (!paperId || paperId <= 0) {
|
||||
throw new Error("试卷ID必须为正数");
|
||||
}
|
||||
|
||||
const result = await endPaper(paperId);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error("服务层: 结束考试失败", error);
|
||||
return {
|
||||
success: false,
|
||||
message: `结束考试失败: ${error.message}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务层:处理试卷
|
||||
* @param {number} paperId - 试卷ID
|
||||
* @returns {Promise<Object>} - 包含操作结果的对象
|
||||
*/
|
||||
export async function processPaperService(paperId) {
|
||||
try {
|
||||
if (!paperId || paperId <= 0) {
|
||||
throw new Error("试卷ID必须为正数");
|
||||
}
|
||||
|
||||
const result = await processPaper(paperId);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error("服务层: 处理试卷失败", error);
|
||||
return {
|
||||
success: false,
|
||||
message: `处理试卷失败: ${error.message}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 服务层:检查试卷答案并计算得分
|
||||
* @param {number} paperId - 试卷ID
|
||||
* @returns {Promise<Object>} - 包含操作结果和试卷数据的对象
|
||||
*/
|
||||
export async function checkPaperAnswersService(paperId) {
|
||||
try {
|
||||
if (!paperId || paperId <= 0) {
|
||||
throw new Error("试卷ID必须为正数");
|
||||
}
|
||||
|
||||
const result = await checkPaperAnswers(paperId);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error("服务层: 检查试卷答案失败", error);
|
||||
return {
|
||||
success: false,
|
||||
message: `检查试卷答案失败: ${error.message}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化考试相关的IPC处理程序
|
||||
* @param {import('electron').IpcMain} ipcMain - IPC主进程实例
|
||||
*/
|
||||
export function initExamingIpc(ipcMain) {
|
||||
// 生成考生试卷
|
||||
ipcMain.handle('examing-generate-paper', async (event, { examineeData, examData }) => {
|
||||
try {
|
||||
return await generateExamineePaperService(examineeData, examData);
|
||||
} catch (error) {
|
||||
console.error('生成考生试卷失败:', error);
|
||||
return {
|
||||
success: false,
|
||||
message: `生成试卷失败: ${error.message}`
|
||||
};
|
||||
ipcMain.handle(
|
||||
"examing-generate-paper",
|
||||
async (event, { examineeData, examData }) => {
|
||||
try {
|
||||
return await generateExamineePaperService(examineeData, examData);
|
||||
} catch (error) {
|
||||
console.error("生成考生试卷失败:", error);
|
||||
return {
|
||||
success: false,
|
||||
message: `生成试卷失败: ${error.message}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
// 获取考生试卷状态
|
||||
ipcMain.handle('examing-get-paper-status', async (event, examineeId) => {
|
||||
ipcMain.handle("examing-get-paper-status", async (event, examineeId) => {
|
||||
try {
|
||||
return await getExamineePaperStatusService(examineeId);
|
||||
} catch (error) {
|
||||
console.error('获取考生试卷状态失败:', error);
|
||||
console.error("获取考生试卷状态失败:", error);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// 更新试卷状态
|
||||
ipcMain.handle('examing-update-paper-status', async (event, { paperId, statusData }) => {
|
||||
ipcMain.handle(
|
||||
"examing-update-paper-status",
|
||||
async (event, { paperId, statusData }) => {
|
||||
try {
|
||||
return await updatePaperStatusService(paperId, statusData);
|
||||
} catch (error) {
|
||||
console.error("更新试卷状态失败:", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 加载试卷试题序列
|
||||
ipcMain.handle("examing-load-paper-serial", async (event, paperId) => {
|
||||
try {
|
||||
return await updatePaperStatusService(paperId, statusData);
|
||||
return await loadPaperSerialService(paperId);
|
||||
} catch (error) {
|
||||
console.error('更新试卷状态失败:', error);
|
||||
return false;
|
||||
console.error("加载试卷试题序列失败:", error);
|
||||
return {
|
||||
success: false,
|
||||
message: `加载试卷试题序列失败: ${error.message}`,
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 根据表名和ID获取完整的试题数据
|
||||
ipcMain.handle(
|
||||
"examing-get-question-by-related-id",
|
||||
async (event, { tableName, id }) => {
|
||||
try {
|
||||
return await getQuestionByRelatedIdService(tableName, id);
|
||||
} catch (error) {
|
||||
console.error("获取试题数据失败:", error);
|
||||
return {
|
||||
success: false,
|
||||
message: `获取试题数据失败: ${error.message}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 更新考生答案
|
||||
ipcMain.handle(
|
||||
"examing-update-answer",
|
||||
async (event, { tableName, id, answers }) => {
|
||||
try {
|
||||
return await updateExamineeAnswerService(tableName, id, answers);
|
||||
} catch (error) {
|
||||
console.error("更新考生答案失败:", error);
|
||||
return {
|
||||
success: false,
|
||||
message: `更新答案失败: ${error.message}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 更新导入语句
|
||||
ipcMain.handle("examing-start-paper", async (event, paperId) => {
|
||||
try {
|
||||
return await startPaperService(paperId);
|
||||
} catch (error) {
|
||||
console.error("开始考试失败:", error);
|
||||
return {
|
||||
success: false,
|
||||
message: `开始考试失败: ${error.message}`,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// 提交考试
|
||||
ipcMain.handle("examing-submit-paper", async (event, paperId) => {
|
||||
try {
|
||||
return await submitPaperService(paperId);
|
||||
} catch (error) {
|
||||
console.error("提交考试失败:", error);
|
||||
return {
|
||||
success: false,
|
||||
message: `提交考试失败: ${error.message}`,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// 结束考试
|
||||
ipcMain.handle("examing-end-paper", async (event, paperId) => {
|
||||
try {
|
||||
return await endPaperService(paperId);
|
||||
} catch (error) {
|
||||
console.error("结束考试失败:", error);
|
||||
return {
|
||||
success: false,
|
||||
message: `结束考试失败: ${error.message}`,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// 处理试卷
|
||||
ipcMain.handle("examing-process-paper", async (event, paperId) => {
|
||||
try {
|
||||
return await processPaperService(paperId);
|
||||
} catch (error) {
|
||||
console.error("处理试卷失败:", error);
|
||||
return {
|
||||
success: false,
|
||||
message: `处理试卷失败: ${error.message}`,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// 检查试卷答案并计算得分
|
||||
ipcMain.handle("examing-check-paper-answers", async (event, paperId) => {
|
||||
try {
|
||||
return await checkPaperAnswersService(paperId);
|
||||
} catch (error) {
|
||||
console.error("检查试卷答案失败:", error);
|
||||
return {
|
||||
success: false,
|
||||
message: `检查试卷答案失败: ${error.message}`,
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
|
1381
electron/service/fileService.js
Normal file
1381
electron/service/fileService.js
Normal file
File diff suppressed because one or more lines are too long
2
output/.gitignore
vendored
Normal file
2
output/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
145
package-lock.json
generated
145
package-lock.json
generated
@ -19,6 +19,7 @@
|
||||
"bootstrap": "^5.3.7",
|
||||
"element-plus": "^2.10.5",
|
||||
"fs": "^0.0.1-security",
|
||||
"pdfkit": "^0.17.1",
|
||||
"popper.js": "^1.16.1",
|
||||
"sqlite": "^5.1.1",
|
||||
"sqlite3": "^5.1.7",
|
||||
@ -2464,6 +2465,15 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/helpers": {
|
||||
"version": "0.5.17",
|
||||
"resolved": "https://registry.npmmirror.com/@swc/helpers/-/helpers-0.5.17.tgz",
|
||||
"integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@szmarczak/http-timer": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmmirror.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
|
||||
@ -3420,6 +3430,15 @@
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/brotli": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmmirror.com/brotli/-/brotli-1.3.3.tgz",
|
||||
"integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/browserslist": {
|
||||
"version": "4.25.1",
|
||||
"resolved": "https://registry.npmmirror.com/browserslist/-/browserslist-4.25.1.tgz",
|
||||
@ -4152,6 +4171,12 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/crypto-js": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/crypto-js/-/crypto-js-4.2.0.tgz",
|
||||
"integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.1.3.tgz",
|
||||
@ -4344,6 +4369,12 @@
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/dfa": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/dfa/-/dfa-1.2.0.tgz",
|
||||
"integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dir-compare": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmmirror.com/dir-compare/-/dir-compare-4.2.0.tgz",
|
||||
@ -5022,7 +5053,6 @@
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
|
||||
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-json-stable-stringify": {
|
||||
@ -5112,6 +5142,32 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/fontkit": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmmirror.com/fontkit/-/fontkit-2.0.4.tgz",
|
||||
"integrity": "sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@swc/helpers": "^0.5.12",
|
||||
"brotli": "^1.3.2",
|
||||
"clone": "^2.1.2",
|
||||
"dfa": "^1.2.0",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"restructure": "^3.0.0",
|
||||
"tiny-inflate": "^1.0.3",
|
||||
"unicode-properties": "^1.4.0",
|
||||
"unicode-trie": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fontkit/node_modules/clone": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmmirror.com/clone/-/clone-2.1.2.tgz",
|
||||
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/foreground-child": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmmirror.com/foreground-child/-/foreground-child-3.3.1.tgz",
|
||||
@ -5960,6 +6016,12 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/jpeg-exif": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmmirror.com/jpeg-exif/-/jpeg-exif-1.1.4.tgz",
|
||||
"integrity": "sha512-a+bKEcCjtuW5WTdgeXFzswSrdqi0jk4XlEtZlx5A94wCoBpFjfFTbo/Tra5SpNCl/YFZPvcV1dJc+TAYeg6ROQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
@ -6069,6 +6131,25 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/linebreak": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmmirror.com/linebreak/-/linebreak-1.1.0.tgz",
|
||||
"integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "0.0.8",
|
||||
"unicode-trie": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/linebreak/node_modules/base64-js": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-0.0.8.tgz",
|
||||
"integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz",
|
||||
@ -6831,6 +6912,12 @@
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0"
|
||||
},
|
||||
"node_modules/pako": {
|
||||
"version": "0.2.9",
|
||||
"resolved": "https://registry.npmmirror.com/pako/-/pako-0.2.9.tgz",
|
||||
"integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/parse-ms": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/parse-ms/-/parse-ms-4.0.0.tgz",
|
||||
@ -6905,6 +6992,19 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pdfkit": {
|
||||
"version": "0.17.1",
|
||||
"resolved": "https://registry.npmmirror.com/pdfkit/-/pdfkit-0.17.1.tgz",
|
||||
"integrity": "sha512-Kkf1I9no14O/uo593DYph5u3QwiMfby7JsBSErN1WqeyTgCBNJE3K4pXBn3TgkdKUIVu+buSl4bYUNC+8Up4xg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"crypto-js": "^4.2.0",
|
||||
"fontkit": "^2.0.4",
|
||||
"jpeg-exif": "^1.1.4",
|
||||
"linebreak": "^1.1.0",
|
||||
"png-js": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pe-library": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmmirror.com/pe-library/-/pe-library-0.4.1.tgz",
|
||||
@ -6968,6 +7068,11 @@
|
||||
"node": ">=10.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/png-js": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/png-js/-/png-js-1.0.0.tgz",
|
||||
"integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g=="
|
||||
},
|
||||
"node_modules/popper.js": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmmirror.com/popper.js/-/popper.js-1.16.1.tgz",
|
||||
@ -7264,6 +7369,12 @@
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/restructure": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmmirror.com/restructure/-/restructure-3.0.2.tgz",
|
||||
"integrity": "sha512-gSfoiOEA0VPE6Tukkrr7I0RBdE0s7H1eFCDBk05l1KIQT1UIKNc5JZy6jdyW6eYH3aR3g5b3PuL77rq0hvwtAw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/retry": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmmirror.com/retry/-/retry-0.12.0.tgz",
|
||||
@ -8054,6 +8165,12 @@
|
||||
"semver": "bin/semver"
|
||||
}
|
||||
},
|
||||
"node_modules/tiny-inflate": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmmirror.com/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
|
||||
"integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.14",
|
||||
"resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.14.tgz",
|
||||
@ -8111,6 +8228,12 @@
|
||||
"utf8-byte-length": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmmirror.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
@ -8158,6 +8281,26 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/unicode-properties": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmmirror.com/unicode-properties/-/unicode-properties-1.4.1.tgz",
|
||||
"integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.0",
|
||||
"unicode-trie": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unicode-trie": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmmirror.com/unicode-trie/-/unicode-trie-2.0.0.tgz",
|
||||
"integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pako": "^0.2.5",
|
||||
"tiny-inflate": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unicorn-magic": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmmirror.com/unicorn-magic/-/unicorn-magic-0.3.0.tgz",
|
||||
|
@ -27,6 +27,7 @@
|
||||
"bootstrap": "^5.3.7",
|
||||
"element-plus": "^2.10.5",
|
||||
"fs": "^0.0.1-security",
|
||||
"pdfkit": "^0.17.1",
|
||||
"popper.js": "^1.16.1",
|
||||
"sqlite": "^5.1.1",
|
||||
"sqlite3": "^5.1.7",
|
||||
@ -56,7 +57,9 @@
|
||||
"target": [
|
||||
{
|
||||
"target": "nsis",
|
||||
"arch": ["ia32"]
|
||||
"arch": [
|
||||
"ia32"
|
||||
]
|
||||
}
|
||||
],
|
||||
"icon": "public/favicon.ico"
|
||||
|
BIN
src/assets/bg.jpeg
Normal file
BIN
src/assets/bg.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
BIN
src/assets/logo.png
Normal file
BIN
src/assets/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
@ -4,8 +4,9 @@
|
||||
<div class="row h-100 align-items-center justify-content-center">
|
||||
<div class="col-auto">
|
||||
<h2 class="display-6 m-0 d-flex align-items-center">
|
||||
<font-awesome-icon icon="graduation-cap" class="me-3" />
|
||||
{{thisYear}}年抚顺市统计行业职工技能大赛考试系统
|
||||
<!-- <font-awesome-icon icon="graduation-cap" class="me-3" /> -->
|
||||
<img src="../../assets/logo.png" alt="logo" style="width:50px;height:50px;margin-right:1rem;">
|
||||
{{thisYear}}<strong>年抚顺市统计行业职工技能大赛考试系统</strong>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
@ -16,7 +17,7 @@
|
||||
<style scoped>
|
||||
.header-container {
|
||||
width: 100%;
|
||||
background-color: #1e40af; /* 深蓝色背景 */
|
||||
background-color: #4f74ed; /* 深蓝色背景 */
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
height: 80px; /* 设置固定高度 */
|
||||
padding: 0 2rem;
|
||||
|
@ -15,6 +15,10 @@ import ExamManagementView from '@/views/admin/ExamManagementView.vue'
|
||||
// 导入ExamineeManagementView
|
||||
import ExamineeManagementView from '@/views/admin/ExamineeManagementView.vue'
|
||||
|
||||
// 首先在文件顶部导入EndView组件
|
||||
import EndView from '@/views/user/EndView.vue'
|
||||
|
||||
// 然后在routes数组中添加新路由
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
routes: [
|
||||
@ -30,10 +34,16 @@ const router = createRouter({
|
||||
},
|
||||
// Modify the examing route to use lazy loading
|
||||
{
|
||||
path: '/examinee/examing',
|
||||
path: '/examinee/examing/:paperId',
|
||||
name: 'examinee-examing',
|
||||
component: ExamingView,
|
||||
},
|
||||
// 添加EndView路由
|
||||
{
|
||||
path: '/examinee/end',
|
||||
name: 'examinee-end',
|
||||
component: EndView,
|
||||
},
|
||||
// admin/AdminHomeView路由
|
||||
{
|
||||
path: '/admin/home',
|
||||
|
@ -3,7 +3,9 @@ import { reactive, provide, inject } from 'vue'
|
||||
// 创建用户状态
|
||||
const userState = reactive({
|
||||
examinee: null,
|
||||
isLoggedIn: false
|
||||
isLoggedIn: false,
|
||||
exam: null, // 考试信息属性
|
||||
paper: null // 新增:试卷信息属性
|
||||
})
|
||||
|
||||
// 创建状态管理工具
|
||||
@ -20,6 +22,16 @@ const userStore = {
|
||||
clearExaminee() {
|
||||
this.state.examinee = null
|
||||
this.state.isLoggedIn = false
|
||||
},
|
||||
|
||||
// 添加设置考试数据的方法
|
||||
setExam(exam) {
|
||||
this.state.exam = exam
|
||||
},
|
||||
|
||||
// 新增:设置试卷数据的方法
|
||||
setPaper(paper) {
|
||||
this.state.paper = paper
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="welcome-container">
|
||||
<div class="welcome-container" style="background-image: url('/src/assets/bg.jpeg'); background-size: cover; background-position: center;">
|
||||
<el-container>
|
||||
<Header />
|
||||
|
||||
|
269
src/views/user/EndView.vue
Normal file
269
src/views/user/EndView.vue
Normal file
@ -0,0 +1,269 @@
|
||||
<template>
|
||||
<div class="end-container">
|
||||
<el-container>
|
||||
<Header />
|
||||
<!-- 主要内容区域 -->
|
||||
<el-main>
|
||||
<div style="width: 100%; height: 100%;">
|
||||
<div class="d-flex align-items-center justify-content-center p-4" style="width:100%">
|
||||
<!-- 交卷结果卡片 -->
|
||||
<div class="bg-white rounded-4 shadow-lg p-4 w-100 max-w-2xl border-2 border-primary/20">
|
||||
<el-result icon="success" title="考试已完成" sub-title="您已成功提交试卷,感谢您的参与!">
|
||||
<template #extra>
|
||||
<el-button type="primary" @click="goHome">返回首页</el-button>
|
||||
</template>
|
||||
</el-result>
|
||||
|
||||
<el-divider />
|
||||
<div class="flex justify-between text-center mt-6 mb-4">
|
||||
<h2 class="text-2xl font-bold text-primary">考生信息</h2>
|
||||
</div>
|
||||
<!-- 考生信息部分 -->
|
||||
<el-descriptions class="margin-top" :column="3" :size="size" border>
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<div class="cell-item">
|
||||
<el-icon :style="iconStyle">
|
||||
<User />
|
||||
</el-icon>
|
||||
姓名
|
||||
</div>
|
||||
</template>
|
||||
{{ examinee?.examinee_name }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<div class="cell-item">
|
||||
<el-icon :style="iconStyle">
|
||||
<Postcard />
|
||||
</el-icon>
|
||||
身份证号
|
||||
</div>
|
||||
</template>
|
||||
{{ formatIdCard(examinee?.examinee_id_card) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<div class="cell-item">
|
||||
<el-icon :style="iconStyle">
|
||||
<Ticket />
|
||||
</el-icon>
|
||||
准考证号
|
||||
</div>
|
||||
</template>
|
||||
{{ examinee?.examinee_admission_ticket }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<el-divider />
|
||||
<div class="flex justify-between text-center mt-6 mb-4">
|
||||
<h2 class="text-2xl font-bold text-primary">考试信息</h2>
|
||||
</div>
|
||||
<!-- 试卷信息部分 -->
|
||||
<el-descriptions class="margin-top" :column="2" :size="size" border>
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<div class="cell-item">
|
||||
<el-icon :style="iconStyle">
|
||||
<Clock />
|
||||
</el-icon>
|
||||
开始时间
|
||||
</div>
|
||||
</template>
|
||||
{{ formatDateTime(paper?.paper_start_time) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<div class="cell-item">
|
||||
<el-icon :style="iconStyle">
|
||||
<Clock />
|
||||
</el-icon>
|
||||
结束时间
|
||||
</div>
|
||||
</template>
|
||||
{{ formatDateTime(paper?.paper_end_time) }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item>
|
||||
<template #label>
|
||||
<div class="cell-item">
|
||||
<el-icon :style="iconStyle">
|
||||
<Timer />
|
||||
</el-icon>
|
||||
总使用时间
|
||||
</div>
|
||||
</template>
|
||||
{{ formatDuration(paper?.paper_start_time, paper?.paper_end_time) }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-main>
|
||||
|
||||
<Footer />
|
||||
</el-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// 导入组件
|
||||
import Header from '@/components/common/Header.vue'
|
||||
import Footer from '@/components/common/Footer.vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { ElMessage, ElDescriptions, ElDescriptionsItem, ElIcon, ElResult } from 'element-plus'
|
||||
import { User, Postcard, Ticket, Clock, Timer } from '@element-plus/icons-vue'
|
||||
|
||||
// 导入用户状态管理
|
||||
import { useUserStore } from '@/store/userStore'
|
||||
|
||||
// 获取用户状态管理
|
||||
const userStore = useUserStore()
|
||||
// 响应式引用考生数据
|
||||
const examinee = computed(() => userStore.state.examinee)
|
||||
// 响应式引用试卷数据
|
||||
const paper = computed(() => userStore.state.paper)
|
||||
// 添加判卷状态变量
|
||||
const isChecking = ref(false)
|
||||
|
||||
// 检查是否已登录
|
||||
if (!userStore.state.isLoggedIn) {
|
||||
// 如果未登录,重定向到欢迎页
|
||||
router.push('/')
|
||||
}
|
||||
|
||||
// 响应式数据
|
||||
const router = useRouter()
|
||||
const size = ref('default')
|
||||
|
||||
// 图标样式计算属性
|
||||
const iconStyle = computed(() => {
|
||||
const marginMap = {
|
||||
large: '8px',
|
||||
default: '6px',
|
||||
small: '4px',
|
||||
}
|
||||
return {
|
||||
marginRight: marginMap[size.value] || marginMap.default,
|
||||
}
|
||||
})
|
||||
|
||||
// 格式化身份证号(第11-15位替换为*)
|
||||
const formatIdCard = (idCard) => {
|
||||
if (!idCard || idCard.length !== 18) return idCard
|
||||
return idCard.substring(0, 9) + '*****' + idCard.substring(14)
|
||||
}
|
||||
|
||||
// 格式化日期时间
|
||||
const formatDateTime = (dateTime) => {
|
||||
if (!dateTime) return '未知'
|
||||
const date = new Date(dateTime)
|
||||
return date.toLocaleString()
|
||||
}
|
||||
|
||||
// 计算考试持续时间
|
||||
const formatDuration = (startTime, endTime) => {
|
||||
if (!startTime || !endTime) return '未知'
|
||||
const start = new Date(startTime)
|
||||
const end = new Date(endTime)
|
||||
const diff = end - start
|
||||
const minutes = Math.floor(diff / (1000 * 60))
|
||||
const hours = Math.floor(minutes / 60)
|
||||
const mins = minutes % 60
|
||||
return `${hours}小时${mins}分钟`
|
||||
}
|
||||
|
||||
// 返回首页
|
||||
const goHome = () => {
|
||||
router.push({ name: 'examinee-home' })
|
||||
}
|
||||
|
||||
// 组件挂载时
|
||||
onMounted(() => {
|
||||
console.log('EndView初始化')
|
||||
// 检查是否有试卷数据
|
||||
if (!paper.value) {
|
||||
ElMessage.warning('未找到试卷信息')
|
||||
console.log('未找到试卷信息,准备跳转到首页')
|
||||
// 延迟重定向到首页
|
||||
setTimeout(() => {
|
||||
goHome()
|
||||
}, 2000)
|
||||
} else {
|
||||
// 有试卷数据,执行判卷
|
||||
checkAnswers()
|
||||
}
|
||||
})
|
||||
|
||||
// 判卷函数
|
||||
const checkAnswers = async () => {
|
||||
try {
|
||||
isChecking.value = true
|
||||
console.log('开始判卷,试卷ID:', paper.value.id)
|
||||
|
||||
// 调用检查答案接口
|
||||
const result = await window.electronAPI.checkPaperAnswers(paper.value.id)
|
||||
console.log('判卷接口返回结果:', result)
|
||||
|
||||
if (result.success) {
|
||||
// 调用 generatePaperPdf 接口并传入 result.data
|
||||
const pdfPath = await window.electronAPI.generatePaperPdf(result.data)
|
||||
console.log('生成的试卷PDF文件路径:', pdfPath)
|
||||
// 更新store中的试卷数据
|
||||
userStore.setPaper(JSON.stringify(result.data))
|
||||
console.log('试卷数据已更新到store,得分:', result.data.paper_score_real)
|
||||
} else {
|
||||
console.error('判卷失败:', result.message)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('判卷过程发生错误:', error)
|
||||
} finally {
|
||||
isChecking.value = false
|
||||
console.log('判卷完成')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 自定义样式 */
|
||||
.bg-primary {
|
||||
background-color: #1E88E5 !important;
|
||||
/* 蓝色主题,与ExamineeHomeView保持一致 */
|
||||
}
|
||||
|
||||
.text-primary {
|
||||
color: #1E88E5 !important;
|
||||
}
|
||||
|
||||
/* 确保容器占满高度 */
|
||||
.end-container,
|
||||
.el-container {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* 让主内容区自动扩展并居中 */
|
||||
.el-main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 适配移动设备 */
|
||||
@media (max-width: 640px) {
|
||||
.max-w-2xl {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.cell-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.margin-top {
|
||||
margin-top: 20px !important;
|
||||
}
|
||||
</style>
|
@ -221,8 +221,10 @@ const fetchLastExam = async () => {
|
||||
const examData = await window.electronAPI.fetchLastExam()
|
||||
// console.log('获取考试信息成功:', examData)
|
||||
lastExam.value = examData
|
||||
// 将考试信息保存到store中
|
||||
userStore.setExam(examData)
|
||||
console.log('信息:', lastExam.value)
|
||||
// 解析考试须知数组 - 注意:根据控制台日志,exam_notice已经是数组,不需要再JSON.parse
|
||||
// 解析考试须知数组
|
||||
if (lastExam.value && lastExam.value.exam_notice) {
|
||||
examNotices.value = lastExam.value.exam_notice
|
||||
} else {
|
||||
@ -298,6 +300,8 @@ const startExam = async () => {
|
||||
|
||||
if (result.success) {
|
||||
console.log('生成试卷成功:', result)
|
||||
// 保存试卷数据到store
|
||||
userStore.setPaper(result.data)
|
||||
ElMessageBox.alert(
|
||||
'已完成组卷,点击"进入考试"开始答题',
|
||||
'组卷完成',
|
||||
@ -306,7 +310,11 @@ const startExam = async () => {
|
||||
type: 'success'
|
||||
}
|
||||
).then(() => {
|
||||
router.push('/examinee/examing')
|
||||
// 使用命名路由传递参数
|
||||
router.push({
|
||||
name: 'examinee-examing',
|
||||
params: { paperId: result.data.id }
|
||||
})
|
||||
})
|
||||
} else {
|
||||
console.error('生成试卷失败:', result)
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user