소스 검색

我的考试扫描异常 考号异常认领功能更新

dengshaobo 6 일 전
부모
커밋
3fe1b2c63c
4개의 변경된 파일240개의 추가작업 그리고 73개의 파일을 삭제
  1. 19 0
      src/api/exam.ts
  2. 1 1
      src/components/ActionImage.vue
  3. 219 72
      src/views/exam/abnormal/abnormal.vue
  4. 1 0
      src/views/exam/scanList.vue

+ 19 - 0
src/api/exam.ts

@@ -273,4 +273,23 @@ export const getExamAbnormalList= (data:any):Promise<ApiResponse> => {
 }
 
 
+//扫描学生  考号异常搜索学生列表
+export const getSearchScanStudents= (data:any,config?: { signal?: AbortSignal }):Promise<ApiResponse> => {
+  return request({
+    url: '/api/v1/ai_exam_scan/find_scan_student_by_condition',
+    method: 'get',
+    params: data ,
+    ...config
+  })
+}
+
+//扫描学生  考号异常  认领答题卡
+export const claimAnswerCard= (data:any):Promise<ApiResponse> => {
+  return request({
+    url: '/api/v1/ai_exam_scan/claim_card',
+    method: 'post',
+    data
+  })
+}
+
 

+ 1 - 1
src/components/ActionImage.vue

@@ -144,7 +144,7 @@ const ShowDrawData = () => {
 // 初始数据加载
 const initData = () => {
   if (!mainContainerRef.value) return
-  
+  console.log('初始化数据加载图片地址信息',props.paperImgUrl)
   // 获取容器的宽高
   const { width, height } = mainContainerRef.value.getBoundingClientRect()
   containerHeight.value = Number(height)

+ 219 - 72
src/views/exam/abnormal/abnormal.vue

@@ -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 = () => {

+ 1 - 0
src/views/exam/scanList.vue

@@ -392,6 +392,7 @@ const OptionDelete=(row: any) => {
         ElMessageBox.confirm('确定要删除该批次吗?', '提示', {
             confirmButtonText: '确定',
             cancelButtonText: '取消',
+            customClass:'page_dialog',
             type: 'warning'
         }).then(() => {
             // 删除操作