重构ExamingView和EndView,实现交卷预览

This commit is contained in:
chenqiang 2025-09-11 14:15:24 +08:00
parent 015885106d
commit 681e3fe273
6 changed files with 1610 additions and 463 deletions

View File

@ -1,5 +1,4 @@
// Preload script runs in a context that has access to both Node.js and browser APIs // Preload script runs in a context that has access to both Node.js and browser APIs
// 在preload.js文件中添加examingProcessPaper API并移除重复的fileGeneratePaperPdf
const { contextBridge, ipcRenderer } = require("electron"); const { contextBridge, ipcRenderer } = require("electron");
// 暴露API给渲染进程 // 暴露API给渲染进程

View File

@ -0,0 +1,96 @@
<template>
<div class="exam-top-bar rounded shadow-sm mb-2">
<div class="left-info">
<div class="info-item"><span class="label">考生姓名</span><span class="value">{{ examinee && examinee.examinee_name }}</span></div>
<div class="info-item"><span class="label">身份证号</span><span class="value">{{ formatIdCard(examinee && examinee.examinee_id_card) }}</span></div>
<div class="info-item"><span class="label">准考证号</span><span class="value">{{ examinee && examinee.examinee_admission_ticket }}</span></div>
</div>
<div class="right-info">
<div class="info-item"><span class="label">考试总分</span><span class="value">{{ paper && paper.paper_score }}</span></div>
<div class="info-item"><span class="label">总时长</span><span class="value">{{ paper && paper.paper_minutes }}分钟</span></div>
<div class="info-item"><span class="label">最小时长</span><span class="value">{{ paper && paper.paper_minutes_min }}分钟</span></div>
<div class="info-item timer"><span class="label">倒计时</span><span class="value">{{ countdown }}</span></div>
</div>
</div>
</template>
<script>
export default {
name: 'ExamingInfoBar',
props: {
examinee: {
type: Object,
default: null
},
paper: {
type: Object,
default: null
},
countdown: {
type: String,
default: '00:00:00'
}
},
methods: {
//
formatIdCard(idCard) {
if (!idCard || idCard.length !== 18) return idCard
return idCard.substring(0, 9) + '*****' + idCard.substring(14)
}
}
}
</script>
<style scoped>
.exam-top-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 20px;
background-color: #f8f9fa;
border: 1px solid #dee2e6;
}
.left-info, .right-info {
display: flex;
gap: 20px;
align-items: center;
}
.info-item {
display: flex;
align-items: center;
font-size: 14px;
}
.info-item .label {
color: #666;
margin-right: 5px;
}
.info-item .value {
color: #333;
font-weight: 500;
}
.info-item.timer .value {
color: #e74c3c;
font-weight: bold;
font-size: 16px;
}
/* 响应式设计 */
@media (max-width: 768px) {
.exam-top-bar {
flex-direction: column;
gap: 10px;
padding: 10px;
}
.left-info, .right-info {
flex-wrap: wrap;
gap: 0.5rem;
justify-content: center;
}
}
</style>

View File

