소스 검색

异常处理界面更新

dengshaobo 3 주 전
부모
커밋
60428bf591
4개의 변경된 파일404개의 추가작업 그리고 39개의 파일을 삭제
  1. 369 12
      src/views/exam/abnormal/abnormal.vue
  2. 10 3
      src/views/exam/abnormalDetail.vue
  3. 7 6
      src/views/exam/scanDetail.vue
  4. 18 18
      src/views/exam/scanList.vue

+ 369 - 12
src/views/exam/abnormal/abnormal.vue

@@ -13,22 +13,22 @@
                     <div class="nav_number"  v-if="abnormalObj.examNumberErrorNum>0">{{ abnormalObj.examNumberErrorNum }}</div>
                     考号异常
                 </div>
-                <div class="nav_item" :class="abnormalType==7?'item_active':''" @click="AbnormalChanage(7)">
+                <!-- <div class="nav_item" :class="abnormalType==7?'item_active':''" @click="AbnormalChanage(7)">
                     <div class="nav_number"  v-if="abnormalObj.losePageErrorNum>0">{{ abnormalObj.losePageErrorNum }}</div>
                     缺页异常
-                </div>
+                </div> -->
                 <div class="nav_item" :class="abnormalType==4?'item_active':''" @click="AbnormalChanage(4)">
                     <div class="nav_number"  v-if="abnormalObj.objectErrorNum>0">{{ abnormalObj.objectErrorNum }}</div>
                     客观题异常
                 </div>
-                <div class="nav_item" :class="abnormalType==5?'item_active':''" @click="AbnormalChanage(5)">
+                <!-- <div class="nav_item" :class="abnormalType==5?'item_active':''" @click="AbnormalChanage(5)">
                     <div class="nav_number"  v-if="abnormalObj.choiceErrorNum>0">{{ abnormalObj.choiceErrorNum }}</div>
                     选做题异常
                 </div>
                 <div class="nav_item" :class="abnormalType==6?'item_active':''" @click="AbnormalChanage(6)" v-if="markType==1">
                     <div class="nav_number"  v-if="abnormalObj.subjectiveErrorNum>0">{{ abnormalObj.subjectiveErrorNum }}</div>
                     划分异常
-                </div>
+                </div> -->
             </div>
             <div class="nav_button el_button">
                 <div :class="isShowDraw?'is_draw_data':'is_draw_active'" @click="ShowDrawData()" v-if="abnormalType==4">显示画框</div>
@@ -72,7 +72,7 @@
                         </div>
                     </div>
                     <div class="content_canvas">
-                        <PositionCanvas ref="PaperCanvas" :usedCardType="usedCardType" :positionList="targetPoints"  :paperImgUrl="currentPaperUrl"  @GetCutPosition="GetCutStudentPosition" paperType="student" v-if="currentPaperUrl"> </PositionCanvas>
+                        <!-- <PositionCanvas ref="PaperCanvas" :usedCardType="usedCardType" :positionList="targetPoints"  :paperImgUrl="currentPaperUrl"  @GetCutPosition="GetCutStudentPosition" paperType="student" v-if="currentPaperUrl"> </PositionCanvas> -->
                     </div>
                 </div>
 
@@ -91,7 +91,7 @@
             <!-- 划分异常试卷区 -->
             <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>
+                    <!-- <ActionImage ref="ActionCanvas" :isDrag="true" :paperInfo="currentPageInfo"  :paperImgUrl="currentPaperUrl" :drawData="currentDrawData" :isAbnormal="true"></ActionImage> -->
                 </template>
                 <template v-else> 
                     
@@ -117,7 +117,7 @@
                                 <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>
+                                <!-- <MarkScore :drawData="item.reviewQuestionScoreList" :fullScore="item.fullScore" :score="item.score" :paperImgUrl="item.url" @GetClickItem="(score) => GetMarkScoreClickItem(score,item, index)"></MarkScore> -->
                             </div>
                         </div>
                     </div>
@@ -547,24 +547,381 @@
 <script lang="ts" setup>
 import { useExamStore } from '@/store/exam'
 import { useRouter } from 'vue-router'
-import { onMounted ,ref} from 'vue';
+import { onMounted, ref, computed, nextTick, watch } from 'vue';
+import { ElMessage } from 'element-plus'
+
+// 引入可能需要的 API (请根据实际路径调整)
+// import { getAbnormalList, updateAbnormalStatus, deletePaper } from '@/api/exam'
+
+// 引入子组件 (确保路径正确)
+// import PositionCanvas from './components/PositionCanvas.vue' // 假设路径
+// import ActionImage from './components/ActionImage.vue'       // 假设路径
+// import MarkScore from './components/MarkScore.vue'           // 假设路径
 
 // 实例化 Store
 const examStore = useExamStore()
 const router = useRouter()
 
