Parcourir la source

答题卡修改

liurongli il y a 5 mois
Parent
commit
e6dd5a2bd3

+ 492 - 256
src/components/PaperImage.vue

@@ -10,7 +10,7 @@
         <!-- 请先制作模版 -->
       </div>
       <div v-if="showContextMenu"  class="custom_context_menu"  :style="{ top: contextMenuY + 'px', left: contextMenuX + 'px' }" @click="hideContextMenu">
-        <div class="menu_item" @click="handleMenuAction('download')">图片另存为</div>
+        <div class="menu_item" @click="handleMenuAction('download')">图片另存为(放大后点另存可提高图片分率)</div>
         <div class="menu_item" @click="handleMenuAction('fitScreen')">适合屏幕</div>
         <div class="menu_item" @click="handleMenuAction('zoomIn')">放大(向上滚轮)</div>
         <div class="menu_item" @click="handleMenuAction('zoomOut')">缩小(向下滚轮)</div>
@@ -55,7 +55,15 @@ export default {
       type:Boolean,
       default:false
     },//是否异常处使用 区别 异常处理使用的地方 正常答案显示蓝色
-
+    usedCardType:{
+      type:Number,
+      default:2
+    },//默认三方卡  1 系统卡  2 三方卡
+
+    currentPage:{
+      type:Number,
+      default:1
+    },//当前页码 默认第一页
     downLoadName:{
       type:String,
       default:''
@@ -63,6 +71,10 @@ export default {
     imageIndex:{//图片索引
       type:[String,Number],
       default:''
+    },
+    scoreFontSize:{
+      type:Number,
+      default:50
     }
   },
   computed:{
@@ -97,7 +109,10 @@ export default {
         width:0,
         height:0
       },//画布的大小
-    
+      imageInfo:{
+        width:0,
+        height:0
+      },//原始图片的大小
       canvas:null,//画板canvas
       ctx:null,//画板上下文
 
@@ -146,6 +161,8 @@ export default {
       CacheHalfRight:new Image(),//缓存的半对图片
       CacheTypicalError:new Image(),//缓存的典型错误图片
       CacheExcellentAnswer:new Image(),//缓存的优秀答案图片
+      jHeight:0,//跨页的标注 需要减去的高度
+      blockList:[],//块列表
 
       
     }
@@ -155,7 +172,12 @@ export default {
     {
       handler(newVal, oldVal)
       {
-        this.InitData();//初始化数据
+         console.log("地址变化了",this.paperImgUrl);
+         if(this.paperImgUrl)
+         {
+          this.InitData();//初始化数据
+         }
+        
       },
       deep: true ,// 如果需要深度监听数组内部对象的变化
       listener: true//立即执行一次
@@ -436,184 +458,104 @@ export default {
     },
 
     //图片加载完成后绘制图片
-    drawImage() {
+    drawImage() 
+    {
       // if (this.image) {
         this.canvas=this.$refs.paperCanvas;
         let ctx = this.canvas.getContext('2d');
-        // ctx.imageSmoothingEnabled = false;//禁用图片平滑
-        // this.paperCtx.drawImage(this.image, 0, 0,this.canvasInfo.width,this.canvasInfo.height);
-        // 根据 devicePixelRatio 缩放图片
-        // ctx.drawImage(
-        //   this.image,
-        //   0, 0,
-        //   this.image.width, this.image.height,
-        //   0, 0,
-        //   this.canvasInfo.width, this.canvasInfo.height
-        // );
         ctx.clearRect(0, 0, this.canvasInfo.width, this.canvasInfo.height);//清除边框数据
         
         this.ImageInfoChange();//用image图片替代背景  是为了高清显示
         
         console.log("加载边框数据",this.drawData);
-        for(var i=0;i<this.drawData.length;i++)
+        this.DrawDataInfo();//加载边框数据
+    },
+
+
+    //绘制批注信息
+    DrawDataInfo()
+    {
+        let ctx = this.canvas.getContext('2d');
+       for(var i=0;i<this.drawData.length;i++)
         {
           let item=this.drawData[i];
-          const point=JSON.parse(item.samplingPosition);
-          var obj={
+          const point=JSON.parse(item.samplingPosition);//原始采分点的坐标
+          
+          console.log("打印point",point);
+          console.log("打印卡类型",this.usedCardType);
+          let blockPoint='';//切块的坐标
+          let blockList=[];//跨页的后面的页的y坐标需要减去的高度
+          let jHeight=0;//跨页的标注 需要减去的高度
+          let obj={
             x:point.x*this.zoomRate*this.scale,
             y:point.y*this.zoomRate*this.scale,
-          }
-          //如果是批阅块的坐标 需要相加
-          if(item.pagePaintingVOS)
-          {
-            console.log("打印item",item);
-            // let pageItem = item.pagePaintingVOS.find(item => item.page == point.page);
-            const pointIndex=point.index || 0;//默认0
-            let pageItem = item.pagePaintingVOS[pointIndex];
-            // item.pagePaintingVOS.forEach((item,index) => { 
-            //   if(index==point.index && item.page == point.page)
-            //   {
-            //     pageItem=item;
-            //   }
-            // });
-            //需要同时根据索引和页面查找
-            // const pageItem = item.pagePaintingVOS.find(item => item.page == point.page && item.index == point.index);
-            console.log("打印pageItem",pageItem);
+          };//采分点的坐标
 
-            if (pageItem) {
-              obj.x = (pageItem.x + point.x) * this.zoomRate * this.scale;
-              obj.y = (pageItem.y + point.y) * this.zoomRate * this.scale;
+          if(this.usedCardType==1)
+          {
+            // 如果是系统卡需要特殊处理 需要将坐标转成系统卡的坐标 并且需要去掉上下左右的边框
+            console.log("打印this.paperImgInfo",this.paperImgInfo);
+            console.log("如果是系统卡需要特殊处理",item);
+            let templateInfo={
+              width:794-30*2,//减去左右的边距
+              height:1123-25*2//减去上下的边距
+            };//模板去掉边框的尺寸
+            //如果长大于宽 就是A3  否则就是A4
+            if(this.paperImgInfo.width>this.paperImgInfo.height)
+            {
+              //A3 1588*1123
+              templateInfo={
+                width:1588-30*2,//减去左右的边距
+                height:1123-25*2//减去上下的边距
+              };//模板去掉边框的尺寸
             }
-            console.log("打印计算后的obj",obj);
-          }
-          // 绘制文字  定位去和客观题组不用显示
-
-            // console.log("打印标题",item.questionName);
-            // ctx.fillStyle = 'red';
-             ctx.fillStyle = '#D81E06';
-              ctx.textAlign = 'center';
-              ctx.textBaseline = 'middle';
-            if(item.questionName=='总分')
+            let imagePoint={};
+            //客观题 需要减去 30 和25  因为客观题的坐标是相当于试卷原点  其他的主观题坐标是相当于批阅块的
+            if(item.titleType==1)
             {
-              const fontSize = Math.max(12, 50 * this.scale); // 最小字体12px,基础字体16px
-              ctx.font = `${fontSize}px Arial`; // 让文字大小跟随缩放
-              
-              ctx.textAlign = 'left';
-
-              const iconX=obj.x-20*this.zoomRate*this.scale;
-              const iconY=obj.y-20*this.zoomRate*this.scale;
-              const iconWidth = 100*this.zoomRate*this.scale; 
-              const iconHeight = 100*this.zoomRate*this.scale;
-
-              // displayType:res.data.displayType,//显示类型 0-分数 1-对错 2-等级
-              // displayName: res.data.displayName,//显示值
-              // correctType: res.data.correctType,//显示对错的时候 0-错 1-半对 2-全对
-              if(item.displayType === 0 || item.displayType === 2){
-                ctx.fillText(`${item.displayName}`,obj.x+35*this.zoomRate*this.scale,obj.y);
-              }else{
-                if(item.correctType==0){
-                  //0 分全错
-                  ctx.drawImage(this.CacheAllWrong, iconX, iconY, iconWidth, iconHeight);
-                }else if(item.correctType==2){
-                  //满分 全对
-                  ctx.drawImage(this.CacheAllRight, iconX, iconY, iconWidth, iconHeight);
-                }else{
-                  //半对
-                  ctx.drawImage(this.CacheHalfRight, iconX, iconY, iconWidth, iconHeight);
-                }
-              }
+             imagePoint={
+                x:((point.x-30)/templateInfo.width)*this.paperImgInfo.width,
+                y:((point.y-15)/templateInfo.height)*this.paperImgInfo.height,
+              };//相对于原图试卷的坐标 这里减去30是 黑块相对于左边的边距30px  上边的边距25px  减去15 是因为选择题的采分点 使用的是第一个答案的初始坐标点 需要减去答案的高度使其上下居中
             }
             else
             {
-              const fontSize = Math.max(12, 24 * this.scale); // 最小字体12px,基础字体16px
-              // ctx.font = '30px Arial';
-             
-              ctx.font = `${fontSize}px Arial`; // 让文字大小跟随缩放
-              
-              ctx.textAlign = 'left';
-              //判断是什么类型 scoreType 分数类型1:全对 2:半对 3: 全错
-              const iconX=obj.x-20*this.zoomRate*this.scale;
-              const iconY=obj.y-20*this.zoomRate*this.scale;
-              const iconWidth = 50*this.zoomRate*this.scale; 
-              const iconHeight = 50*this.zoomRate*this.scale;
-              // console.log("打印item.score",item.score)
-              if(item.displayType === 0 || item.displayType === 2){
-                ctx.fillText(`${item.displayName}`,obj.x+35*this.zoomRate*this.scale,obj.y);
-              }else{
-                if(item.correctType==0){
-                  //0 分全错
-                  ctx.drawImage(this.CacheAllWrong, iconX, iconY, iconWidth, iconHeight);
-                }else if(item.correctType==2){
-                  //满分 全对
-                  ctx.drawImage(this.CacheAllRight, iconX, iconY, iconWidth, iconHeight);
-                }else{
-                  //半对
-                  ctx.drawImage(this.CacheHalfRight, iconX, iconY, iconWidth, iconHeight);
-                }
-              }
-              // if(item.score==0)
-              // {
-                
-                
-              //   //0 分全错
-              //   ctx.drawImage(this.CacheAllWrong, iconX, iconY, iconWidth, iconHeight);
-                
-              // }
-              // else if(item.score==item.fullScore)
-              // {
-              //   //满分 全对
-              //   ctx.drawImage(this.CacheAllRight, iconX, iconY, iconWidth, iconHeight);
-              // }
-              // else
-              // {
-              //   //半对
-              //   ctx.drawImage(this.CacheHalfRight, iconX, iconY, iconWidth, iconHeight);
-              // }  
+               imagePoint={
+                x:(point.x/templateInfo.width)*this.paperImgInfo.width ,
+                y:(point.y/templateInfo.height)*this.paperImgInfo.height,
+              };//相对于原图试卷的坐标
             }
-            // ctx.fillText(`${item.score}`,obj.x+35*this.zoomRate*this.scale,obj.y);
             
-            // ctx.fillStyle = 'blue';
-            // ctx.font = `24px Arial`; // 让文字大小跟随缩放
-            // ctx.textAlign = 'center';
-            // ctx.textBaseline = 'middle';
-            // ctx.fillText(item.questionName,obj.x-65*this.zoomRate*this.scale,obj.y);
-
-
-          
-          
-          
-          
-        }
-        // ctx.restore();
-      // }
-    },
-
-    //下载图片绘制
-    DownloadDrawImage()
-    {
-      this.canvas=this.$refs.paperCanvas;
-      let ctx = this.canvas.getContext('2d');
-        
-      ctx.clearRect(0, 0, this.canvasInfo.width, this.canvasInfo.height);//清除边框数据
-      ctx.drawImage(this.image, 0, 0,this.canvasInfo.width,this.canvasInfo.height);
+            // console.log("系统卡相对于原图试卷的坐标imagePoint",imagePoint);
+            // let offsetX=this.GetInteger(imagePoint.x*this.zoomRate*this.scale);
+            // console.log("系统卡转换的采分点坐标offsetX",offsetX);
+            // let offsetY=Number(imagePoint.y*this.zoomRate*this.scale);
+            // console.log("系统卡转换的采分点坐标offsetY",offsetY);
+            obj={
+              x:imagePoint.x*this.zoomRate*this.scale,
+              y:imagePoint.y*this.zoomRate*this.scale,
+            };//采分点坐标更新
+         
 
-        
-        // console.log("加载边框数据",this.drawData);
-        for(var i=0;i<this.drawData.length;i++)
-        {
-          let item=this.drawData[i];
-          const point=JSON.parse(item.samplingPosition);
-          var obj={
-            x:point.x*this.zoomRate*this.scale,
-            y:point.y*this.zoomRate*this.scale,
+            
           }
+          console.log("打印当前题目",item.questionName);
+          console.log("打印转换前采分点坐标point",point);
+          console.log("打印转换后相对批阅块的采分点坐标obj",obj);
           //如果是批阅块的坐标 需要相加
+          console.log("打印item",item);
           if(item.pagePaintingVOS)
           {
             console.log("打印item",item);
             // let pageItem = item.pagePaintingVOS.find(item => item.page == point.page);
             const pointIndex=point.index || 0;//默认0
-            let pageItem = item.pagePaintingVOS[pointIndex];
+            blockPoint = item.pagePaintingVOS[pointIndex];
+            const pointPage=point.page;//采分点所在的页码
+            if(item.pagePaintingVOS.length>1)
+            {
+              //跨页的
+              blockList=item.pagePaintingVOS || [];
+            }
             // item.pagePaintingVOS.forEach((item,index) => { 
             //   if(index==point.index && item.page == point.page)
             //   {
@@ -622,42 +564,122 @@ export default {
             // });
             //需要同时根据索引和页面查找
             // const pageItem = item.pagePaintingVOS.find(item => item.page == point.page && item.index == point.index);
-            console.log("打印pageItem",pageItem);
+            console.log("打印blockPoint",blockPoint);
+            let newBlockPoint=blockPoint;
+            //如果是系统卡需要特殊处理 需要将坐标转成系统卡的坐标 并且需要去掉上下左右的边框
+            if(this.usedCardType==1)
+            {
+              
+              let templateInfo={
+                width:794-30*2,//减去左右的边距
+                height:1123-25*2//减去上下的边距
+              };//模板去掉边框的尺寸
+              //如果长大于宽 就是A3  否则就是A4
+              if(this.paperImgInfo.width>this.paperImgInfo.height)
+              {
+                //A3 1588*1123
+                templateInfo={
+                  width:1588-30*2,//减去左右的边距
+                  height:1123-25*2//减去上下的边距
+                };//模板去掉边框的尺寸
+              }
+              newBlockPoint={
+                x:this.GetInteger(((blockPoint.x-30)/templateInfo.width)*this.paperImgInfo.width),
+                y:this.GetInteger(((blockPoint.y-25)/templateInfo.height)*this.paperImgInfo.height),
+                w:this.GetInteger((blockPoint.w/templateInfo.width)*this.paperImgInfo.width),
+                h:this.GetInteger((blockPoint.h/templateInfo.height)*this.paperImgInfo.height),
+                page:blockPoint.page,
+              };//相对于原图试卷的坐标
+              blockPoint=newBlockPoint;
+              if(item.pagePaintingVOS.length>1)
+              {
+                blockList=[];
+                for(var j=0;j<item.pagePaintingVOS.length;j++)
+                {
+                  let blockObj=item.pagePaintingVOS[j];
+                  let obj={
+                    x:this.GetInteger(((blockObj.x-30)/templateInfo.width)*this.paperImgInfo.width),
+                    y:this.GetInteger(((blockObj.y-25)/templateInfo.height)*this.paperImgInfo.height),
+                    w:this.GetInteger((blockObj.w/templateInfo.width)*this.paperImgInfo.width),
+                    h:this.GetInteger((blockObj.h/templateInfo.height)*this.paperImgInfo.height),
+                    page:blockObj.page,
+                  };
+                  
+                  blockList.push(obj);
+                  
+                }
+              }
+              
 
-            if (pageItem) {
-              obj.x = (pageItem.x + point.x) * this.zoomRate * this.scale;
-              obj.y = (pageItem.y + point.y) * this.zoomRate * this.scale;
+            }
+
+
+            if(pointPage != this.pointPage)
+            {
+              //如果不是同一页  
+              console.log("打印不同页的坐标 打印第一页的切块坐标",newBlockPoint);
+              jHeight=newBlockPoint.h;
+            }
+
+            if (blockPoint) {
+              obj.x =this.GetInteger(newBlockPoint.x* this.zoomRate * this.scale+ obj.x);
+              obj.y =this.GetInteger(newBlockPoint.y* this.zoomRate * this.scale +obj.y);
             }
             console.log("打印计算后的obj",obj);
           }
+
+          console.log("打印转换后相对于原试卷的采分点坐标obj",obj);
           // 绘制文字  定位去和客观题组不用显示
 
-            // console.log("打印标题",item.questionName);
-            // ctx.fillStyle = 'red';
-             ctx.fillStyle = '#D81E06';
-              ctx.textAlign = 'center';
-              ctx.textBaseline = 'middle';
+            //console.log("打印标题",item.questionName);
+            //ctx.fillStyle = 'red';
+            ctx.fillStyle = '#D81E06';
+            ctx.textAlign = 'center';
+            ctx.textBaseline = 'middle';
             if(item.questionName=='总分')
             {
-              const fontSize = Math.max(12, 50 * this.scale); // 最小字体12px,基础字体16px
+              const fontSize = Math.max(12, this.scoreFontSize * this.scale); // 最小字体12px,基础字体50px
               ctx.font = `${fontSize}px Arial`; // 让文字大小跟随缩放
               
               ctx.textAlign = 'left';
-
-              const iconX=obj.x-20*this.zoomRate*this.scale;
-              const iconY=obj.y-20*this.zoomRate*this.scale;
-              const iconWidth = 100*this.zoomRate*this.scale; 
-              const iconHeight = 100*this.zoomRate*this.scale;
-
-
-              if(item.displayType == 0  || item.displayType === 2){
-                ctx.fillText(`${item.displayName}`,obj.x+35*this.zoomRate*this.scale,obj.y);
+              // 添加下划线
+              let text = '',textWidth = 0;
+              if(item.displayType === 0 || item.displayType === 2){
+                text = item.displayName.toString();
+                textWidth = ctx.measureText(text).width;
               }else{
+                textWidth = 2 * fontSize*this.zoomRate*this.scale; ;
+              }
+              const underlineY = obj.y + 50*this.zoomRate * this.scale ; // 可根据需要调整下划线位置
+              const startX = obj.x +35*this.zoomRate*this.scale;
+
+              ctx.beginPath();
+              ctx.moveTo(startX, underlineY);
+              ctx.lineTo(startX + textWidth, underlineY);
+              ctx.strokeStyle = ctx.fillStyle; // 使用与文字相同的颜色
+              ctx.lineWidth = 4;
+              ctx.stroke();
+              // 添加下划线2
+            
+              ctx.beginPath();
+              ctx.moveTo(startX-20, underlineY+20*this.zoomRate*this.scale);
+              ctx.lineTo(startX + textWidth + 20, underlineY+20*this.zoomRate*this.scale);
+              ctx.strokeStyle = ctx.fillStyle; // 使用与文字相同的颜色
+              ctx.lineWidth = 4;
+              ctx.stroke();
+              if(item.displayType === 0 || item.displayType === 2){
+                ctx.fillText(item.displayName,obj.x+35*this.zoomRate*this.scale,obj.y);
+              }else{
+                //判断是什么类型 scoreType 分数类型1:全对 2:半对 3: 全错
+                const iconX=obj.x +35*this.zoomRate*this.scale;
+                const iconY=obj.y-fontSize*this.zoomRate*this.scale;
+                const iconWidth = 2 * fontSize*this.zoomRate*this.scale; 
+                const iconHeight = 2 * fontSize*this.zoomRate*this.scale;
                 if(item.correctType==0){
                   //0 分全错
                   ctx.drawImage(this.CacheAllWrong, iconX, iconY, iconWidth, iconHeight);
                 }else if(item.correctType==2){
-                  //满分 全对
+                  //满分全对
                   ctx.drawImage(this.CacheAllRight, iconX, iconY, iconWidth, iconHeight);
                 }else{
                   //半对
@@ -667,20 +689,21 @@ export default {
             }
             else
             {
-              const fontSize = Math.max(12, 24 * this.scale); // 最小字体12px,基础字体16px
+              const fontSize = Math.max(12, 18 * this.scale); // 最小字体12px,基础字体18px
               // ctx.font = '30px Arial';
-             
               ctx.font = `${fontSize}px Arial`; // 让文字大小跟随缩放
-              
               ctx.textAlign = 'left';
               //判断是什么类型 scoreType 分数类型1:全对 2:半对 3: 全错
               const iconX=obj.x-20*this.zoomRate*this.scale;
               const iconY=obj.y-20*this.zoomRate*this.scale;
-              const iconWidth = 50*this.zoomRate*this.scale; 
-              const iconHeight = 50*this.zoomRate*this.scale;
-
-              if(item.displayType === 0 || item.displayType === 2){
-                ctx.fillText(`${item.displayName}`,obj.x+35*this.zoomRate*this.scale,obj.y);
+              const iconWidth = 40*this.zoomRate*this.scale; 
+              const iconHeight = 40*this.zoomRate*this.scale;
+              // console.log("打印item.score",item.score)
+              // displayType:res.data.displayType,//显示类型 0-分数 1-对错 2-等级
+              // displayName: res.data.displayName,//显示值
+              // correctType: res.data.correctType,//显示对错的时候 0-错 1-半对 2-全对
+              if(item.displayType === 2){
+                ctx.fillText(item.displayName,obj.x+35*this.zoomRate*this.scale,obj.y);
               }else{
                 if(item.correctType==0){
                   //0 分全错
@@ -692,36 +715,171 @@ export default {
                   //半对
                   ctx.drawImage(this.CacheHalfRight, iconX, iconY, iconWidth, iconHeight);
                 }
+                if(item.displayType === 0){//0-分数 显示分数和对错
+                  ctx.fillText(item.displayName,obj.x+35*this.zoomRate*this.scale,obj.y);
+                }
               }
-              // console.log("打印item.score",item.score)
-              // if(item.score==0)
-              // {
-                
-                
-              //   //0 分全错
-              //   ctx.drawImage(this.CacheAllWrong, iconX, iconY, iconWidth, iconHeight);
-                
-              // }
-              // else if(item.score==item.fullScore)
-              // {
-              //   //满分 全对
-              //   ctx.drawImage(this.CacheAllRight, iconX, iconY, iconWidth, iconHeight);
-              // }
-              // else
-              // {
-              //   //半对
-              //   ctx.drawImage(this.CacheHalfRight, iconX, iconY, iconWidth, iconHeight);
-              // }  
             }
-            // ctx.fillText(item.score,obj.x+35*this.zoomRate*this.scale,obj.y);
-            
+            // ctx.fillText(item.displayName,obj.x+35*this.zoomRate*this.scale,obj.y);
             // ctx.fillStyle = 'blue';
             // ctx.font = `24px Arial`; // 让文字大小跟随缩放
             // ctx.textAlign = 'center';
             // ctx.textBaseline = 'middle';
             // ctx.fillText(item.questionName,obj.x-65*this.zoomRate*this.scale,obj.y);
+            //绘制标注信息
+            if(item.drawLineData)
+            {
+              //有标注信息 加载标注  所有的坐标都要加上批阅块的初始坐标
+              console.log("打印point",point);
+
+              console.log("打印当前的页面",this.currentPage);
+              console.log("打印当前的批阅块数组",blockList);
+              const drawLineData=JSON.parse(item.drawLineData);
+              console.log("打印drawLineData",drawLineData);
 
 
+              // for(var j=0;j<drawLineData.length;j++)
+              // {
+              //   var drawItem=drawLineData[j];
+
+              //   console.log("打印drawItem",drawItem);
+              //   // 扣分点 加分点 标记// 1:文字 (扣分留痕 显示扣分信息)  2:划线  3:波浪线   4:画笔 5:评语
+              //   if(drawItem.drawType==1)
+              //   {
+                  
+              //     const fontSize = Math.max(12, 40 * this.zoomRate* this.scale); // 最小字体12px,基础字体16px
+              //     ctx.font = `${fontSize}px Arial`; // 让文字大小跟随缩放
+              //     // ctx.font = '30px Arial';
+              //     ctx.fillStyle = '#D81E06';
+              //     ctx.textAlign = 'center';
+              //     ctx.textBaseline = 'middle';
+              //     if(drawItem.type=='reduce')
+              //     {
+              //       ctx.fillText('-'+drawItem.score,(drawItem.x + blockPoint.x) * this.zoomRate * this.scale, (drawItem.y + blockPoint.y) * this.zoomRate * this.scale);  
+              //     }
+              //     if(drawItem.type=='bonus')
+              //     {
+              //       ctx.fillText('+'+drawItem.score, (drawItem.x + blockPoint.x) * this.zoomRate * this.scale, (drawItem.y + blockPoint.y) * this.zoomRate * this.scale);  
+              //     }
+                  
+              //   }
+              //   else if(drawItem.drawType==2)
+              //   {
+              //     //绘制横线
+              //     console.log("打印需要减去的高度",jHeight);
+              //     jHeight=0;
+              //     console.log("打印blockList",blockList);
+              //     let drawX=this.GetInteger((drawItem.x+ blockPoint.x)* this.zoomRate * this.scale);
+              //     let drawY=this.GetInteger((drawItem.y+blockPoint.y - jHeight)* this.zoomRate * this.scale);
+              //     let drawEndX=this.GetInteger((drawItem.endX+ blockPoint.x)* this.zoomRate * this.scale);
+              //     let drawEndY=this.GetInteger((drawItem.endY+blockPoint.y - jHeight)* this.zoomRate * this.scale);
+              //     this.DrawHorizontalLine(drawX,drawY,drawEndX,drawEndY);
+              //     // this.DrawHorizontalLine((drawItem.x+ blockPoint.x)* this.zoomRate * this.scale, (drawItem.y+blockPoint.y)* this.zoomRate * this.scale,(drawItem.endX+ blockPoint.x)* this.zoomRate * this.scale, (drawItem.endY+blockPoint.y)* this.zoomRate * this.scale);
+
+              //   }
+              //   else if(drawItem.drawType==3)
+              //   {
+              //     //绘制波浪线
+              //     let startX=parseFloat(((drawItem.x + blockPoint.x)* this.zoomRate * this.scale).toFixed(2));
+              //     let startY=parseFloat(((drawItem.y + blockPoint.y)* this.zoomRate * this.scale).toFixed(2));
+              //     let endX=parseFloat(((drawItem.endX + blockPoint.x)* this.zoomRate * this.scale).toFixed(2));
+              //     let endY=parseFloat(((drawItem.endY +blockPoint.y)* this.zoomRate * this.scale).toFixed(2));
+                  
+              //     this.DrawWaveLine(startX, startY,endX, endY);
+              //   }
+              //   else if(drawItem.drawType==4)
+              //   {
+              //     //绘制画笔数据
+              //     // console.log("打印画笔数据",drawItem);
+              //     this.DrawPenLine(drawItem,blockPoint);
+              //   }
+              //   else if(drawItem.drawType==5)
+              //   {
+              //     //绘制评语
+              //     let startX=parseFloat(((drawItem.x + blockPoint.x)* this.zoomRate * this.scale).toFixed(2));
+              //     let startY=parseFloat(((drawItem.y + blockPoint.y)* this.zoomRate * this.scale).toFixed(2));
+              //     // console.log("打印绘制评语数据",drawItem);
+              //     this.DrawText(startX,startY,drawItem.text);
+              //   }
+              // }
+
+              for(const [index, drawItem] of drawLineData.entries()) {
+                console.log("打印drawItem",drawItem);
+                // 计算通用的缩放因子,避免重复计算
+                const zoomScale = this.zoomRate * this.scale;
+                const offsetX = blockPoint.x * zoomScale;
+                const offsetY = blockPoint.y * zoomScale;
+                
+                // 扣分点 加分点 标记// 1:文字 (扣分留痕 显示扣分信息)  2:划线  3:波浪线   4:画笔 5:评语
+                switch(drawItem.drawType) {
+                  case 1: {
+                    // 文字类型(扣分点/加分点标记)
+                    const fontSize = Math.max(12, 40 * zoomScale);
+                    ctx.font = `${fontSize}px Arial`;
+                    ctx.fillStyle = '#D81E06';
+                    ctx.textAlign = 'center';
+                    ctx.textBaseline = 'middle';
+                    
+                    const x = drawItem.x * zoomScale + offsetX;
+                    const y = drawItem.y * zoomScale + offsetY;
+                    
+                    if(drawItem.type==='reduce') {
+                      ctx.fillText('-'+drawItem.score, x, y);  
+                    } else if(drawItem.type==='bonus') {
+                      ctx.fillText('+'+drawItem.score, x, y);  
+                    }
+                    break;
+                  }
+                  
+                  case 2: {
+                    // 绘制横线
+                    console.log("打印需要减去的高度",jHeight);
+                    jHeight=0;
+                    console.log("打印blockList",blockList);
+                    const coords = {
+                      x: this.GetInteger(drawItem.x * zoomScale + offsetX),
+                      y: this.GetInteger(drawItem.y * zoomScale + offsetY - jHeight * zoomScale),
+                      endX: this.GetInteger(drawItem.endX * zoomScale + offsetX),
+                      endY: this.GetInteger(drawItem.endY * zoomScale + offsetY - jHeight * zoomScale)
+                    };
+                    this.DrawHorizontalLine(coords.x, coords.y, coords.endX, coords.endY);
+                    break;
+                  }
+                  
+                  case 3: {
+                    // 绘制波浪线
+                    const coords = {
+                      startX: parseFloat((drawItem.x * zoomScale + offsetX).toFixed(2)),
+                      startY: parseFloat((drawItem.y * zoomScale + offsetY).toFixed(2)),
+                      endX: parseFloat((drawItem.endX * zoomScale + offsetX).toFixed(2)),
+                      endY: parseFloat((drawItem.endY * zoomScale + offsetY).toFixed(2))
+                    };
+                    this.DrawWaveLine(coords.startX, coords.startY, coords.endX, coords.endY);
+                    break;
+                  }
+                  
+                  case 4:
+                    // 绘制画笔数据
+                    this.DrawPenLine(drawItem,blockPoint);
+                    break;
+                  
+                  case 5: {
+                    // 绘制评语
+                    const coords = {
+                      x: parseFloat((drawItem.x * zoomScale + offsetX).toFixed(2)),
+                      y: parseFloat((drawItem.y * zoomScale + offsetY).toFixed(2))
+                    };
+                    this.DrawText(coords.x, coords.y, drawItem.text);
+                    break;
+                  }
+                  
+                  default:
+                    console.warn('未知的绘图类型:', drawItem.drawType);
+                }
+              }
+
+              
+            }
           
           
           
@@ -729,67 +887,146 @@ export default {
         }
     },
 
-    //加载答案框数据
-    drawQuestionPosition()
+    //转成整数
+    GetInteger(value)
     {
+      // 如果值为空、undefined 或 null,返回 0
+      if (value === null || value === undefined || value === '') {
+        return 0;
+      }
+      
+      // 如果已经是数字,直接处理
+      if (typeof value === 'number') {
+        // 检查是否为 NaN
+        if (isNaN(value)) {
+          return 0;
+        }
+        // 使用 Math.round 四舍五入取整
+        return Math.round(value);
+      }
+      
+      // 如果是字符串,先尝试转换为数字
+      if (typeof value === 'string') {
+        // 去除首尾空格
+        value = value.trim();
+        // 如果是空字符串,返回 0
+        if (value === '') {
+          return 0;
+        }
+        // 转换为数字
+        const num = Number(value);
+        // 检查是否为有效数字
+        if (isNaN(num)) {
+          return 0;
+        }
+        // 四舍五入取整
+        return Math.round(num);
+      }
+      
+      // 其他情况,尝试转换为数字后取整
+      const num = Number(value);
+      return isNaN(num) ? 0 : Math.round(num);
+    },
 
-      let canvas=this.$refs.paperCanvas;
-      let ctx = canvas.getContext('2d');
-      console.log("加载答案边框数据",this.questionPositionData);
-      for(var i=0;i<this.questionPositionData.length;i++)
+    //画横线
+      DrawHorizontalLine(x1,y1,x2,y2)
+      {
+        console.log("画横线起始坐标点",x1, y1, x2, y2);
+        const canvas = this.$refs.paperCanvas;
+        const ctx = canvas.getContext('2d');
+        ctx.strokeStyle = 'red';//设置红色
+        ctx.lineWidth = 2;//线条宽度
+        ctx.beginPath();
+        ctx.moveTo(x1, y1);
+        ctx.lineTo(x2, y2);
+        ctx.stroke();
+      },
+      //画波浪线
+      DrawWaveLine(startX, startY, endX, endY)
+      {
+        // console.log("画波浪线起始坐标点",startX, startY, endX, endY);
+        const amplitude  = 2; // 波浪的宽度
+        const frequency  = 0.8; //振幅 越大越密集
+        //计算中间点
+        const dx=endX-startX;
+        const dy=endY-startY;
+
+
+        // 开始绘制
+        const canvas = this.$refs.paperCanvas;
+        const ctx = canvas.getContext('2d');
+        ctx.strokeStyle = 'red';//设置红色
+        ctx.lineWidth = 2;//线条宽度
+        // 清除之前的线条
+        // ctx.clearRect(0, 0, this.canvasInfo.width, this.canvasInfo.height);
+        ctx.beginPath();
+        ctx.moveTo(startX, startY);//绘制第一个点
+        //绘制波浪
+        // 绘制波浪线
+        for (let x = startX; x <= endX; x += 1) {
+          const y = startY + dy * (x - startX) / dx + amplitude * Math.sin(frequency * (x - startX));
+          ctx.lineTo(x, y);
+        }
+        // ctx.lineTo(endX, endY);//绘制最后一个点
+        // ctx.lineWidth = 2; // 设置线条宽度
+        ctx.stroke();
+      },
+
+      //绘制画笔数据
+      DrawPenLine(data,blockPoint)
       {
-        var item=this.questionPositionData[i];
-      
-        // var obj={
-        //   x:item.x*this.zoomRate*this.scale,
-        //   y:item.y*this.zoomRate*this.scale,
-        //   width:item.w*this.zoomRate*this.scale,
-        //   height:item.h*this.zoomRate*this.scale,
-        //   blockName:item.blockName,
-        //   // page:'',
-        //   // blockArea:'',
-        // }
-        // //外边框数据
-        // if(item.unit=='mm')
-        // {
-        //   obj={
-        //     x:mmToPx(item.x)*this.zoomRate*this.scale,
-        //     y:mmToPx(item.y)*this.zoomRate*this.scale,
-        //     width:mmToPx(item.w)*this.zoomRate*this.scale,
-        //     height:mmToPx(item.h)*this.zoomRate*this.scale,
-        //     blockName:item.blockName,
-        //     // page:item.page,
-        //     // blockArea:item.blockArea,
-        //   }
-        // }
         
-        for(var j=0;j<item.questionlist.length;j++)
+        let linelist=data.drawlineData;
+        if(linelist.length>0)
         {
-          for(var k=0;k<item.questionlist[j].answerList.length;k++)
-          {
-            var obj={
-              x:mmToPx(item.questionlist[j].answerList[k].x)*this.zoomRate*this.scale,
-              y:mmToPx(item.questionlist[j].answerList[k].y)*this.zoomRate*this.scale,
-              width:mmToPx(item.questionlist[j].answerList[k].w)*this.zoomRate*this.scale,
-              height:mmToPx(item.questionlist[j].answerList[k].h)*this.zoomRate*this.scale,
-              // blockName:item.blockName,
+          const canvas = this.$refs.paperCanvas;
+          const ctx = canvas.getContext('2d');
+          ctx.strokeStyle = 'red';//设置红色
+          ctx.lineWidth = 2;//线条宽度
+          // 开始绘制
+          ctx.beginPath();
+          
+          // 绘制路径
+          for (let i = 0; i < linelist.length; i++) {
+            if(blockPoint)
+            {
+              let x=parseFloat(((linelist[i].x + blockPoint.x)* this.zoomRate * this.scale).toFixed(2));
+              let y=parseFloat(((linelist[i].y + blockPoint.y)* this.zoomRate * this.scale).toFixed(2));
+              ctx.lineTo(x, y);
             }
-            ctx.strokeRect(obj.x,obj.y,obj.width,obj.height); 
+           
           }
+          ctx.stroke();
+          ctx.closePath();
         }
-       
-        // ctx.font = '15px Arial';
-        
-        // ctx.textAlign = 'left';
-        // // ctx.textBaseline = 'middle';
-        // // 绘制文字
-        // if(obj.blockArea!=2)
-        // {
-        //   ctx.fillText(obj.blockName,obj.x, obj.y+15);
-        // }
+      },
+
+      //绘制文字
+      DrawText(startX, startY, text)
+      {
+        // 开始绘制
+        const canvas = this.$refs.paperCanvas;
+        const ctx = canvas.getContext('2d');
+        // 设置字体样式
+        ctx.font = '15px Arial';
+        ctx.fillStyle = 'red';
+        ctx.textAlign = 'left';
+        // ctx.textBaseline = 'middle';
+        // 绘制文字
+        ctx.fillText(text,startX, startY);
+      },
+
+    //下载图片绘制
+    DownloadDrawImage()
+    {
+      this.canvas=this.$refs.paperCanvas;
+      let ctx = this.canvas.getContext('2d');
         
-      }
-      ctx.restore();
+      ctx.clearRect(0, 0, this.canvasInfo.width, this.canvasInfo.height);//清除边框数据
+      ctx.drawImage(this.image, 0, 0,this.canvasInfo.width,this.canvasInfo.height);
+
+      this.DrawDataInfo();//加载边框数据
+
     },
 
     // 更新缩放率
@@ -1174,7 +1411,6 @@ export default {
     position: absolute;
     cursor: pointer;
     z-index: 9;
-    // border:1px solid red;
     img
     {
       width: 100%;

+ 1 - 1
src/http/api/reportStudent.js

@@ -85,7 +85,7 @@ const schoolReport = {
     //学生端查询考试列表(单校)
     queryStudentExamDataList(data) {
         return get(
-            base.prefix + "/api/v1/oneschoolReport/examoneschoolDatalist",
+            base.prefix + "/api/v1/oneSchoolReport/examOneSchoolDataList",
             data
         );
     },

+ 4 - 3
src/views/analysisReport/studentPage/scrolReport/transcript_single.vue

@@ -131,7 +131,7 @@
       <div class="module_table">
         <div class="answer_sheet" v-if="answerCard.paperImageList.length">
           <div class="item" v-for="(item, index) in answerCard.paperImageList">
-            <PaperImage :imageIndex="index" :paperImgUrl="item.picUrl" :drawData="item.questionVOS || []"></PaperImage>
+            <PaperImage :imageIndex="index" :scoreFontSize="20" :paperImgUrl="item.picUrl" :drawData="item.questionVOS || []"></PaperImage>
             <div class="item_hover">
               <div class="show_view" @click="OpenStudentPaper(index)">
                 <img src="@/assets/icon/pic_show_view.png" />
@@ -334,7 +334,7 @@
   </div>
 </template>
 <script>
-import PaperImage from '@/components/PaperImageSmall.vue' //学生试卷组件
+import PaperImage from '@/components/PaperImage.vue' //学生试卷组件
 import StudentPaper from '@/components/StudentPaper.vue' //学生答题卡预览组件
 import BarChart from '@/views/analysisReport/components/dCharts/barChart' //单柱状图组件
 import RadarCharts from '@/views/analysisReport/components/dCharts/radarCharts' //雷达图
@@ -612,7 +612,8 @@ export default {
     //答题卡预览
     OpenStudentPaper(index) {
       this.currentPageIndex = index //当选选中的第几页
-      this.paperTitle = `${this.pageName}_${this.userInfo.userName}【${this.answerCard.studentCode}】`
+      const studentCode = this.answerCard.studentCode ? `【${this.answerCard.studentCode}】` : this.answerCard.studentCode;
+      this.paperTitle = `${this.pageName}_${this.userInfo.userName}${studentCode}`
       this.showStudentPaperDialog = true
     },
     getMiddleNumber(arr) {