@ -0,0 +1,612 @@
<template>
<div v-if="showPreviewModal" class="preview-modal-mask" @click="closeExamPreview">
<div class="preview-modal-container" @click.stop>
<div class="preview-modal-header">
<div class="preview-header-content">
<div class="preview-title">试卷预览</div>
<div class="preview-info-row">
<span class="preview-info-item">
<span class="preview-info-label">姓名</span>
<span class="preview-info-value">{{ examinee && examinee.examinee_name }}</span>
</span>
<span class="preview-info-item">
<span class="preview-info-label">身份证号</span>
<span class="preview-info-value">{{ formatIdCard(examinee && examinee.examinee_id_card) }}</span>
</span>
<span class="preview-info-item">
<span class="preview-info-label">准考证号</span>
<span class="preview-info-value">{{ examinee && examinee.examinee_admission_ticket }}</span>
</span>
<span class="preview-info-item">
<span class="preview-info-label">总题数</span>
<span class="preview-info-value">{{ questionList.length }}</span>
</span>
<span class="preview-info-item">
<span class="preview-info-label">答题数</span>
<span class="preview-info-value answered-count">{{ answeredCount }}</span>
</span>
<span class="preview-info-item">
<span class="preview-info-label">试卷满分</span>
<span class="preview-info-value">{{ paper && paper.paper_score }}</span>
</span>
</div>
</div>
<button class="close-btn" @click="closeExamPreview">×</button>
</div>
<div class="preview-modal-body">
<div class="preview-question-list">
<div v-for="(item, index) in previewQuestionData" :key="item.serial_no" class="preview-question-item">
<div class="preview-question-header">
<span class="preview-question-number"> {{ item.serial_no }} </span>
<span class="preview-question-type">
{{ item.question && item.question.type_info && item.question.type_info.item_name || '' }}
</span>
<span class="preview-question-status" :class="{
'answered': getQuestionStatus(item) === 'answered',
'partially-answered': getQuestionStatus(item) === 'partially-answered',
'unanswered': getQuestionStatus(item) === 'unanswered'
}">
{{ getQuestionStatusText(item) }}
</span>
</div>
<div class="preview-question-body">
<!-- 题干 - 添加分值显示 -->
<div class="preview-question-text">
<span v-html="item.question && item.question.question_description || ''"></span>
<span v-if="item.question_detail && item.question_detail.score" class="question-score-display">{{ item.question_detail.score }}</span>
</div>
<!-- 题目图片 -->
<div class="preview-question-images" v-if="item.question && item.question.images && item.question.images.length > 0">
<div v-for="(image, imgIndex) in item.question.images" :key="imgIndex" class="preview-question-image">
<img :src="image.image_base64" :alt="image.image_name" style="max-height:200px;max-width:400px;">
</div>
</div>
<!-- 题目数据集 -->
<div class="preview-question-datasets" v-if="item.question && item.question.datasets && item.question.datasets.length > 0">
<div v-for="(dataset, dataIndex) in item.question.datasets" :key="dataIndex" class="preview-question-dataset">
<h4>{{ dataset.dataset_name }}</h4>
<pre>{{ dataset.dataset_data }}</pre>
</div>
</div>
<!-- 问题详情和答案 -->
<div v-if="item.question_detail">
<!-- 选择题选项 -->
<div class="preview-question-options" v-if="item.question && item.question.question_type === 'choice'">
<div style="font-weight:bold; margin-bottom: 10px;" v-html="item.question_detail.choice_description || ''"></div>
<div class="preview-option-item" v-for="(option, oIndex) in item.question_detail.choice_options || []" :key="oIndex" :class="{ 'preview-selected': option.selected }">
<span class="preview-option-letter">{{ String.fromCharCode(65 + oIndex) }}</span>
<span class="preview-option-text" v-html="option.content || option"></span>
</div>
</div>
<!-- 填空题答案 -->
<div class="preview-question-answer" v-else-if="item.question && item.question.question_type === 'fill_blank'">
<p style="font-weight:bold" v-html="item.question_detail.blank_description || ''"></p>
<div class="preview-fill-answer" :class="{
'preview-fill-answer-unanswered': getQuestionStatus(item) === 'unanswered',
'preview-fill-answer-partially': getQuestionStatus(item) === 'partially-answered'
}">
<span class="answer-label">您的答案</span>
<span class="answer-content">{{ formatAnswerContent(item.question_detail.examinee_answers) }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="preview-modal-footer">
<el-button size="small" @click="closeExamPreview">返回</el-button>
<el-button type="danger" size="small" @click="confirmSubmitExam">确认交卷</el-button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'ExamingPreview',
components: {
ElButton: require('element-ui').Button
},
props: {
showPreviewModal: {
type: Boolean,
default: false
},
previewQuestionData: {
type: Array,
default: () => []
},
examinee: {
type: Object,
default: () => ({})
},
paper: {
type: Object,
default: () => ({})
},
questionList: {
type: Array,
default: () => []
},
answeredCount: {
type: Number,
default: 0
}
},
methods: {
//
formatIdCard(idCard) {
if (!idCard) return ''
// 64*
return idCard.substring(0, 6) + '********' + idCard.substring(14)
},
//
getQuestionStatus(item) {
// 使
if (item.question && item.question.question_type === 'fill_blank' && item.question_detail) {
const blankCount = item.question_detail.blank_count || 0
const examineeAnswers = item.question_detail.examinee_answers
const validAnswerCount = this.getValidAnswerCount(examineeAnswers)
if (validAnswerCount === 0) {
return 'unanswered' //
} else if (validAnswerCount < blankCount) {
return 'partially-answered' //
} else {
return 'answered' //
}
}
// 使
return item.answered === 1 ? 'answered' : 'unanswered'
},
//
getQuestionStatusText(item) {
const status = this.getQuestionStatus(item)
if (status === 'partially-answered') {
return '未完全作答'
} else if (status === 'answered') {
return '已作答'
} else {
return '未作答'
}
},
//
getValidAnswerCount(answer) {
if (!answer) return 0
//
if (typeof answer === 'string') {
const trimmed = answer.trim()
// 0
if (trimmed === '' || trimmed === '[]') {
return 0
}
// JSON
if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
try {
const parsed = JSON.parse(trimmed)
if (Array.isArray(parsed)) {
//
return parsed.filter(item => {
const itemStr = String(item || '')
return itemStr.trim() !== ''
}).length
}
} catch (e) {
//
return trimmed !== '' ? 1 : 0
}
}
//
return trimmed !== '' ? 1 : 0
}
//
else if (Array.isArray(answer)) {
//
return answer.filter(item => {
const itemStr = String(item || '')
return itemStr.trim() !== ''
}).length
}
//
return 0
},
//
isAnswerValid(answer) {
return this.getValidAnswerCount(answer) > 0
},
//
formatAnswerContent(answer) {
if (!this.isAnswerValid(answer)) {
return '' //
}
// JSON
if (typeof answer === 'string') {
try {
// JSON
if (answer.startsWith('[') && answer.endsWith(']')) {
const parsed = JSON.parse(answer)
if (Array.isArray(parsed)) {
//
const filteredAnswers = parsed.filter(item =>
item !== null && item !== undefined && String(item).trim() !== ''
)
return filteredAnswers.length > 0 ? filteredAnswers.join(', ') : ''
}
}
return answer
} catch (e) {
return answer
}
}
//
else if (Array.isArray(answer)) {
const filteredAnswers = answer.filter(item =>
item !== null && item !== undefined && String(item).trim() !== ''
)
return filteredAnswers.length > 0 ? filteredAnswers.join(', ') : ''
}
return String(answer || '')
},
//
closeExamPreview() {
this.$emit('close-preview')
},
//
confirmSubmitExam() {
this.$emit('confirm-submit')
}
}
}
</script>
<style scoped>
.preview-modal-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 2000;
}
.preview-modal-container {
background-color: white;
border-radius: 8px;
width: 90%;
max-width: 1200px;
max-height: 90vh;
display: flex;
flex-direction: column;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.preview-modal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 15px 20px;
background-color: #f5f7fa;
border-bottom: 1px solid #e4e7ed;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
flex-shrink: 0;
}
.preview-header-content {
flex: 1;
}
.preview-title {
font-size: 18px;
font-weight: bold;
color: #303133;
margin-bottom: 10px;
}
.preview-info-row {
display: flex;
flex-wrap: wrap;
gap: 15px;
}
.preview-info-item {
display: flex;
align-items: center;
font-size: 13px;
}
.preview-info-label {
color: #606266;
margin-right: 4px;
}
.preview-info-value {
color: #303133;
font-weight: 500;
}
.answered-count {
color: #007c11;
font-weight: bold;
}
.close-btn {
background: none;
border: none;
font-size: 24px;
color: #909399;
cursor: pointer;
width: 30px;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
transition: all 0.3s;
}
.close-btn:hover {
background-color: #f56c6c;
color: white;
}
.preview-modal-body {
flex: 1;
overflow-y: auto;
padding: 20px;
}
.preview-question-list {
display: flex;
flex-direction: column;
gap: 20px;
}
.preview-question-item {
border: 1px solid #e4e7ed;
border-radius: 8px;
padding: 15px;
background-color: #fff;
}
.preview-question-header {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 2px solid #e4e7ed;
}
.preview-question-number {
font-size: 16px;
font-weight: bold;
color: #303133;
}
.preview-question-type {
background-color: #ecf5ff;
color: #409eff;
padding: 2px 8px;
border-radius: 3px;
font-size: 12px;
}
.preview-question-status {
margin-left: auto;
padding: 4px 10px;
border-radius: 4px;
font-size: 12px;
font-weight: bold;
}
.preview-question-status.answered {
background-color: #f0f9ff;
color: #007c11;
border: 1px solid #9ffa7b;
}
.preview-question-status.partially-answered {
background-color: #fff3cd;
color: #856404;
border: 1px solid #ffc107;
}
.preview-question-status.unanswered {
background-color: #fff2f0;
color: #f56c6c;
border: 1px solid #ffbbb0;
}
.preview-question-body {
font-size: 14px;
line-height: 1.6;
color: #303133;
}
.preview-question-text {
margin-bottom: 15px;
white-space: pre-wrap;
word-wrap: break-word;
}
.preview-question-images {
margin-bottom: 15px;
}
.preview-question-image {
margin-bottom: 10px;
text-align: center;
}
.preview-question-image img {
max-width: 100%;
max-height: 300px;
border-radius: 4px;
border: 1px solid #e4e7ed;
}
.preview-question-datasets {
margin-bottom: 15px;
}
.preview-question-dataset {
margin-bottom: 10px;
}
.preview-question-dataset h4 {
font-size: 13px;
margin: 0 0 5px 0;
color: #606266;
}
.preview-question-dataset pre {
background-color: #f8f8f8;
padding: 8px;
border-radius: 4px;
border: 1px solid #e4e7ed;
font-size: 12px;
overflow-x: auto;
white-space: pre-wrap;
word-wrap: break-word;
}
.preview-question-options {
margin-top: 15px;
}
.preview-option-item {
display: flex;
align-items: flex-start;
padding: 10px 12px;
margin-bottom: 8px;
background-color: #f8f9fa;
border-radius: 4px;
border: 1px solid #e4e7ed;
}
.preview-option-item.preview-selected {
background-color: #bcffb3;
border-color: #007c11;
font-weight: bold;
}
.preview-option-letter {
display: inline-flex;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
background-color: #409eff;
color: white;
border-radius: 50%;
font-size: 11px;
font-weight: bold;
margin-right: 10px;
flex-shrink: 0;
}
.preview-option-item.preview-selected .preview-option-letter {
background-color: #006e25;
}
.preview-option-text {
flex: 1;
white-space: pre-wrap;
word-wrap: break-word;
font-size: 13px;
}
.preview-question-answer {
margin-top: 15px;
}
.preview-fill-answer {
background-color: #f0f9ff;
padding: 10px 15px;
border-radius: 4px;
border: 1px solid #9ffa7b;
margin-top: 10px;
}
.preview-fill-answer.preview-fill-answer-unanswered {
background-color: #fff3cd;
border-color: #ffc107;
}
.preview-fill-answer.preview-fill-answer-partially {
background-color: #fff3cd;
border-color: #ffc107;
}
.answer-label {
font-weight: bold;
color: #007c11;
margin-right: 8px;
}
.preview-fill-answer.preview-fill-answer-unanswered .answer-label,
.preview-fill-answer.preview-fill-answer-partially .answer-label {
color: #856404;
}
.answer-content {
color: #303133;
}
.preview-modal-footer {
display: flex;
justify-content: flex-end;
gap: 10px;
padding: 15px 20px;
background-color: #f5f7fa;
border-top: 1px solid #e4e7ed;
flex-shrink: 0;
}
/* 响应式设计补充 */
@media (max-width: 768px) {
.preview-modal-container {
width: 95%;
max-height: 95vh;
}
.preview-modal-body {
padding: 15px;
}
.preview-question-header {
flex-wrap: wrap;
}
.preview-question-status {
margin-left: 0;
width: 100%;
text-align: center;
}
}
</style>

