小菜最近遇到一个需求,批量合成二维码。比如一个饭店有冰箱、桌子、显示器、电脑等等,需要为这些资产贴上一个二维码,二维码中只有一个ID号,用ID向后台来查询资产的信息。在这个方案中有一个问题,就是生成二维码后,怎么让员工一眼就是知道二维码和资产对应的关系。

实现思路,先将后台生成的ID号建立一个excel表格,通过读取excel表格来批量生成二维码,然后在用canvas技术,将二维码和excel表格信息对应起来,最后在合成一个二维码。废话少说,先上代码示例。

备份演示地址 http://walidream.com/example/js/qrcode/

参考资料

示例演示

1.读取本地excel文件

方法:readWorkbookFromLocalFile

参数:file

说明:读取excel中的数据

readWorkbookFromLocalFile(file){
	let self = this;
	let reader = new FileReader();
	reader.onload = function(e) {
		let data = e.target.result;
		let workbook = XLSX.read(data, {type: 'binary'});
		self.readWorkbook(workbook);
	};
	reader.readAsBinaryString(file);
}

2.处理读取到的数据

方法:readWorkbook

参数:workbook

说明:处理excel中的数据

readWorkbook(workbook){
	let self = this;
	let sheetNames = workbook.SheetNames; // 工作表名称集合
	let worksheet = workbook.Sheets[sheetNames[0]]; // 这里我们只读取第一张sheet
	let csv = XLSX.utils.sheet_to_csv(worksheet);
	let rows = csv.split('\n');

	let head = rows.shift(); //编辑表格头部
	self.tabHeads = self.getTabHeah(head);

	rows.pop(); // 最后一行没用的
	self.qrcodes = self.getTabBody(rows);

	//生成二维码
	self.creatQrcode();
}

3.获取表格头部

方法:getTabHeah

参数:head

说明:将第一个处理成表头和key对应

getTabHeah(head){
	let arr = head.split(',');
	let headrs = [];
	headrs = arr.map((val,ind)=>{
		return {prop:'key'+ind,label:val}
	});
	return headrs;
}

4.获取表数据

方法:getTabBody

参数:rows

说明:处理excel表中的数据

getTabBody(rows){
	let self = this;
	let arr = [];
	rows.forEach(val=>{
		let brr = val.split(",");
		let obj = {};
		brr.forEach((v,i)=>{
			obj['key'+i] = v;
			obj['label'+i] = self.tabHeads[i].label;
		})
		obj['qrcode'] = '';
		obj['synthesis'] = '';
		obj['isMome'] = true;
		arr.push(obj);
	})
	return arr;
}

5.生成二维码

方法:creatQrcode

说明:将第一列的ID生成对应的二维码

creatQrcode(){
	let self = this;
	let opts = {
		errorCorrectionLevel: 'H',
		type: 'image/jpeg',
		width:200,
		rendererOpts: {
			quality: 0.5
		}
	}
	let arr = [];
	self.qrcodes.forEach(val=>{
		QRCode.toDataURL(val['key0'], opts , function (err, url) {
			if (err) throw err;

			val.qrcode = url;
			arr.push(val);
		})
	})
	self.qrcodes = arr;
}

6.合成单个二维码

方法:qrcodeSynthesis

参数:obj,setting

说明:将二维码和ID对应并合成新的二维码

function qrcodeSynthesis(obj,setting){
    return new Promise(function(resolve,reject){
        var canvas = document.createElement("canvas");

        //设置canvas宽高
        canvas.width = setting.width;
        canvas.height = setting.height;

        //获取绘图环境
        var context = canvas.getContext('2d');

        if(!context){
            alert('您的浏览器尚不支持,请更换浏览器');
            return ;
        }
        //设置加载图片的状态
        var ImgStatus = {
            qrImgStatus:false
        }
        //设置二维码
        var qrImg = new Image();

        //加载二维码
        qrImg.onload = function(){
            //绘制二维码
            context.drawImage(qrImg,0,0);
            ImgStatus.qrImgStatus = true;
        }
        //填充画布背景
        drawRect(context,0,0,setting.width,setting.height,setting.canvasBorder[0],setting.canvasBorder[1],setting.canvasBg);

        //绘制二维码
        qrImg.crossOrigin = "Anonymous" ;  //二维码
        qrImg.src = obj.qrcode;

        //绘制编号
        var style ={
            font:'bold 16px Arial ',
            color:'#000',
            textBaseline:'middle'
        };
        var numTxt = {
            txt:obj['label0']+''+obj['key0'],
            x:setting.qrcode.width,
            y:40
        }
        var numTxtAttr = drawText(context,numTxt,style);
        //绘制资产名称
        var nameTxt = {
            txt:obj['label1']+''+obj['key1'],
            x:setting.qrcode.width,
            y: numTxt.y + numTxtAttr.txtHeight + 15
        }
        var nameTxtAttr = drawText(context,nameTxt,style);



        (function imgStatus(ImgStatus){
            var time = null;
            if(ImgStatus.qrImgStatus){
                var imgdate = canvas.toDataURL("image/jpeg", 0.5);
                resolve(imgdate);
                return false;
            }else{
                time = setTimeout(function(){
                    imgStatus(ImgStatus);
                },1000);
            }
        })(ImgStatus);

    })

    //绘制矩形
    function drawRect(cxt,x,y,width,height,BW,BC,fillColor){
        cxt.beginPath();
        cxt.moveTo(x,y);
        cxt.lineTo(x+width,y);
        cxt.lineTo(x+width,y+height);
        cxt.lineTo(x,y+height);
        cxt.closePath();

        cxt.lineWidth=BW;
        cxt.fillStyle=fillColor;
        cxt.strokeStyle=BC;

        cxt.fill();
        cxt.stroke();
    }
    //绘制单行文本
    function drawText(cxt,obj,setobj){
        var setting = {
            font:'30px Arial',
            color:'#000',
            textBaseline:'middle'
        }
        if(setobj) setting = Object.assign({},setting,setobj);

        cxt.font=setting.font;
        cxt.fillStyle=setting.color;
        cxt.fillText(obj.txt,obj.x,obj.y);

        let fontHeight = setting.font.match(/\d+/);

        return {
            txt:obj.txt,
            txtWidth:cxt.measureText(obj.txt).width,
            txtHeight: parseInt(fontHeight[0]),
            source:obj
        }

    }

}

7.批量合成二维码

方法:synthesisQrcode

说明:批量合成二维码

synthesisQrcode(){
	let self = this;
	let promises = self.qrcodes.map(val=>{
		return qrcodeSynthesis(val,self.canvas);
	})

	let arr = [];
	Promise.all(promises).then(function (urls) {
		self.qrcodes = self.qrcodes.map((v,i)=>{
			v.synthesis = urls[i];
			return v;
		})
	})
}