找回密码
 立即注册

QQ登录

只需一步,快速开始

[调研中] 二维码截图问题

Wilson.Zhang
超级版主   /  发表于:2024-10-10 08:33:30
11#
antd 发表于 2024-10-9 17:47
老师,在之前的帖子中,我阐述了为什么不能用spreadjs自己打印的原因(无法打印图片、无法无预览打 ...

看到了7楼和9楼热心用户的跟帖回复,可以参考他们给出的方案试试看能不能满足需求。
回复 使用道具 举报
antd
高级会员   /  发表于:2024-10-10 15:03:41
12#
不吐葡萄皮 发表于 2024-10-9 18:21
知道了你的要求,那就是等一会儿就能拿到绘制出来的图片了,比如下面代码:

      大佬,首先感谢大佬提供的思路,你提供的这种方式,确实可行,但是当页面内容多一点的时候camera.toImageSrc()获取的base64地址点开就是个空白的快照,定时器的值设置大点才能正常的获取,但这压根不能一劳永逸。
      其实我这里更需要的是camera.toImageSrc()而非sheet.shapes.addPictureShape。camera.toImageSrc()能正确获取,那sheet.shapes.addPictureShape肯定就是正确的了

回复 使用道具 举报
afr2022
金牌服务用户   /  发表于:2024-10-10 16:47:37
13#
Wilson.Zhang 发表于 2024-10-10 08:33
看到了7楼和9楼热心用户的跟帖回复,可以参考他们给出的方案试试看能不能满足需求。

老师,现在的问题是参考了各位大佬们的方案后,对于结构简单的模板可以正常的获取的到想要的src,但是结构稍复杂点的获取到的src就是空白图片
回复 使用道具 举报
Wilson.Zhang
超级版主   /  发表于:2024-10-10 17:59:39
14#
afr2022 发表于 2024-10-10 16:47
老师,现在的问题是参考了各位大佬们的方案后,对于结构简单的模板可以正常的获取的到想要的src,但是结 ...

“结构稍复杂点的获取到的src就是空白图片”,猜测可能是超时到时的时候二维码还没生成导致的,试试看把超时延长。
回复 使用道具 举报
afr2022
金牌服务用户   /  发表于:2024-10-10 18:15:51
15#
Wilson.Zhang 发表于 2024-10-10 17:59
“结构稍复杂点的获取到的src就是空白图片”,猜测可能是超时到时的时候二维码还没生成导致的,试试看把 ...

我把时间调到5s才能正常的获取到src,如果是一个页面有多个二维码或者条形码。那循环获取怕是时间太长了吧?还是希望官方能够出一些事件或者方法直接获取快照后的二维码图片src
回复 使用道具 举报
不吐葡萄皮
注册会员   /  发表于:2024-10-10 18:34:14
16#
afr2022 发表于 2024-10-10 18:15
我把时间调到5s才能正常的获取到src,如果是一个页面有多个二维码或者条形码。那循环获取怕是时间太长了 ...

5s就有点过分了,可以把代码发出来看看吗?
回复 使用道具 举报
antd
高级会员   /  发表于:2024-10-10 20:11:29
17#
不吐葡萄皮 发表于 2024-10-10 18:34
5s就有点过分了,可以把代码发出来看看吗?
  1. // 获取iframe
  2.     const iframe = document.querySelector("#printIframe");
  3.     let iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
  4.     iframeDoc.head.innerHTML = `<style>${cssRules}</style>`
  5.     // 打印按钮
  6.     testBtn.onclick = async ()=>{
  7.         sheet = spread.getActiveSheet();
  8.         //  不显示水平网格线
  9.         sheet.options.gridline.showHorizontalGridline = false;
  10.         //  不显示垂直网格线
  11.         sheet.options.gridline.showVerticalGridline = false;
  12.         const sheetName = sheet.name();
  13.         iframeDoc.body.innerHTML = '';
  14.         // 清空
  15.         varRecords = [];
  16.         imageRecords = [];
  17.         cameraShapeList = [];
  18.         promiseScreenshotList = [];
  19.         // 获取打印区域
  20.         let printInfo = sheet.printInfo();
  21.         let rowStart = printInfo.rowStart();
  22.         let rowEnd = printInfo.rowEnd();
  23.         let columnStart = printInfo.columnStart();
  24.         let columnEnd = printInfo.columnEnd();
  25.         console.log(rowStart,rowEnd,columnStart,columnEnd);
  26.         if(rowStart>=0){//未设置打印区时,位置坐标都为-1
  27.             // 获取打印区域的上侧与左侧的距离
  28.             const printAreaTopLeft = getTopAndLeft(rowStart,columnStart,sheet);
  29.             // 获取打印区域的宽高
  30.             const printAreaWidthHeight = getWidthAndHeight(rowStart,columnStart,rowEnd,columnEnd,sheet);
  31.             let keyList = data[0]?Object.keys(data[0]):[];
  32.             // 寻找打印区域内且和源数据有映射的普通变量
  33.             printAreaVariable(keyList,rowStart,columnStart,rowEnd,columnEnd,sheetName);
  34.             // 调用判断打印区区域内的图片
  35.             printAreaImage(printAreaTopLeft,printAreaWidthHeight);
  36.             console.log("变量位置:",varRecords);
  37.             const divBox = document.createElement("div");//iframe下直接容器
  38.             async function test() {
  39.                 for (let item of data){
  40.                     let tempDiv = document.createElement("div");//每页的内容
  41.                     tempDiv.classList.add("page-break");
  42.                     // 给普通变量填值
  43.                     varRecords.map(varItem=>{
  44.                         sheet.setValue(varItem.row,varItem.col,item[varItem.keyName]);
  45.                     });//遍历变量位置
  46.                     
  47.                     const htmlStr = sheet.getRange(rowStart,columnStart,rowEnd - rowStart + 1,columnEnd - columnStart + 1).toHtml();
  48.                     tempDiv.innerHTML = htmlStr;
  49.                     tempDiv.style.position = "relative";
  50.                     // 渲染插入的图片
  51.                     imageRecords.map(imageItem=>{
  52.                         const img = document.createElement("img");
  53.                         img.style.position = "absolute";
  54.                         img.style.top = imageItem.imageTop + 'px';
  55.                         img.style.left = imageItem.imageLeft + 'px';
  56.                         img.style.width = imageItem.width + 'px';
  57.                         img.style.height = imageItem.height + "px";
  58.                         img.src = imageItem.src;
  59.                         tempDiv.appendChild(img);
  60.                     });

  61.                     // 获取快照后的图片src
  62.                     for(let cameraInfo of cameraShapeList){
  63.                         await new Promise((resolve,reject)=>{
  64.                             setTimeout(()=>{
  65.                                 console.log("我成功了");
  66.                                 console.log(cameraInfo.camera)
  67.                                 console.log(cameraInfo.camera.toImageSrc());
  68.                                 resolve()
  69.                             },8000)
  70.                         });
  71.                     }
  72.    
  73.                     divBox.appendChild(tempDiv);
  74.                 };//遍历源数据
  75.             }
  76.             await test();
  77.             console.log("执行完毕")
  78.             // cameraShapeList.forEach(item=>{
  79.             //     sheet.shapes.remove(item.imgName)
  80.             // })
  81.             //  显示水平网格线
  82.             sheet.options.gridline.showHorizontalGridline = true;
  83.             //  显示垂直网格线
  84.             sheet.options.gridline.showVerticalGridline = true;

  85.             // // 还原普通变量
  86.             varRecords.forEach(item=>{
  87.                 sheet.setValue(item.row,item.col,item.str);
  88.             });
  89.             // iframeDoc.body.appendChild(divBox);

  90.             // setTimeout(()=>{
  91.             //     iframe.contentWindow.print();
  92.             // },100)
  93.         }else{
  94.             alert("请先设置打印区域");
  95.             return;
  96.         };
  97.     };//按钮
  98.    
  99.     /**
  100.          * 使用spreadjs中单元格名称来充当变量,并获取区域内的变量
  101.          * @param {*} keyList 源数据中的属性变量
  102.          * @param {*} rowStart 区域开始的行
  103.          * @param {*} columnStart 区域开始的列
  104.          * @param {*} rowEnd 区域结束的行
  105.          * @param {*} columnEnd 区域结束的列
  106.          * @param {*} sheetName sheet名
  107.          */
  108.     function printAreaVariable(keyList,rowStart,columnStart,rowEnd,columnEnd,sheetName){
  109.         sheet.getCustomNames().forEach(async cellInfo=>{
  110.             let {row,column,endRow,endColumn} = cellInfo.getExpression();
  111.             let cellName = cellInfo.getName();
  112.             console.log("单元格名称区域:",row,column,endRow,endColumn,cellName);
  113.             if(rowStart<=row && columnStart<=column){
  114.                 if((rowEnd>=endRow && columnEnd>=endColumn) || (!endRow && !endColumn)){
  115.                     console.log(row,column,cellName);
  116.                     if(keyList.includes(cellName)){
  117.                         varRecords.push({row,col:column,keyName:cellName,str:sheet.getValue(row,column)});
  118.                     };//判断是否是源数据中的变量
  119.                     // 二维码与条形码单元格名称
  120.                     if(cellName.startsWith("QR_")){
  121.                         let tempObj = {row, rowCount: endRow - row + 1, col:column, colCount: endColumn - column + 1};
  122.                         // 范围区域转公式
  123.                         const rangeStr = GC.Spread.Sheets.CalcEngine.rangeToFormula(tempObj);
  124.                         const imgName = `${cellName}_Image`;
  125.                         let {top,left} =  getTopAndLeft(row,column,sheet);
  126.                         let obj = {top,left,row,column,endRow,endColumn,imgName};
  127.                         // 快照
  128.                         let camera = sheet.shapes.addCameraShape(imgName,`${sheetName}!${rangeStr}`,left,top);
  129.                         obj.camera = camera;
  130.                         cameraShapeList.push(obj);
  131.                     };//判断二维码与条形码
  132.                 }
  133.             };//判断是否在范围内
  134.         });
  135.     };
  136.    
  137.     /**
  138.      * 判断那些插入的图片在打印区域内的方法
  139.      * @param {*} topLeftObj 打印区域的top与left值
  140.      * @param {*} widthHeightObj 打印区域的width和height值
  141.      */
  142.     function printAreaImage(topLeftObj,widthHeightObj){
  143.         sheet.shapes.all().forEach(shape=>{
  144.             // console.log(shape,"src:",shape.toImageSrc(),"width:",shape.width(),"height:",shape.height(),"top:",shape.y(),"left:",shape.x());
  145.             //打印区域内的图片(不含截图)
  146.             if((shape.x()>=topLeftObj.left) &&
  147.                 (shape.y()>=topLeftObj.top) &&
  148.                 ((shape.width()+shape.x())<=(topLeftObj.left+widthHeightObj.width)) &&
  149.                 ((shape.height()+shape.y())<=(topLeftObj.top+widthHeightObj.height)) &&
  150.                 cameraShapeList.findIndex(item=>item.imgName == shape.name()) == -1){
  151.                 // 图片距离打印区顶部的位置
  152.                 let imageTop = shape.y() - topLeftObj.top;
  153.                 let imageLeft = shape.x() - topLeftObj.left;
  154.                 imageRecords.push({imageTop,imageLeft,src:shape.toImageSrc(),width:shape.width(),height:shape.height()});
  155.             };
  156.         });//遍历图片
  157.         console.log("插入的图片:",imageRecords);
  158.     };
复制代码
核心代码差不多就这些了。中间有两个方法是获取打印区域的宽高以及距离顶部和左侧的距离的。复杂点的模板就这样的:
图片.png184537047.png 这种就是获取到的src点开全是空白,刚才我又试了一下5s又不行了,还是空白。如果只是单纯的空白测试二维码,可以正常拿到设置1ms都可以
源数据格式:
图片.png742499694.png


图片.png622465819.png

评分

参与人数 1满意度 +5 收起 理由
afr2022 + 5

查看全部评分

回复 使用道具 举报
不吐葡萄皮
注册会员   /  发表于:2024-10-11 14:24:26
18#
  1.     function printAreaVariable(keyList,rowStart,columnStart,rowEnd,columnEnd,sheetName){
  2.         sheet.getCustomNames().forEach(async cellInfo=>{
复制代码


这个方法应该也是异步方法吧,然后调用的地方是await。

  1.                     // 获取快照后的图片src
  2.                     for(let cameraInfo of cameraShapeList){
  3.                         await new Promise((resolve,reject)=>{
  4.                             setTimeout(()=>{
  5.                                 console.log("我成功了");
  6.                                 console.log(cameraInfo.camera)
  7.                                 console.log(cameraInfo.camera.toImageSrc());
  8.                                 resolve()
  9.                             },8000)
  10.                         });
  11.                     }
复制代码

这个部分可以把for-of放到setTimeout里面吧,因为画好就是全部camera都画好。

我这边跑不起来,所以楼主可以发一下log信息,或者是完整可运行的例子更好

评分

参与人数 1金币 +200 收起 理由
Joestar.Xu + 200 赞一个!

查看全部评分

回复 使用道具 举报
antd
高级会员   /  发表于:2024-10-11 14:37:03
19#
不吐葡萄皮 发表于 2024-10-11 14:24
这个方法应该也是异步方法吧,然后调用的地方是await。

这个部分可以把for-of放到setTimeout里面吧 ...

感谢大佬的回复,printAreaVariable应该就是同步方法,里面并没有出现异步的操作,至于大佬说的把for-of放到定时器中,我再试一下看看,因为这个项目不是很方便完全发到论坛所以只能放一点与这块相关的
回复 使用道具 举报
antd
高级会员   /  发表于:2024-10-11 17:10:11
20#
不吐葡萄皮 发表于 2024-10-11 14:24
这个方法应该也是异步方法吧,然后调用的地方是await。

这个部分可以把for-of放到setTimeout里面吧 ...

大佬,我整理个演示demo出来,大佬有时间的话可以帮忙指导一下,里面有演示视频。由于论坛的现在,成功的示例是gif的形式。其中二维码单元格的名字以QR_开头即可。

20241011问题演示.rar

18.38 MB, 下载次数: 2

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 立即注册
返回顶部