View File

@ -0,0 +1,350 @@
<template>
<div v-if="questionList.length > 0">
<div class="question-header">
<span class="question-number"> {{ currentQuestion }} </span>
<span class="question-score">
<el-tag>
{{ currentQuestionData.question && currentQuestionData.question.type_info && currentQuestionData.question.type_info.item_name || '' }}
</el-tag>
({{ currentQuestionData.question_detail && currentQuestionData.question_detail.score || 0 }})
</span>
</div>
<div class="question-body">
<div class="question-text" v-html="currentQuestionData.question && currentQuestionData.question.question_description || ''"></div>
<!-- 题目图片 -->
<div class="question-images" v-if="currentQuestionData.question && currentQuestionData.question.images && currentQuestionData.question.images.length > 0">
<div v-for="(image, index) in currentQuestionData.question.images" :key="index" class="question-image">
<img :src="image.image_base64" :alt="image.image_name" @click="handleViewImage(image.image_base64)" style="max-height:300px;max-width:500px;">
</div>
</div>
<!-- 题目数据集 -->
<div class="question-datasets" v-if="currentQuestionData.question && currentQuestionData.question.datasets && currentQuestionData.question.datasets.length > 0">
<div v-for="(dataset, index) in currentQuestionData.question.datasets" :key="index" class="question-dataset">
<h4>{{ dataset.dataset_name }}</h4>
<pre>{{ dataset.dataset_data }}</pre>
</div>
</div>
<!-- 问题详情 -->
<div v-if="currentQuestionData.question_detail">
<!-- 选择题选项 -->
<div class="question-options" v-if="currentQuestionData.question && currentQuestionData.question.question_type === 'choice'">
<!-- 显示choice_description -->
<div style="font-weight:bold" v-html="currentQuestionData.question_detail.choice_description || ''"></div>
<div class="option-item" v-for="(option, oIndex) in currentQuestionData.question_detail.choice_options || []" :key="oIndex" :class="{ 'selected': option.selected }" @click="handleSelectOption(oIndex)">
<span class="option-letter">{{ String.fromCharCode(65 + oIndex) }}</span>
<span class="option-text" v-html="option.content || option"></span>
</div>
</div>
<!-- 填空题输入框 -->
<div class="question-answer" v-else-if="currentQuestionData.question && currentQuestionData.question.question_type === 'fill_blank'">
<!-- 显示fill_blank_description -->
<p style="font-weight:bold" v-html="currentQuestionData.question_detail.blank_description || ''"></p>
<input type="text" placeholder="请在此填写答案" v-model="currentQuestionData.question_detail.examinee_answers" @input="handleFillAnswerInput">
<p style="color: #9f9f9f; line-height: 200%">{{ blankAnswerTip }}</p>
</div>
</div>
</div>
<!-- 图片查看模态框 -->
<div v-if="showImageViewer" class="image-viewer-mask" @click="closeImageViewer">
<div class="image-viewer-container" @click.stop>
<img :src="currentImage" class="viewer-image">
<button class="close-btn" @click="closeImageViewer">关闭</button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'ExamingQuestionDetail',
components: {
ElTag: require('element-ui').Tag
},
props: {
currentQuestion: {
type: Number,
required: true
},
currentQuestionData: {
type: Object,
required: true
},
questionList: {
type: Array,
required: true
},
blankAnswerTip: {
type: String,
default: '数字请保留2位小数如"100.00"'
}
},
data() {
return {
showImageViewer: false,
currentImage: ''
}
},
methods: {
//
handleSelectOption(index) {
this.$emit('select-option', index)
},
//
handleFillAnswerInput() {
this.$emit('fill-answer-input')
},
//
handleViewImage(imageSrc) {
this.currentImage = imageSrc
this.showImageViewer = true
},
//
closeImageViewer() {
this.showImageViewer = false
}
}
}
</script>
<style scoped>
.question-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 20px;
background-color: #f8f9fa;
border-bottom: 1px solid #e9ecef;
margin-bottom: 20px;
}
.question-number {
font-size: 18px;
font-weight: bold;
color: #333;
}
.question-score {
display: flex;
align-items: center;
gap: 10px;
}
.question-body {
padding: 0 20px 20px;
}
.question-text {
font-size: 16px;
line-height: 1.8;
color: #333;
margin-bottom: 20px;
white-space: pre-wrap;
word-wrap: break-word;
}
.question-images {
margin-bottom: 20px;
}
.question-image {
margin-bottom: 15px;
text-align: center;
}
.question-image img {
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s ease;
}
.question-image img:hover {
border-color: #409eff;
box-shadow: 0 0 10px rgba(64, 158, 255, 0.3);
}
.question-datasets {
margin-bottom: 20px;
}
.question-dataset {
margin-bottom: 15px;
}
.question-dataset h4 {
font-size: 14px;
margin: 0 0 8px 0;
color: #666;
}
.question-dataset pre {
background-color: #f5f5f5;
padding: 10px;
border-radius: 4px;
border: 1px solid #ddd;
font-size: 13px;
overflow-x: auto;
white-space: pre-wrap;
word-wrap: break-word;
}
.question-options {
margin-top: 20px;
}
.option-item {
display: flex;
align-items: flex-start;
padding: 15px;
margin-bottom: 10px;
background-color: #f8f9fa;
border-radius: 4px;
border: 1px solid #e9ecef;
cursor: pointer;
transition: all 0.3s ease;
}
.option-item:hover {
background-color: #e9ecef;
border-color: #409eff;
}
.option-item.selected {
background-color: #e3f2fd;
border-color: #409eff;
font-weight: 500;
}
.option-item.selected .option-letter {
background-color: #006e25;
}
.option-letter {
display: inline-flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
background-color: #409eff;
color: white;
border-radius: 50%;
font-size: 12px;
font-weight: bold;
margin-right: 12px;
flex-shrink: 0;
}
.option-text {
flex: 1;
font-size: 14px;
line-height: 1.6;
white-space: pre-wrap;
word-wrap: break-word;
}
.question-answer {
margin-top: 20px;
}
.question-answer input {
width: 100%;
padding: 10px 15px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
margin-top: 10px;
transition: border-color 0.3s ease;
}
.question-answer input:focus {
outline: none;
border-color: #409eff;
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
}
/* 图片查看器样式 */
.image-viewer-mask {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: 2000;
cursor: pointer;
}
.image-viewer-container {
position: relative;
max-width: 90%;
max-height: 90vh;
cursor: default;
}
.viewer-image {
max-width: 100%;
max-height: 90vh;
border-radius: 4px;
}
.close-btn {
position: absolute;
top: -40px;
right: -40px;
width: 32px;
height: 32px;
background-color: rgba(255, 255, 255, 0.2);
border: none;
border-radius: 50%;
color: white;
font-size: 18px;
cursor: pointer;
transition: all 0.3s ease;
}
.close-btn:hover {
background-color: rgba(255, 255, 255, 0.3);
}
/* 响应式设计 */
@media (max-width: 768px) {
.question-header {
flex-direction: column;
align-items: flex-start;
gap: 10px;
padding: 10px 15px;
}
.question-body {
padding: 0 15px 15px;
}
.question-text {
font-size: 14px;
}
.option-item {
padding: 12px;
}
.close-btn {
top: -30px;
right: -30px;
width: 28px;
height: 28px;
font-size: 16px;
}
}
</style>