+// ==================== 状态定义 ====================
+
+// 异常类型: 2-定位异常 3-考号异常 4-客观题异常 5-选做题异常 6-划分异常(空白卷) 7-缺页异常
+const abnormalType = ref(2)
+const markType = ref(0) // 0-网阅卡 1-手阅卡
+
+// 异常统计数据
+const abnormalObj = ref({
+    locationErrorNum: 0,   // 定位异常数
+    examNumberErrorNum: 0, // 考号异常数
+    losePageErrorNum: 0,   // 缺页异常数
+    objectErrorNum: 0,     // 客观题异常数
+    choiceErrorNum: 0,     // 选做题异常数
+    subjectiveErrorNum: 0  // 划分异常数
+})
+
+// 左侧导航/显示控制
+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[]>([]) // 底部缩略图列表
+const currentPageInfo = ref<any>({})    // 当前页面信息
+
+// 定位异常相关
+const usedCardType = ref(1) // 1-模板 2-学生
+const sourcePoints = ref<any[]>([]) // 模板点位
+const targetPoints = ref<any[]>([]) // 学生点位
+const currentTemplateList = ref<any[]>([]) // 模板页码列表
+
+// 右侧表格数据
+const positionData = ref({ pendingList: [] }) // 定位异常待处理
+const numberData = ref({ pendingList: [], processedList: [] }) // 考号异常
+const losePageData = ref({ pendingList: [] }) // 缺页异常
+const objectData = ref({ pendingList: [], processedList: [] }) // 客观题异常
+const choiceData = ref({ pendingList: [], processedList: [], choiceQuestion: [] }) // 选做题异常
+const subjectiveData = ref({ pendingList: [], processedList: [] }) // 划分异常
+
+// 搜索与查询
+const searchContent = ref('')
+const searchStudetList = ref<any[]>([])
+
+// 表格高度与Key
+const tableHeightRight = ref(200)
+const losePagetableHeight = ref(200)
+const searchTableHeight = ref(200)
+const objectTableHeight = ref(200)
+const subjectiveTableHeight = ref(200)
+const tableKey = ref(0)
+
+// 其他状态
+const rightTab = ref('pending') // pending | processed
+const reCutLoading = ref(false)
+const reCutText = ref('重新切割')
+const correctionLoading = ref(false)
+const subjectStudentIndex = ref(-1)
+const subjectStudentAbnormal = ref<any[]>([])
+const subjectStudentQuestion = ref<any[]>([])
+const questionTableData = ref<any[]>([])
+const subjectiveTableData = ref<any[]>([])
+const choiceHeader = ref([])
+
+// Canvas Refs
+const PositionCanvas = ref()
+const PaperCanvas = ref()
+const ActionCanvas = ref()
+
+// ==================== 计算属性 ====================
+
+// 示例:如果需要动态计算某些表格数据
+const pendingListComputed = computed(() => {
+    if (abnormalType.value === 2) return positionData.value.pendingList
+    if (abnormalType.value === 3) return numberData.value.pendingList
+    if (abnormalType.value === 7) return losePageData.value.pendingList
+    if (abnormalType.value === 4) return rightTab.value === 'pending' ? objectData.value.pendingList : objectData.value.processedList
+    if (abnormalType.value === 5) return rightTab.value === 'pending' ? choiceData.value.pendingList : choiceData.value.processedList
+    if (abnormalType.value === 6) return rightTab.value === 'pending' ? subjectiveData.value.pendingList : subjectiveData.value.processedList
+    return []
+})
+
+// ==================== 方法定义 ====================
+
+// 1. 切换异常类型
+const AbnormalChanage = (type: number) => {
+    abnormalType.value = type
+    // TODO: 加载对应类型的异常列表数据
+    console.log('切换异常类型:', type)
+}
+
+// 2. 刷新异常列表
+const RefreshAbnormalList = () => {
+    // TODO: 调用接口刷新当前 abnormalType 的数据
+    console.log('刷新列表')
+}
+
+// 3. 适应屏幕
+const FitScreen = () => {
+    // TODO: 调用 ActionImage 或 Canvas 组件的 fit 方法
+    console.log('适应屏幕')
+}
+
+// 4. 显示/隐藏画框 (客观题)
+const ShowDrawData = () => {
+    isShowDraw.value = !isShowDraw.value
+    // TODO: 更新 ActionImage 的 drawData 显示状态
+}
+
+// 5. 划分异常显示类型切换
+const SubjectDataChange = () => {
+    // TODO: 根据 isShowDrawType 重新渲染右侧列表或 Canvas
+    console.log('切换显示类型:', isShowDrawType.value)
+}
+
+// 6. 模板页码切换
+const ChangeTemplatePage = (item: any) => {
+    currentTemplatePageIndex.value = item.pageNum
+    // TODO: 加载对应页码的模板图片
+}
+
+// 7. 获取切割点位 (模板)
+const GetCutTemaplatePosition = (points: any[]) => {
+    sourcePoints.value = points
+    console.log('获取模板点位', points)
+}
+
+// 8. 获取切割点位 (学生)
+const GetCutStudentPosition = (points: any[]) => {
+    targetPoints.value = points
+    console.log('获取学生点位', points)
+}
+
+// 9. 图片旋转
+const AnticlockwiseImage = () => {
+    // TODO: 逆时针旋转
+    console.log('逆时针旋转')
+}
+const ClockwiseImage = () => {
+    // TODO: 顺时针旋转
+    console.log('顺时针旋转')
+}
+
+// 10. 标记为空白页
+const MarkBlankPage = () => {
+    // TODO: 调用接口标记当前试卷为空白页
+    console.log('标记空白页')
+}
+
+// 11. 保存定位信息
+const SavePositionImage = () => {
+    // TODO: 提交 sourcePoints 和 targetPoints 到后端
+    console.log('保存定位')
+}
+
+// 12. 底部缩略图切换
+const ChanageCurrentPaperUrl = (index: number, item: any) => {
+    currentPaperIndex.value = index
+    currentPaperUrl.value = item.recognizeUrl
+    currentPageInfo.value = item
+    // TODO: 加载新试卷的详细数据
+}
+
+// 13. 右侧表格行点击
+const PendingListRowClick = (row: any, column: any, event: Event) => {
+    // TODO: 高亮选中行,并加载该学生的试卷图片到左侧
+    console.log('点击行:', row)
+}
+
+// 14. 表格行样式
+const TableRowClassName = ({ row, rowIndex }: any) => {
+    // TODO: 根据 row 的状态返回 class 字符串
+    return ''
+}
+
+// 15. 获取批次号显示
+const GetPositionSelNumber = (row: any) => {
+    // TODO: 格式化批次号
+    return row.batchNo || '-'
+}
+
+// 16. 重新切割 (定位异常)
+const ReCutPaper = () => {
+    reCutLoading.value = true
+    // TODO: 调用重新切割接口
+    setTimeout(() => {
+        reCutLoading.value = false
+        ElMessage.success('切割成功')
+    }, 1000)
+}
+
+// 17. 删除当前试卷
+const DeleteCurrentPaper = () => {
+    // TODO: 二次确认后删除
+    console.log('删除试卷')
+}
+
+// 18. 考号异常 - 搜索学生
+const GetSearchStudent = () => {
+    // TODO: 根据 searchContent 搜索学生列表
+    console.log('搜索学生:', searchContent.value)
+}
+
+// 19. 考号异常 - 新增考生
+const OpenAddStudentDialog = () => {
+    // TODO: 打开新增弹窗
+    console.log('新增考生')
+}
+
+// 20. 考号异常 - 查看试卷
+const OpenViewPaper = (row: any) => {
+    // TODO: 预览该学生的试卷
+    console.log('查看试卷:', row)
+}
+
+// 21. 考号异常 - 认领
+const KaohaoClaimConfirm = (scope: any) => {
+    // TODO: 确认认领逻辑
+    console.log('认领:', scope.row)
+}
+
+// 22. 获取页数
+const GetPaperPageNum = (row: any) => {
+    return row.scanPictureVOS ? row.scanPictureVOS.length : 0
+}
+
+// 23. 标记为定位异常 (从考号/缺页转定位)
+const MarkPositionAbnormal = () => {
+    // TODO: 调用接口修改异常类型
+    console.log('标记为定位异常')
+}
+
+// 24. 标记为考号异常 (从缺页转考号)
+const MarkExamNumberAbnormal = () => {
+    // TODO: 调用接口修改异常类型
+    console.log('标记为考号异常')
+}
+
+// 25. 缺页删除
+const LosePageDelete = () => {
+    // TODO: 调用 delete_batch_pic 接口
+    console.log('缺页删除')
+}
+
+// 26. 切换待处理/已处理 Tab
+const ChangeTab = (tab: string) => {
+    rightTab.value = tab
+    // TODO: 可能需要重新加载数据或过滤
+}
+
+// 27. 清空选择 (客观题)
+const ClearValue = () => {
+    // TODO: 清空当前题目的选择
+    console.log('清空')
+}
+
+// 28. 客观题 - 选项转换辅助
+const GetLetterToNumber = (letter: string) => {
+    // A->1, B->2...
+    return letter.charCodeAt(0) - 64
+}
+const GetLetterToNumberTF = (letter: string) => {
+    // T/F 处理
+    return letter
+}
+
+// 29. 客观题 - 判断是否存在
+const IsCunzai = (selectValue: any, value: any) => {
+    // TODO: 判断 selectValue 中是否包含 value
+    return selectValue === value
+}
+
+// 30. 客观题 - 选择答案
+const ChooseAnswer = (row: any, value: any) => {
+    // TODO: 更新 row.selectValue
+    console.log('选择答案:', value)
+}
+
+// 31. 客观题校正完成
+const ObjectiveCheck = () => {
+    correctionLoading.value = true
+    // TODO: 提交客观题修正结果
+    setTimeout(() => {
+        correctionLoading.value = false
+        ElMessage.success('校正成功')
+    }, 1000)
+}
+
+// 32. 选做题 - 选择答案
+const ChoiceAnswer = (row: any, option: any) => {
+    // TODO: 更新选做题选择
+    console.log('选做选择:', option)
+}
+
+// 33. 选做题校正完成
+const ChoiceCheck = () => {
+    correctionLoading.value = true
+    // TODO: 提交选做题修正结果
+    setTimeout(() => {
+        correctionLoading.value = false
+        ElMessage.success('校正成功')
+    }, 1000)
+}
+
+// 34. 划分异常 - 得分点击
+const GetMarkScoreClickItem = (score: number, item: any, index: number) => {
+    // TODO: 处理主观题打分
+    console.log('打分:', score)
+}
+
+// 35. 划分异常 - 修改分数
+const ChangeSubjectScore = () => {
+    // TODO: 防抖提交分数修改
+    console.log('分数变更')
+}
+
+// 36. 划分异常校正完成
+const SubjectiveCheck = () => {
+    correctionLoading.value = true
+    // TODO: 提交主观题修正结果
+    setTimeout(() => {
+        correctionLoading.value = false
+        ElMessage.success('校正成功')
+    }, 1000)
+}
+
+// ==================== 生命周期 ====================
 
 onMounted(() => {
-  
     if (!examStore.currentExam) {
         console.warn('当前没有选中的考试信息')
-        // 可选:如果没有数据,可以重定向回列表页或提示用户
+    } else {
+        // TODO: 初始化加载异常统计数据
+        // LoadAbnormalStats()
+        // LoadAbnormalList(abnormalType.value)
     }
     
-  
+    // 监听窗口变化调整高度
+    window.addEventListener('resize', CalculateHeight)
+    CalculateHeight()
 })
