|
|
@@ -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>
|