|
|
@@ -88,46 +88,12 @@
|
|
|
<div v-if="abnormalType==3 || abnormalType ==7 || abnormalType ==4 || abnormalType ==5" class="img_canvas_center">
|
|
|
<ActionImage ref="ActionCanvas" :isDrag="true" :paperInfo="currentPageInfo" :paperImgUrl="currentPaperUrl" :drawData="currentDrawData" :isAbnormal="true"></ActionImage>
|
|
|
</div>
|
|
|
- <!-- 划分异常试卷区 -->
|
|
|
- <div v-if="abnormalType==6" :class="isShowDrawType==1?'img_canvas_center':'mark_list_center'">
|
|
|
- <template v-if="isShowDrawType==1">
|
|
|
- <!-- <ActionImage ref="ActionCanvas" :isDrag="true" :paperInfo="currentPageInfo" :paperImgUrl="currentPaperUrl" :drawData="currentDrawData" :isAbnormal="true"></ActionImage> -->
|
|
|
- </template>
|
|
|
- <template v-else>
|
|
|
-
|
|
|
- <div class="mark_score_center mark_list" ref="abnormalList" v-if="isShowAbnormalQuestion">
|
|
|
- <div class="center_item" :id="`student-${item.id}`" :class="subjectStudentIndex==item.subjectiveIndex?'center_item_cur':''" v-for="(item,index) in subjectStudentAbnormal" :key="index">
|
|
|
- <div class="item_header">
|
|
|
- <div class="header_student_name">
|
|
|
- <span>{{item.questionName}} </span>
|
|
|
- </div>
|
|
|
- <div class="header_student_score">得分:{{item.score}}</div>
|
|
|
- </div>
|
|
|
- <div class="item_image">
|
|
|
- <MarkScore :drawData="item.reviewQuestionScoreList" :fullScore="item.fullScore" :score="item.score" :paperImgUrl="item.url" @GetClickItem="(score) => GetMarkScoreClickItem(score,item, index)"></MarkScore>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="mark_score_center mark_list" ref="allList" v-else>
|
|
|
- <div class="center_item" :id="`student-${item.id}`" :class="subjectStudentIndex==item.subjectiveIndex?'center_item_cur':''" v-for="(item,index) in subjectStudentQuestion" :key="index">
|
|
|
- <div class="item_header">
|
|
|
- <div class="header_student_name">
|
|
|
- <span>{{item.questionName}} </span>
|
|
|
- </div>
|
|
|
- <div class="header_student_score">得分:{{item.score}}</div>
|
|
|
- </div>
|
|
|
- <div class="item_image">
|
|
|
- <!-- <MarkScore :drawData="item.reviewQuestionScoreList" :fullScore="item.fullScore" :score="item.score" :paperImgUrl="item.url" @GetClickItem="(score) => GetMarkScoreClickItem(score,item, index)"></MarkScore> -->
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- </div>
|
|
|
+
|
|
|
</div>
|
|
|
<div class="page_jg"></div>
|
|
|
<div class="left_bottom" v-if="!(abnormalType==6 && isShowDrawType==2)">
|
|
|
<div class="bottom_draggable draggable_width_100" >
|
|
|
- <div v-for="(item,index) in studentPaperList" class="bottom_img_item" :class="currentPaperIndex == index?'img_item_cur':''" @click="ChanageCurrentPaperUrl(index, item)" :key="'paper_'+index">
|
|
|
+ <div v-for="(item,index) in currentPaperList" class="bottom_img_item" :class="currentPaperIndex == index?'img_item_cur':''" @click="ChanageCurrentPaperUrl(index, item)" :key="'paper_'+index">
|
|
|
<img style="width: 100%;height: 100%" :src="item.recognizeUrl" alt="" >
|
|
|
<div class="bottom_img_item_number" v-if="abnormalType==2">{{index+1}}</div>
|
|
|
<div class="bottom_img_item_number" v-else>
|
|
|
@@ -193,11 +159,10 @@
|
|
|
<el-table ref="numberPendingTable" @row-click="PendingListRowClick" :row-class-name="TableRowClassName" :data="numberData.pendingList" max-height="300" border stripe>
|
|
|
<el-table-column align="center" type="index" width="40" label="序号">
|
|
|
</el-table-column>
|
|
|
- <!-- <el-table-column align="center" prop="batchNo" width="45" label="批次"></el-table-column> -->
|
|
|
<el-table-column align="center" width="65" label="批次">
|
|
|
<template v-slot="scope">
|
|
|
{{GetPositionSelNumber(scope.row)}}
|
|
|
-
|
|
|
+
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column align="center" prop="studentName" width="80" label="姓名">
|
|
|
@@ -248,22 +213,6 @@
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <!-- <el-table-column align="center" prop="adminClassName" width="40" label="班级"></el-table-column> -->
|
|
|
- <!-- <el-table-column align="center" width="60" label="状态">
|
|
|
- <template v-slot="scope">
|
|
|
- <div class="row_scan_status">
|
|
|
- <div class="no_scan_btn" v-if="scope.row.scannedStatus == 0">
|
|
|
- 未扫描
|
|
|
- </div>
|
|
|
- <div class="yes_scan_btn" v-if="scope.row.scannedStatus == 1">
|
|
|
- 已扫描
|
|
|
- </div>
|
|
|
- <div class="repeat_scan_btn" v-if="scope.row.scannedStatus == 7">
|
|
|
- 重号
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- </el-table-column> -->
|
|
|
<el-table-column align="center" width="90" label="操作">
|
|
|
<template v-slot="scope">
|
|
|
<div class="row_scan_status">
|
|
|
@@ -547,15 +496,15 @@
|
|
|
<script lang="ts" setup>
|
|
|
import { useExamStore } from '@/store/exam'
|
|
|
import { useRouter } from 'vue-router'
|
|
|
-import { onMounted, ref, computed, nextTick, watch } from 'vue';
|
|
|
-import { ElMessage } from 'element-plus'
|
|
|
+import { onMounted,onUnmounted, ref, computed, nextTick, watch } from 'vue';
|
|
|
+import { ElMessage,ElMessageBox } from 'element-plus'
|
|
|
|
|
|
// 引入可能需要的 API (请根据实际路径调整)
|
|
|
-import { getExamAbnormalList, updateAbnormalStatus, deletePaper } from '@/api/exam'
|
|
|
+import { getExamAbnormalList,getSearchScanStudents,claimAnswerCard, updateAbnormalStatus, deletePaper } from '@/api/exam'
|
|
|
|
|
|
// 引入子组件 (确保路径正确)
|
|
|
// import PositionCanvas from './components/PositionCanvas.vue' // 假设路径
|
|
|
-// import ActionImage from './components/ActionImage.vue' // 假设路径
|
|
|
+import ActionImage from '@/components/ActionImage.vue'// 画布图片组件
|
|
|
// import MarkScore from './components/MarkScore.vue' // 假设路径
|
|
|
|
|
|
// 实例化 Store
|
|
|
@@ -601,15 +550,21 @@ const isShowDraw = ref(false) // 客观题是否显示画框
|
|
|
const isShowDrawType = ref(1) // 划分异常显示类型: 1-答题卡 2-划分区
|
|
|
const isShowAbnormalQuestion = ref(false) // 是否只显示异常题
|
|
|
|
|
|
-// 图片与Canvas相关
|
|
|
-const currentTemplateUrl = ref('')
|
|
|
-const currentPaperUrl = ref('')
|
|
|
-const currentImagePageNo = ref('')
|
|
|
-const currentPaperIndex = ref(0)
|
|
|
-const currentTemplatePageIndex = ref(0)
|
|
|
-const studentPaperList = ref<any[]>([]) // 底部缩略图列表
|
|
|
+// 图片与Canvas相关 试卷图片相关数据
|
|
|
+const currentIndex= ref(0);//当前表格学生索引
|
|
|
+const currentItem= ref<any>({});//当前表格学生数据
|
|
|
+const currentTemplateUrl = ref('')//试卷图片模板地址
|
|
|
+const currentPaperUrl = ref('')//试卷图片地址
|
|
|
+const currentImagePageNo = ref('')//当前图片页码
|
|
|
+const currentPaperIndex = ref(0)//当前图片索引
|
|
|
+const currentTemplatePageIndex = ref(0)////当前模板页索引
|
|
|
+const currentDrawData= ref<any[]>([]);//画框数据
|
|
|
+const currentPaperList = ref<any[]>([]) // 底部缩略图列表
|
|
|
const currentPageInfo = ref<any>({}) // 当前页面信息
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
// 定位异常相关
|
|
|
const usedCardType = ref(1) // 1-模板 2-学生
|
|
|
const sourcePoints = ref<any[]>([]) // 模板点位
|
|
|
@@ -625,8 +580,12 @@ const choiceData = ref({ pendingList: [], processedList: [], choiceQuestion: []
|
|
|
const subjectiveData = ref({ pendingList: [], processedList: [] }) // 划分异常
|
|
|
|
|
|
// 搜索与查询
|
|
|
-const searchContent = ref('')
|
|
|
-const searchStudetList = ref<any[]>([])
|
|
|
+const searchContent = ref('')//卡号异常搜索关键词
|
|
|
+const searchStudetList = ref<any[]>([])//考号异常搜索结果列表
|
|
|
+// 用于取消请求的控制器
|
|
|
+let searchAbortController: AbortController | null = null;
|
|
|
+const searchTimer=ref<number | null>(null);//搜索请求定时器;//搜索请求定时器
|
|
|
+const searchTimestamp=0;//search请求时间戳
|
|
|
|
|
|
// 表格高度与Key
|
|
|
const tableHeightRight = ref(200)//定位表格高度
|
|
|
@@ -673,7 +632,22 @@ const AbnormalChanage = (type: number) => {
|
|
|
abnormalType.value = type
|
|
|
// TODO: 加载对应类型的异常列表数据
|
|
|
console.log('切换异常类型:', type)
|
|
|
- GetAbnormalList();
|
|
|
+
|
|
|
+ //考号异常 3
|
|
|
+ if(type==3)
|
|
|
+ {
|
|
|
+ console.log('考号异常',numberData.value)
|
|
|
+ if(numberData.value.pendingList.length>0)
|
|
|
+ {
|
|
|
+ currentIndex.value=0;
|
|
|
+ currentItem.value=numberData.value.pendingList[currentIndex.value];//当前学生数据
|
|
|
+ currentPaperList.value=currentItem.value.scanPictureVOS || [];//试卷图片列表
|
|
|
+ currentPaperUrl.value=currentPaperList.value[0].recognizeUrl;//当前图片地址
|
|
|
+ currentImagePageNo.value=currentPaperList.value[0].pageNo;//当前图片的页码
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
// 2. 刷新异常列表
|
|
|
@@ -752,14 +726,56 @@ const ChanageCurrentPaperUrl = (index: number, item: any) => {
|
|
|
const PendingListRowClick = (row: any, column: any, event: Event) => {
|
|
|
// TODO: 高亮选中行,并加载该学生的试卷图片到左侧
|
|
|
console.log('点击行:', row)
|
|
|
+ if(abnormalType.value==2)
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+ //考号异常
|
|
|
+ if(abnormalType.value==3)
|
|
|
+ {
|
|
|
+ currentItem.value=row;
|
|
|
+
|
|
|
+ currentPaperList.value=currentItem.value.scanPictureVOS || [];//试卷图片列表
|
|
|
+ currentPaperUrl.value=currentPaperList.value[0].recognizeUrl;//当前图片地址
|
|
|
+ currentImagePageNo.value=currentPaperList.value[0].pageNo;//当前图片的页码
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// 14. 表格行样式
|
|
|
const TableRowClassName = ({ row, rowIndex }: any) => {
|
|
|
// TODO: 根据 row 的状态返回 class 字符串
|
|
|
+ //定位异常和考号异常 都以 wholePaperId 为判断条件
|
|
|
+ if(abnormalType.value==2 || abnormalType.value==3)
|
|
|
+ {
|
|
|
+ if(row.wholePaperId==currentItem.value.wholePaperId)
|
|
|
+ {
|
|
|
+ return 'selected_row'
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return ''
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //客观题异常 以id 为判断条件
|
|
|
+ if(abnormalType.value==4 )
|
|
|
+ {
|
|
|
+ if(row.id==currentItem.value.id)
|
|
|
+ {
|
|
|
+ return 'selected_row'
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return ''
|
|
|
+ }
|
|
|
+ }
|
|
|
return ''
|
|
|
}
|
|
|
|
|
|
+// 14. 客观题表格行样式
|
|
|
+const ObjectTableClassName=({ row, rowIndex }: any) => {
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
// 15. 获取批次号显示
|
|
|
const GetPositionSelNumber = (row: any) => {
|
|
|
// TODO: 格式化批次号
|
|
|
@@ -785,9 +801,76 @@ const DeleteCurrentPaper = () => {
|
|
|
// 18. 考号异常 - 搜索学生
|
|
|
const GetSearchStudent = () => {
|
|
|
// TODO: 根据 searchContent 搜索学生列表
|
|
|
- console.log('搜索学生:', searchContent.value)
|
|
|
+ console.log('考号搜索学生:', searchContent.value)
|
|
|
+ //清除之前的定时器
|
|
|
+ if(searchTimer.value)
|
|
|
+ {
|
|
|
+ clearTimeout(searchTimer.value);
|
|
|
+ }
|
|
|
+
|
|
|
+ //如果搜索的内容为空,清空结果并返回
|
|
|
+ if (!searchContent.value.trim()) {
|
|
|
+ searchStudetList.value = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 防抖处理:300ms 后执行搜索
|
|
|
+ searchTimer.value = setTimeout(() => {
|
|
|
+ GetSearchScanStudentList();
|
|
|
+ }, 300);
|
|
|
+
|
|
|
}
|
|
|
|
|
|
+// 搜索学生列表
|
|
|
+const GetSearchScanStudentList = async () => {
|
|
|
+ const keyword = searchContent.value.trim();
|
|
|
+
|
|
|
+ // 如果内容为空,清空列表并返回
|
|
|
+ if (!keyword) {
|
|
|
+ searchStudetList.value = [];
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ //1. 取消上一次未完成的请求
|
|
|
+ if (searchAbortController) {
|
|
|
+ searchAbortController.abort();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 创建新的 AbortController
|
|
|
+ searchAbortController = new AbortController();
|
|
|
+ const signal = searchAbortController.signal;
|
|
|
+
|
|
|
+ const param = {
|
|
|
+ examSubjectId: examSubjectId.value,
|
|
|
+ chooseCode:'2',//是学号还是考号
|
|
|
+ studentName: keyword,
|
|
|
+ schoolId: schoolId.value,
|
|
|
+ };
|
|
|
+
|
|
|
+ console.log("打印通用查询学生列表的参数", param);
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 3. 发起请求,传入 signal
|
|
|
+ const res = await getSearchScanStudents(param, { signal });
|
|
|
+
|
|
|
+ // 4. 处理成功响应
|
|
|
+ if (res.code === 200) {
|
|
|
+ searchStudetList.value = res.data || [];
|
|
|
+
|
|
|
+ }
|
|
|
+ } catch (error: any) {
|
|
|
+ // 5. 处理错误
|
|
|
+ if (error.name === 'CanceledError' || error.message === 'The operation was aborted.') {
|
|
|
+ // 请求被取消,通常不需要做任何操作,静默忽略
|
|
|
+ console.log('之前的搜索请求已取消');
|
|
|
+ } else {
|
|
|
+ console.error('搜索学生列表失败:', error);
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
// 19. 考号异常 - 新增考生
|
|
|
const OpenAddStudentDialog = () => {
|
|
|
// TODO: 打开新增弹窗
|
|
|
@@ -803,12 +886,60 @@ const OpenViewPaper = (row: any) => {
|
|
|
// 21. 考号异常 - 认领
|
|
|
const KaohaoClaimConfirm = (scope: any) => {
|
|
|
// TODO: 确认认领逻辑
|
|
|
- console.log('认领:', scope.row)
|
|
|
+ if (!currentItem.value?.wholePaperId) {
|
|
|
+ ElMessage.warning('请选择待处理的异常!')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ ElMessageBox.confirm('确定要认领为当前的学生吗?', '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning',
|
|
|
+ customClass: 'page_dialog',
|
|
|
+ }).then(async () => {
|
|
|
+ const pictureIds = currentItem.value.scanPictureVOS.map((item: any) => item.id);
|
|
|
+
|
|
|
+ const param = {
|
|
|
+ pictureIds: pictureIds,
|
|
|
+ studentScanId: scope.row.id,
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ const res = await claimAnswerCard(param);
|
|
|
+ console.log("打印认领返回结果", res);
|
|
|
+ if (res.code === 200) {
|
|
|
+ ElMessage({
|
|
|
+ type: 'success',
|
|
|
+ message: '认领成功'
|
|
|
+ })
|
|
|
+ searchContent.value = "";
|
|
|
+ searchStudetList.value = [];
|
|
|
+ console.log("打印当前选择的异常数据索引", currentIndex.value);
|
|
|
+ console.log("打印当前的数据", currentItem.value);
|
|
|
+
|
|
|
+ // TODO: 调用 GetAbnormalList 更新考号异常列表数据
|
|
|
+ GetAbnormalList();
|
|
|
+ } else {
|
|
|
+ ElMessage({
|
|
|
+ type: 'error',
|
|
|
+ message: res.msg + '!'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('认领失败:', error);
|
|
|
+ ElMessage({
|
|
|
+ type: 'error',
|
|
|
+ message: '认领失败,请重试'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }).catch(() => {
|
|
|
+ // 用户取消操作
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
// 22. 获取页数
|
|
|
const GetPaperPageNum = (row: any) => {
|
|
|
- return row.scanPictureVOS ? row.scanPictureVOS.length : 0
|
|
|
+ return row.scanPictureVOS ? row.scanPictureVOS.length : '-'
|
|
|
}
|
|
|
|
|
|
// 23. 标记为定位异常 (从考号/缺页转定位)
|
|
|
@@ -974,6 +1105,8 @@ const GetAbnormalList = async () => {
|
|
|
choiceErrorNum: choiceData.value.pendingList.length, // 选做题异常数量
|
|
|
subjectiveErrorNum: subjectiveData.value.pendingList.length, // 划分异常数量
|
|
|
};//异常数据
|
|
|
+ console.log("打印异常数据",abnormalObj.value);
|
|
|
+ console.log("打印考号异常数据",numberData);
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1002,7 +1135,21 @@ onMounted(() => {
|
|
|
// 监听窗口变化调整高度
|
|
|
window.addEventListener('resize', CalculateTableHeight)
|
|
|
CalculateTableHeight()
|
|
|
-})
|
|
|
+
|
|
|
+
|
|
|
+});
|
|
|
+// 组件卸载时清理,防止内存泄漏
|
|
|
+onUnmounted(() => {
|
|
|
+ if (searchAbortController) {
|
|
|
+ searchAbortController.abort();
|
|
|
+ }
|
|
|
+ //清除之前的定时器
|
|
|
+ if(searchTimer.value)
|
|
|
+ {
|
|
|
+ clearTimeout(searchTimer.value);
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
|
|
|
//计算表格高度
|
|
|
const CalculateTableHeight = () => {
|