View File

@ -252,7 +252,7 @@ export default {
} }
}, },
// //
// checkAnswersAPI //
async checkAnswers () { async checkAnswers () {
try { try {
if (!this.paper || !this.paper.id) { if (!this.paper || !this.paper.id) {
@ -275,11 +275,24 @@ export default {
const result = await window.electronAPI.examingCheckPaperAnswers({ paperId }) const result = await window.electronAPI.examingCheckPaperAnswers({ paperId })
if (result && result.success) { if (result && result.success) {
// store // this.$message.success('');
// if (result.data) {
// this.$store.commit('setPaper', result.data) // PDF
// } try {
this.$message.success('判卷完成!'); //
const paperDataStr = JSON.stringify(this.paper);
// PDF
const pdfResult = await window.electronAPI.fileGeneratePaperPdf(paperDataStr);
if (pdfResult && pdfResult.filePath) {
this.pdfPath = pdfResult;
console.log('PDF生成成功保存路径:', pdfResult.filePath);
// this.$message.success('PDF');
} else {
console.error('PDF生成失败:', pdfResult);
}
} catch (pdfError) {
console.error('PDF生成过程异常:', pdfError);
}
} else { } else {
console.error('判卷失败:', result?.message || '未知错误'); console.error('判卷失败:', result?.message || '未知错误');
this.$message.error('判卷失败,请稍后重试'); this.$message.error('判卷失败,请稍后重试');

File diff suppressed because it is too large Load Diff