+
+const CalculateHeight = () => {
+    nextTick(() => {
+        const h = window.innerHeight - 150
+        tableHeightRight.value = h > 200 ? h : 200
+        losePagetableHeight.value = h > 200 ? h : 200
+        // 其他高度同理
+    })
+}
+
 </script>
  
 <style lang="scss" scoped>
-
+.content_main
+{
+    height: 100% !important;
+}
 </style>

+ 10 - 3
src/views/exam/abnormalDetail.vue

@@ -23,9 +23,9 @@
             </div>
             <div class="detail_content">
                 <!-- 异常 -->
-                <!-- <Abnormal v-if="scanState == 3"></Abnormal> -->
+                <Abnormal v-if="scanState == 3"></Abnormal>
                 <!-- 状态  0  未扫描  1 已上传 2  缺考  3 异常 -->
-                <TableList :scanState="scanState"></TableList>
+                <TableList :scanState="scanState" v-else></TableList>
             </div>
         </div>
 
@@ -35,7 +35,7 @@
 import { useExamStore } from '@/store/exam'
 import { useUserStore } from '@/store/user'
 import { useRouter } from 'vue-router'
-import { onMounted ,ref,computed,onUnmounted,nextTick } from 'vue';
+import { onMounted ,ref,computed,onUnmounted,nextTick,watch } from 'vue';
 import { hasImportStudent,getBatchList,getCurrentBatchNo,deleteBatch,updateScanCount } from '@/api/exam'
 import { ElMessageBox, ElMessage } from 'element-plus'
 
