Bladeren bron

重新识别更新 客观题重新识别更新

dengshaobo 1 maand geleden
bovenliggende
commit
eaabd410a3

+ 19 - 1
src/views/exam/abnormal/tableList.vue

@@ -315,6 +315,7 @@
         </div>
     </div>
     <div class="page_dialog">
+        <ReIdentify v-model="isReIdentify" :reIdentifyTotal="reIdentifyTotal" justObjective="1" :schoolInfo="selectSchoolInfo"  @ReIdentifyComplete="RefreshList"></ReIdentify>
         <PaperPreview v-model="showPaperPreview" :imageList="previewImageList" :showDraw="true" :answerData="previewAnswerData"></PaperPreview>
     </div>
   </div>
@@ -328,6 +329,7 @@ import {deleteAnswerCard, getExamStudentList,updateScannedStatus,updateExamNumbe
 import { ElMessageBox, ElMessage } from 'element-plus'
 import PaperPreview from '../components/PaperPreview.vue'//图片预览组件
 import ActionImage from '@/components/ActionImage.vue'// 画布图片组件
+import ReIdentify from '@/views/exam/components/ReIdentify.vue';//重新识别弹窗
 // 实例化 Store
 const examStore = useExamStore()
 const userStore = useUserStore()
@@ -359,6 +361,7 @@ watch(() => props.scanState, (newState) => {
 
     console.log("扫描状态变更为",newState);
     pageInfo.value.pageNum=1;
+    showUploadReview.value=0;
     GetExamStudentList();//获取考生列表
 });
 
@@ -415,6 +418,13 @@ const previewImageList=ref<any[]>([]);//图片列表
 const previewAnswerData=ref<any[]>([]);//答案数据
 const currentTemplateList=ref<any[]>([]);//模板数据
 
+// 客观题重新识别
+const isReIdentify=ref(false);//打开重新识别弹窗
+const reIdentifyTotal=ref(0);//重新识别的总张数
+const selectSchoolInfo=ref({
+    schoolId:'',
+    schoolName:''
+});//学校信息
 // 修改后:显式声明类型为 any[],或者定义具体的 Interface
 interface TreeNode {
   id: string | number;
@@ -538,9 +548,17 @@ const AllMarkedMiss=async()=>{
 
 }
 
+//重新识别客观题
+const OpenReldentify=()=>
+{
+    isReIdentify.value=true;
+    reIdentifyTotal.value=studentList.value.length;
+
+}
+
 //刷新列表
 const RefreshList=()=>{
-
+    GetExamScanList();
 }
 
 /**

+ 20 - 10
src/views/exam/components/ReIdentify.vue

@@ -29,7 +29,7 @@
                         </div>
                     </div>
                     <div class="identify_progress">
-                        <span>识别进度:</span>
+                        <span>识别进度</span>
                         <el-progress 
                             :percentage="reIdentifyProgress" 
                             :stroke-width="16" 
@@ -128,7 +128,7 @@ const examStore = useExamStore()
 // const scanLoading = ref(false);                      // 扫描按钮loading状态
 
 // --- 学校信息 ---
-const schoolId = ref('');        // 当前学校ID
+// const schoolId = ref('');        // 当前学校ID
 const schoolName = ref('');      // 当前学校名称(带冒号后缀)
 
 // --- 重新识别相关 ---
@@ -175,6 +175,10 @@ const examSubjectId = computed(() => {
   return examStore.currentExam?.id
 })//计算属性
 
+const schoolId = computed(() => {
+    return userStore.userInfo.schoolId;
+});
+
 /**
  * 剩余未上传完成的文件数量
  * 当前组件未使用,已注释
@@ -225,7 +229,7 @@ watch(
     (newVal) => {
         console.log("监听到学校信息的改变了", newVal);
         if (newVal) {
-            schoolId.value = newVal.schoolId || '';
+            // schoolId.value = newVal.schoolId || '';
             schoolName.value = newVal.schoolName ? newVal.schoolName + ':' : '';
         }
     },
@@ -272,18 +276,18 @@ const ReIdentifyWebSocketLink = () => {
 
     // 构建 WebSocket 用户标识:AGAIN_ + 科目ID
     let userCourseId = '';
-    console.log("打印用户信息", store.state.user.userInfo);
+    console.log("打印用户信息", userStore.userInfo);
     userCourseId = "AGAIN_" + examSubjectId.value;
     reIdentifyUserId.value = userCourseId;
     console.log("打印重新识别的userCourseId", userCourseId);
-
+    console.log("import.meta.env.NODE_ENV", import.meta.env.NODE_ENV);
     // 根据环境设置 WebSocket URL
-    if (process.env.NODE_ENV === 'development') {
+    if (import.meta.env.MODE === 'development') {
         // 开发环境使用固定地址
         websocketUrl.value = 'wss://dev3.k12100.net/teaching/api/v1/teaching/websocket/';
-    } else if (process.env.NODE_ENV === 'production') {
+    } else if (import.meta.env.MODE === 'production') {
         // 生产环境使用环境变量
-        websocketUrl.value = process.env.VUE_APP_WEB_SOCKET_URL || '';
+        websocketUrl.value = import.meta.env.VUE_APP_WEB_SOCKET_URL || '';
     }
 
     // 拼接完整的 WebSocket URL
@@ -322,13 +326,19 @@ const StartReIdentify = () => {
         examSubjectId: examSubjectId.value,        // 考试科目ID
         recognizeNumber: props.reIdentifyTotal,    // 需要识别的总张数
         justObjective: props.justObjective,        // 是否只识别客观题
-        schoolId: props.schoolInfo.schoolId        // 学校ID
+        schoolId: schoolId.value        // 学校ID
     };
 
     // 调用重新识别接口
     recognizeAgain(param).then(res => {
         console.log("重新识别结果", res);
-        if (res.code !== 200) {
+        reIdentifyLoading.value = false;
+        if (res.code == 200) {
+            ElMessage.success("重新识别完成!");
+        }
+        else
+        {   
+            
             ElMessage.error("重新识别失败!" + res.msg);
         }
     }).catch(err => {

+ 141 - 241
src/views/exam/components/scanButton.vue

@@ -1,254 +1,154 @@
 <template>
      <div class="canvas_button">
-        <canvas id="canvasProcess" height="180" width="180"></canvas>
+        <canvas ref="canvasRef" id="canvasProcess" height="180" width="180"></canvas>
         <div class="canvas_cr"></div>
-        <img src="../../../assets/icon/scan_button_bg.png" v-if="showButton">
+        <!-- <img src="@/assets/icon/scan_button_bg.png" v-if="showButton"> -->
+        <!-- 2. 使用 :src 绑定导入的变量 -->
+        <img :src="scanButtonBg" v-if="showButton">
      </div>
 </template>
 
-<script>
-
-export default {
-    name: 'scanButton',
-
-    props: {
-        process: {
-            type: Number,
-            default: 10
-        },
-        quekao: {
-            type: Number,
-            default: 20
-        },
-        yichang: {
-            type: Number,
-            default: 40
-        }
-    },
-    watch: {
-        yichang(){
-            // console.log("异常数值变化了",this.yichang);
-            // console.log("打印进度值",this.process,this.quekao,this.yichang);
-        },
-    },
-    data () {
-        return {
-            canvas: null,
-            scale: 1,
-            circle:0,
-            id: '',
-
-            animationSpeed:1,
-            showButton:true
-        }
-    },
-    mounted() {
-        // this.canvas = document.getElementById('canvasScanButton')
-        this.DrawCanvas();//画布开始
-        // this.animations()
+<script setup>
+import { ref, onMounted, onBeforeUnmount, watch } from 'vue';
+import scanButtonBg from '@/assets/icon/scan_button_bg.png';
+const props = defineProps({
+    process: {
+        type: Number,
+        default: 10
     },
-    beforeDestroy () {
-        cancelAnimationFrame(this.id);//取消注册请求动画id 通过取消动画帧请求,可以停止正在进行的动画,防止不必要的计算和渲染,从而节省资源和提高性能。
+    quekao: {
+        type: Number,
+        default: 20
     },
-    methods: {
-
-        handleAnimation: function(anim) {
-            this.anim = anim;
-            this.anim.setSpeed(this.animationSpeed);
-            // 可以在这里添加更多的动画控制逻辑
-        },
-
-        //画一个环行进度条圆圈
-        DrawCanvas()
-        {
-
-            
-            this.canvas=document.getElementById('canvasProcess');
-            if(this.canvas==null)
-            {
-                return;
-            }
-            let ctx=this.canvas.getContext('2d');
-            //创建一个圆锥渐变对象
-            let g = ctx.createConicGradient(0, 55, 55);
-            //添加颜色停止点
-            g.addColorStop(0,'blue')
-            g.addColorStop(1,'white')
-            ctx.clearRect(0,0,this.canvas.width,this.canvas.height);//清除指定矩形区域内的所有像素
-            ctx.save();//保存当前绘图状态
-            ctx.translate(this.canvas.width / 2, this.canvas.height / 2);//将原点移动到画布的中心
-
-             //抖动
-            // this.scale = this.scale + 0.002
-            // ctx.scale(this.scale, this.scale)
-            // if (this.scale >= 1.05) {
-            //     this.scale = 0.9998
-            // }
-            // // 圆底
-            ctx.translate(-this.canvas.width / 2, -this.canvas.height / 2)//将原点移动到画布的中心
-            ctx.beginPath();//开始路径
-            ctx.save();//保存当前绘图状态
-            ctx.arc(90,90,75,0,2 * Math.PI);//绘制一个圆形,圆心在90,90原点上 半径为80像素
-            ctx.shadowColor = "#4D2EFA";//描边颜色
-            ctx.shadowBlur = 10;//描边粗细
-            ctx.fillStyle = '#ffffff';//底部背景色
-            ctx.fill();//填充
-            ctx.restore();//恢复之前保存的绘图状态
-            ctx.closePath();//闭合路径
-
-            // 绘制进度环轨道
-            ctx.beginPath();//开始路径
-            ctx.lineWidth = 10;//进度环宽度
-            ctx.strokeStyle = '#EAF0FF';//进度环轨道颜色值
-            ctx.arc(90,90,75,0,2*Math.PI);//绘制进度环圆形 圆心在90 90上半径为75像素
-            ctx.stroke();//描边
-            ctx.closePath();//闭合路径
-
-            // 进度环
-            //绿色进度环
-            ctx.beginPath()
-            ctx.lineWidth = 10;//进度条宽度
-            ctx.strokeStyle = '#2BC644';//进度条颜色值
-            ctx.arc(90,90,75, -90 * Math.PI / 180,((this.process.toFixed(0) / 100)*360 - 90)*Math.PI/180);//绘制进度条弧度 圆心在90 90 半径为75像素
-            ctx.stroke()
-            ctx.closePath();//闭合路径
-
-            //异常进度环
-            ctx.beginPath()
-            ctx.strokeStyle = '#F56C6C';//异常进度条颜色值
-            ctx.arc(90,90,75,((this.process.toFixed(0) / 100)*360 - 90)*Math.PI/180,((this.yichang.toFixed(0) / 100)*360 + ((this.process.toFixed(0) / 100)*360 - 90))*Math.PI/180)
-            ctx.stroke()
-            ctx.closePath()
-
-            //缺考进度环
-            ctx.beginPath()
-            ctx.strokeStyle = '#FB9F34'//缺考颜色值
-            ctx.arc(90,90,75,
-            ((this.yichang.toFixed(0) / 100)*360 + ((this.process.toFixed(0) / 100)*360 - 90))*Math.PI/180,
-            ((this.quekao.toFixed(0) / 100)*360 + (this.yichang.toFixed(0) / 100)*360 + ((this.process.toFixed(0) / 100)*360 - 90))*Math.PI/180)
-            ctx.stroke();
-            ctx.closePath();
-
-            // 扫描文字
-            ctx.beginPath()
-            ctx.font = "20px bold"
-            ctx.textAlign = 'center'
-            ctx.fillStyle = '#333333';//文字颜色值
-            ctx.fillText('开始扫描',90,120);//扫描的位置
-            ctx.closePath()
-            // 扫描百分比
-            ctx.beginPath()
-            ctx.font = "32px bold";
-            ctx.textAlign = 'center'
-            ctx.fillStyle = '#2E64FA';//扫描百分比颜色值
-            ctx.fillText(this.FormatProcess(this.process) + '%',90,90)
-            ctx.closePath()
-            ctx.restore()
-            // console.log("打印进度值",this.process,this.quekao,this.yichang);
-            // 请求下一帧
-            this.id = requestAnimationFrame(this.DrawCanvas);
-            
-        },
-
-        // 格式化进度显示:如果小数部分为0则不显示,否则显示一位小数
-        FormatProcess(process) 
-        {
-            // 1. 检查是否为有效数字
-            if (process === null || process === undefined || isNaN(process) || !isFinite(process)) {
-                return 0;
-            }
-
-            // 2. 确保是数字类型(防止字符串等意外类型)
-            const num = Number(process);
-
-            // 3. 再次校验转换后的结果
-            if (isNaN(num)) {
-                return 0;
-            }
-
-            // 4. 格式化逻辑
-            if (num % 1 === 0) {
-                // 如果是整数,直接返回整数
-                return num;
-            } else {
-                // 如果有小数部分,保留两位小数(根据原代码逻辑是 toFixed(2))
-                // 注意:toFixed 返回的是字符串,如果需要数字可以加 +parseFloat(),但通常用于展示字符串即可
-                return parseFloat(num.toFixed(2)); 
-            }
-        },
-        animations () {
-            this.canvas=document.getElementById('canvasProcess');
-            let ctx = this.canvas.getContext('2d')
-            //创建一个圆锥渐变对象
-            let g = ctx.createConicGradient(0, 90, 90);
-            //添加颜色停止点
-            g.addColorStop(0,'blue')
-            g.addColorStop(1,'white')
-            ctx.clearRect(0,0,this.canvas.width,this.canvas.height);//清除指定矩形区域内的所有像素
-            ctx.save();//保存当前绘图状态
-            ctx.translate(this.canvas.width / 2, this.canvas.height / 2);//将原点移动到画布的中心
+    yichang: {
+        type: Number,
+        default: 40
+    }
+});
+
+const canvasRef = ref(null);
+const animationId = ref(null);
+const showButton = ref(true);
+const animationSpeed = ref(1);
+const anim = ref(null);
+
+// 格式化进度显示
+const FormatProcess = (process) => {
+    if (process === null || process === undefined || isNaN(process) || !isFinite(process)) {
+        return 0;
+    }
+    const num = Number(process);
+    if (isNaN(num)) {
+        return 0;
+    }
+    if (num % 1 === 0) {
+        return num;
+    } else {
+        return parseFloat(num.toFixed(2)); 
+    }
+};
 
-            //抖动
-            // this.scale = this.scale + 0.002
-            // ctx.scale(this.scale, this.scale)
-            // if (this.scale >= 1.05) {
-            //     this.scale = 0.9998
-            // }
-            // 圆底
-            ctx.translate(-this.canvas.width / 2, -this.canvas.height / 2)
-            ctx.beginPath()
-            ctx.save()
-            ctx.arc(125,125,100,0,360 * Math.PI / 180)
-            ctx.shadowColor = "#4D2EFA";
-            ctx.shadowBlur = 15;
-            ctx.fillStyle = '#ffffff';//底部背景色
-            ctx.fill()
-            ctx.restore()
-            ctx.closePath()
-            // 进度环底边
-            ctx.beginPath()
-            ctx.lineWidth = 20
-            ctx.strokeStyle = '#D1E0FF';//进度环轨道颜色值
-            ctx.arc(125,125,85,0,360*Math.PI/180)
-            ctx.stroke()
-            ctx.closePath()
-            // 进度环
-            ctx.beginPath()
-            ctx.lineWidth = 20
-            ctx.strokeStyle = '#2BC644';//进度条颜色值
-            ctx.arc(125,125,85,-90 * Math.PI / 180,((this.process.toFixed(0) / 100)*360 - 90)*Math.PI/180)
-            ctx.stroke()
-            ctx.closePath()
-            ctx.beginPath()
-            ctx.strokeStyle = 'red'
-            ctx.arc(125,125,85,((this.process.toFixed(0) / 100)*360 - 90)*Math.PI/180,((this.yichang.toFixed(0) / 100)*360 + ((this.process.toFixed(0) / 100)*360 - 90))*Math.PI/180)
-            ctx.stroke()
-            ctx.beginPath()
-            ctx.strokeStyle = '#FB9334'//缺考颜色值
-            ctx.arc(125,125,85,
-            ((this.yichang.toFixed(0) / 100)*360 + ((this.process.toFixed(0) / 100)*360 - 90))*Math.PI/180,
-            ((this.quekao.toFixed(0) / 100)*360 + (this.yichang.toFixed(0) / 100)*360 + ((this.process.toFixed(0) / 100)*360 - 90))*Math.PI/180)
-            ctx.stroke()
-            ctx.closePath()
-            // 扫描文字
-            ctx.beginPath()
-            ctx.font = "20px bold"
-            ctx.textAlign = 'center'
-            ctx.fillStyle = '#333333';//文字颜色值
-            ctx.fillText('开始扫描',125,155);//扫描的位置
-            ctx.closePath()
-            // 扫描百分比
-            ctx.beginPath()
-            ctx.font = "32px bold";
-            ctx.textAlign = 'center'
-            ctx.fillStyle = '#2E64FA';//扫描百分比颜色值
-            ctx.fillText(this.process.toFixed(0) + '%',125,125)
-            ctx.closePath()
-            ctx.restore()
-            this.id = requestAnimationFrame(this.animations)
-        }
+const handleAnimation = (animObj) => {
+    anim.value = animObj;
+    if (anim.value) {
+        anim.value.setSpeed(animationSpeed.value);
     }
-}
+};
+
+const DrawCanvas = () => {
+    const canvas = canvasRef.value;
+    if (!canvas) return;
+
+    const ctx = canvas.getContext('2d');
+    
+    // 清除画布
+    ctx.clearRect(0, 0, canvas.width, canvas.height);
+    
+    ctx.save();
+    ctx.translate(canvas.width / 2, canvas.height / 2);
+    ctx.translate(-canvas.width / 2, -canvas.height / 2);
+
+    // 圆底
+    ctx.beginPath();
+    ctx.save();
+    ctx.arc(90, 90, 75, 0, 2 * Math.PI);
+    ctx.shadowColor = "#4D2EFA";
+    ctx.shadowBlur = 10;
+    ctx.fillStyle = '#ffffff';
+    ctx.fill();
+    ctx.restore();
+    ctx.closePath();
+
+    // 绘制进度环轨道
+    ctx.beginPath();
+    ctx.lineWidth = 10;
+    ctx.strokeStyle = '#EAF0FF';
+    ctx.arc(90, 90, 75, 0, 2 * Math.PI);
+    ctx.stroke();
+    ctx.closePath();
+
+    // 绿色进度环
+    ctx.beginPath();
+    ctx.lineWidth = 10;
+    ctx.strokeStyle = '#2BC644';
+    const startAngle = -90 * Math.PI / 180;
+    const processEndAngle = ((props.process.toFixed(0) / 100) * 360 - 90) * Math.PI / 180;
+    ctx.arc(90, 90, 75, startAngle, processEndAngle);
+    ctx.stroke();
+    ctx.closePath();
+
+    // 异常进度环
+    ctx.beginPath();
+    ctx.strokeStyle = '#F56C6C';
+    const yichangEndAngle = ((props.yichang.toFixed(0) / 100) * 360 + ((props.process.toFixed(0) / 100) * 360 - 90)) * Math.PI / 180;
+    ctx.arc(90, 90, 75, processEndAngle, yichangEndAngle);
+    ctx.stroke();
+    ctx.closePath();
+
+    // 缺考进度环
+    ctx.beginPath();
+    ctx.strokeStyle = '#FB9F34';
+    const quekaoEndAngle = ((props.quekao.toFixed(0) / 100) * 360 + (props.yichang.toFixed(0) / 100) * 360 + ((props.process.toFixed(0) / 100) * 360 - 90)) * Math.PI / 180;
+    ctx.arc(90, 90, 75, yichangEndAngle, quekaoEndAngle);
+    ctx.stroke();
+    ctx.closePath();
+
+    // 扫描文字
+    ctx.beginPath();
+    ctx.font = "20px bold";
+    ctx.textAlign = 'center';
+    ctx.fillStyle = '#333333';
+    ctx.fillText('开始扫描', 90, 120);
+    ctx.closePath();
+
+    // 扫描百分比
+    ctx.beginPath();
+    ctx.font = "32px bold";
+    ctx.textAlign = 'center';
+    ctx.fillStyle = '#2E64FA';
+    ctx.fillText(FormatProcess(props.process) + '%', 90, 90);
+    ctx.closePath();
+    
+    ctx.restore();
+
+    // 请求下一帧
+    animationId.value = requestAnimationFrame(DrawCanvas);
+};
+
+onMounted(() => {
+    DrawCanvas();
+});
+
+onBeforeUnmount(() => {
+    if (animationId.value) {
+        cancelAnimationFrame(animationId.value);
+    }
+});
+
+watch(() => props.yichang, () => {
+    // console.log("异常数值变化了", props.yichang);
+    // console.log("打印进度值", props.process, props.quekao, props.yichang);
+});
 </script>
 
 <style lang="scss" scoped> 

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

@@ -630,7 +630,23 @@ const MessageBack = (data:any) => {
 
 //重新识别弹窗
 const OpenReIdentify=() => {
+    
+    //判断是否在扫描 
+    if(isScanning.value)
+    {
+        //正在扫描中 不可重新识别
+        ElMessage.error("正在扫描中,请等待扫描完成后再重新识别!");
+        return;
+    }
+    
+    //计算总识别张数
+    let sumTotal=0;
+    tableData.value.forEach((item:any) => {
+        sumTotal+=item.uploadNum;
+    });
     isReIdentify.value=true;
+    // reIdentifyNumber.value=sumTotal;
+    reIdentifyTotal.value=sumTotal;
 }
 
 //开始扫描

+ 1 - 0
vite.config.ts

@@ -14,6 +14,7 @@ export default defineConfig({
   server: {
     host: '0.0.0.0',//允许所有ip访问
     port: 8088,//默认端口
+    https:false,//是否开启https
     proxy:{
      
       '/api':{