@@ -51,6 +51,7 @@ const router = useRouter()
 // 定义 Props 和 Emits
 const props = defineProps<{
   modelValue: boolean,
+  scanState: number,//扫描状态
 }>()
 
 const emit = defineEmits<{
@@ -63,6 +64,12 @@ const showDialog = computed({
   set: (val) => emit('update:modelValue', val)
 })
 
+watch(() => props.scanState, (newState) => {
+    console.log("弹窗显示状态变更为",newState);
+    scanState.value = newState;
+});
+
+
 
 // 考试科目 ID
 const examSubjectId = computed(() => {

+ 7 - 6
src/views/exam/scanDetail.vue

@@ -132,7 +132,7 @@
 </template>
 <script lang="ts" setup>
 import { useExamStore } from '@/store/exam'
-import { useRouter } from 'vue-router'
+import { useRouter,useRoute  } from 'vue-router'
 import { onMounted ,ref,computed,nextTick,onUnmounted} from 'vue';
 import { ElMessageBox, ElMessage } from 'element-plus'
 
@@ -148,7 +148,7 @@ interface OptionItem {
 // 实例化 Store
 const examStore = useExamStore()
 const router = useRouter()
-
+const route = useRoute() // 2. 获取 route 实例
 // 考试科目 ID
 const examSubjectId = computed(() => {
   return examStore.currentExam?.id
@@ -375,11 +375,12 @@ const GetScanDetailImage = async () => {
 
 
 onMounted(() => {
-  
-    if (!examStore.currentExam) {
-        console.warn('当前没有选中的考试信息')
-        // 可选:如果没有数据,可以重定向回列表页或提示用户
+
+    // 3. 获取地址栏参数 batchNo 并赋值
+    if (route.query.batchNo) {
+        paramInfo.value.batchNo = route.query.batchNo as string;
     }
+    
     LoadData();//加载数据
     CalculateTableHeight();//初始化计算表格高度
     // 监听窗口大小变化

+ 18 - 18
src/views/exam/scanList.vue

@@ -75,7 +75,7 @@
                                 <i class="el-icon-loading"></i>{{loadingText}}……
                             </div>
                             <div class="ele_button table_row_button" v-else>
-                                <span class="btn_editor" @click="GotoDetail(-1)">详情</span>
+                                <span class="btn_editor" @click="GotoBatchDetail(scope.row.batchNo)">详情</span>
                                 <span class="btn_delete" v-if="scope.row.scanUserName==currentUserName " @click="OptionDelete(scope.row)">删除</span>
                                 <span class="editor_disable" v-else>删除</span>
                             </div>
@@ -153,7 +153,7 @@
         </div>
     </div>
     <SelectStudent v-model="showSelectStudent"  @success="StudentSuccess"></SelectStudent>
-    <AbnormalDetail v-model="showAbnormalDialog"></AbnormalDetail>
+    <AbnormalDetail v-model="showAbnormalDialog" :scanState="scanState"></AbnormalDetail>
   </div>
 </template>
 <script lang="ts" setup>
@@ -191,6 +191,7 @@ const currentUserName=computed(() => {
 
 const selectSchoolId=ref(0);//学校ID
 const showAbnormalDialog=ref(false);//异常弹窗
+const scanState = ref(0);//扫描状态//默认未扫描
 
 const params=ref({
     batchNo:'',
@@ -427,25 +428,24 @@ const OptionDelete=(row: any) => {
 const GotoDetail = (type: number) => {
 
     console.log('跳转到异常详情页', type);
+    scanState.value=type;
     // 根据类型跳转到不同的详情页
-    switch (type) {
-        case 0:
-            showAbnormalDialog.value=true;
-            break;
-        case 1:
-           
-            break;
-        case -1:
-            router.push({
-                path: '/exam/scanDetail',
-                query: {
-                    examSubjectId: examSubjectId.value,
-                },
-            })
-            break;
-        }
+    showAbnormalDialog.value=true;
+    
 }
 
+//跳转到批次详情页
+const GotoBatchDetail=(batchNo:any)=>{ 
+    router.push({
+        path: '/exam/scanDetail',
+        query: {
+            examSubjectId: examSubjectId.value,
+            batchNo: batchNo,
+        },
+    })
+}
+
+
 // 打开导入学生名单
 const OpenImportStudent = () => {
     showSelectStudent.value=true;