美文网首页前端水很深
js导出excel报表(包括多个工作簿sheet导出)

js导出excel报表(包括多个工作簿sheet导出)

作者: 张小小小七 | 来源:发表于2018-04-24 10:54 被阅读1858次
    1. 要完成导出样式如下图


      导出报表excel格式.png
    • 1-4行:标题
    • 5-12行:项目的基本信息 inputProData
    • 13-20行:项目的指标信息 indexsArray(每种指标的数量不固定)
    1. 需要的数据和格式:
      2.1 inputProData是个对象{},基本信息以键值对的方式存在inputProData对象中。
      2.2 indexsArray是个数组[], 每一条指标信息对应一个indexsArray[i]。
      具体数据格式如下图。ps:这里假设已获取了下图这些数据。


      inputProData
    indexsArray
    1. HTML
    • 这里讲1.单条导出2.批量导出,单条导出从页面获取数据导出成excel,批量导出从后台获取数据。批量导出是导出一个excel多个工作簿sheet
    • 按钮绑定事件如下图。
    <span  onclick="doInputImport()">单条导出</span>
    <span  onclick="doInputeExp()">批量导出</span>
    
    • 要引入 'jszip', 'bolb', 'xlsx', 'fileSaver' JS!!! jszip引用要放在最前面。
    1. JS
    • 单条导入

    先定义一个exlFun 对象,存放关于excel导出的方法

    var  exlFun = {};
    //后面格式转换要用到
    var capital = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    var digit = [1, 26, 676, 17576];
    var capital_zero = "-0ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    

    单条导入方法:doInputImport

    doInputImport= function(){
            //TODO 1.从页面获取数据  标题数据通过项目名称拼凑
            var inputProData = operateData.getDataFromDiv('inputProInfo');//基本信息
            var indexsArray = viewModel.indexsGridDataTable.getSimpleData();//指标信息
            //TODO 2.拼凑excel数据数据格式并导出   PRJ_NAME存放项目名称
            exlFun.creatExcel(inputProData,indexsArray,null,inputProData.PRJ_NAME+"项目支出绩效目标申报表",'nobatch'); 
    }
    

    exlFun.creatExcel:

    
    //创建excel并导出(这里因为实际项目原因,将批量导出和单条导出写一起了,可以先只看非批量的导出)
    /**
      *  inputProData:项目基本信息(批量处理时inputProData传的是所有要导出项目的信息,包括每个项目的基本信息和指标信息)
      *  indexsArray:项目指标信息
      *  opt:可为空null
      *  fileName:excel文件名称
      *  type 
      **/
    exlFun.creatExcel = function(inputProData,indexsArray,opt,fileName,type){
        opt = opt || {};
            if(type == 'nobatch'){//非批量
                    opt.proData = inputProData;//存放项目信息
                    opt.indexsData = indexsArray;//存放指标信息
                    //文件名称(如果未传fileName,以导出文件加日期命名)
                    fileName = fileName || "导出文件" + getCurrentDate() + ".xlsx";
                    if (fileName.slice(-5).toLowerCase() != '.xlsx') {
                        fileName = fileName + ".xlsx";
                    }
                    //将网页项目数据转换成excle数据格式sheet
                    var sheet = exlFun.getExcelSheet(opt, fileName);
                    //导出(下载)excel
                    exlFun.saveExcelFile(sheet, fileName);
             }else{//批量
                    var sheets = [];var proNames = [];//分开存放每个项目sheet
                    //获取不同项目的基本数据
                    for(var i=0; i<inputProData.length; i++){
                        var proData = inputProData[i].targetPro;
                        var indexsData = inputProData[i].targetIdx;
                                    //将数据的null-->''
                        comFun.dealUndefine(proData);
                        comFun.dealArrOrObjUndefine(indexsData);
                        ////将网页项目数据转换成excle数据格式sheet
                        opt.proData = proData;//项目信息
                        opt.indexsData = indexsData;//指标信息
                        var sheet = exlFun.getExcelSheet(opt, fileName);
                        //将单个项目sheet放入sheets数组
                        sheets.push(sheet);
                        proNames.push(proData.PRJ_NAME);
                    }   
                    //文件名
                    fileName = fileName || "导出文件" + getCurrentDate() + ".xlsx";//文件名称
                    if (fileName.slice(-5).toLowerCase() != '.xlsx') {
                        fileName = fileName + ".xlsx";
                    }
                    //导出(下载)excel多个工作簿sheet
                    exlFun.saveBatchExcelFile(sheets,fileName,proNames);//opt放所有sheets
                }
      }
    

    exlFun.getExcelSheet:

    exlFun.getExcelSheet = function(opt, fileName){
                var maxHeadRow = 4;//表头 4行
                var maxHeadCol = 9;//表格 9列 :A-I
                //excel总行数:表头+指标数据行数+指标标题行数+项目信息行数
                var rowsLength = maxHeadRow + opt.indexsData.length + 1 + 8;
                opt.maxHeadCol = 9;
                var colWidth = [];//存放列宽
                var rowHeight = [];//存放行高
                var sheet = {
                          '!merges': [],//存放单元格合并信息
                          'A2': {//标题放在A2单元格,见图1 (标题=项目名称+fileName文件名称)
                                v: opt.proData.PRJ_NAME+fileName.replace(".xlsx",""),
                          },
                          'A3': {
                                v: "( 2018年度)",
                          },
                          '!ref': 'A1:I4',
                }
                //设置标题单元格样式style  加粗,黑色,居中显示
                sheet["A2"].s = { font: { sz: 14, bold: true, color: { rgb: "000000" } }, 
                                  alignment: {horizontal: "center" ,vertical: "center"}
                                 /* fill: { bgColor: { indexed: 64 }, fgColor: { rgb: "FFFF00" } }*/
                };
                sheet["A3"].s = { font: { sz: 14, bold: false, color: { rgb: "000000" } }, 
                          alignment: {horizontal: "center" ,vertical: "center"}
                };
                //获取不同指标级的行数
                var indexsTypeNum =  exlFun.getIndexTypeNum(opt.indexsData);
                //获取合并单元格信息
                var sheet = exlFun.getMerges(sheet,rowsLength,indexsTypeNum);
    //          console.log(sheet['!merges']);
                //将项目基本信息加入sheet
                sheet = exlFun.getExcelProData (opt,sheet);
                //将项目指标信息加入sheet
                sheet = exlFun.getExcelIndexsData(opt,sheet,rowsLength,maxHeadCol,indexsTypeNum)
                //设置excel范围 :A1:I34
                sheet['!ref'] = 'A1:' +  exlFun.index2ColName(maxHeadCol) + rowsLength;
                sheet["!cols"] = colWidth;
                sheet["!rows"] = rowHeight;
                //设置列宽为100
                for(var n = 0; n < maxHeadCol; n++){  
                    sheet['!cols'].push({  
                        wpx: 100  
                     });
                }  
                sheet.maxHeadRow = maxHeadRow;/excel表头标题行数
                sheet.maxHeadCol = maxHeadCol;//excel列数
                sheet.rowLenght = opt.indexsData.length + 1 + 8;//excel行数
                return sheet;
            }
    
            //index转为列名,如:28 转为 AB
            exlFun.index2ColName = function(index) {
                var colName = "";
                var j = 0;
                for (var i = digit.length - 1; i >= 0; i--) {
                    j = Math.floor(index / digit[i]);
                    if (j > 0) {
                        colName += capital[j - 1];
                        index = index % digit[i];
                    } else {
                        if (colName.length > 0) {
                            colName += "0"
                        }
                    }
                }
                colName = colName.split("");
                for (var x = colName.length - 1; x >= 0; x--) {
                    if (colName[x] == "0") {
                        //向高位借位处理0
                        if (colName.join("").substring(0, x).replace(/0/g, "") != "") { 
                            colName[x] = "Z";
                            colName[x - 1] = capital_zero[capital_zero.indexOf(colName[x - 1]) - 1];
                        } else {
                            break;
                        }
                    } else if (colName[x] == "-") {  //向高位借位,还低位的借位
                        colName[x] = "Y";
                        colName[x - 1] = capital_zero[capital_zero.indexOf(colName[x - 1]) - 1];
                    }
                }
                return colName.join("").replace(/0/g, "");
            }
    

    合并单元格 exlFun.getMerges:

    合并单元格

    例如:项目名称单元格A5,从第0行,第0列开始,在第0行,第3列结束。这路合并信息都是从0开始计算。单元格合并信息为:

    sheet['!merges'].push({//项目名称
           s: {r: 0, c: 0},//s指start:开始,r指row:行 ,c指col:列
           e: {r: 0, c: 2}//e指end:结束
    })
    
    /**
     *  sheet:excel数据,存放sheet['!merges']
     *  rowsLength:行数
     *  indexsTypeNum:不同级次的指标个数
     **/
           exlFun.getMerges = function(sheet,rowsLength,indexsTypeNum){
               for(var i=0; i<rowsLength-1; i++){
                   //行合并 - 项目信息
                   if(i == 0 || i == 1){//row:1-2  col:0-8
                       sheet['!merges'].push({
                              s: {r: i+1, c: 0},
                              e: {r: i+1, c: 8}
                       })
                   }else if(i == 2 ){
                       
                   }else if(i == 3){//row:4  col:0-2 / 3-8
                       sheet['!merges'].push({
                              s: {r: i+1, c: 0},
                              e: {r: i+1, c: 2}
                       });
                       sheet['!merges'].push({
                              s: {r: i+1, c: 3},
                              e: {r: i+1, c: 8}
                       });
                   }else if(i == 4 || i == 5){//row:5-6  col:0-2 / 3-4 / 5-6 / 7-8
                       sheet['!merges'].push({
                              s: {r: i+1, c: 0},
                              e: {r: i+1, c: 2}
                       });
                       sheet['!merges'].push({
                              s: {r: i+1, c: 3},
                              e: {r: i+1, c: 4}
                       });
                       sheet['!merges'].push({
                              s: {r: i+1, c: 5},
                              e: {r: i+1, c: 6}
                       });
                       sheet['!merges'].push({
                              s: {r: i+1, c: 7},
                              e: {r: i+1, c: 8}
                       });
                   }else if(i == 6 || i == 7 || i == 8){//row:7-9  col:0-2/5-6/7-8
                       sheet['!merges'].push({
                              s: {r: i+1, c: 5},
                              e: {r: i+1, c: 6}
                       });
                       sheet['!merges'].push({
                              s: {r: i+1, c: 7},
                              e: {r: i+1, c: 8}
                       });
                   }else if(i == 9 || i == 10){//row:10-11  col:1-4/5-8
                       sheet['!merges'].push({
                              s: {r: i+1, c: 1},
                              e: {r: i+1, c: 4}
                       });
                       sheet['!merges'].push({
                              s: {r: i+1, c: 5},
                              e: {r: i+1, c: 8}
                       });
                   }else{//row:12-end  col:6-7
                       sheet['!merges'].push({
                              s: {r: i+1, c: 6},
                              e: {r: i+1, c: 7}
                       });
                   }
               }
               
               //列合并-一二级指标 
               var indexsMer = exlFun.getColMer(indexsTypeNum); 
               for(var m=0; m<indexsMer.length; m++){
                   sheet['!merges'].push(indexsMer[m]);
               }
               
               //项目信息
               sheet['!merges'].push({//项目资金
                      s: {r: 7, c: 0},
                      e: {r: 9, c: 2}
               })
               sheet['!merges'].push({//总体目标
                      s: {r: 10, c: 0},
                      e: {r: 11, c: 0}
               })
               //指标信息
               sheet['!merges'].push({//绩效指标
                      s: {r: 12, c: 0},
                      e: {r: rowsLength-1, c: 0}
               })
               sheet['!merges'].push({//总体目标
                      s: {r: 10, c: 0},
                      e: {r: 11, c: 0}
               })
               return sheet
           }
    
    
    

    项目基本信息加入sheet :exlFun.getExcelProData

    //获取excel项目数据,这个也是根据excel模板(有固定数据和动态数据)
            exlFun.getExcelProData = function(opt,sheet){
                 var proDatas = opt.proData;
                 sheet['A5'] = {"v": "项目名称"};//固定
                 sheet['A6'] = {"v": "主管部门及代码"};
                 sheet['A7'] = {"v": "项目属性"};
                 sheet['A8'] = {"v": "项目资金(万元)"};
                 sheet['A11'] = {"v": "总体目标"};
                 sheet['A13'] = {"v": "绩效指标 "};
                 sheet['B11'] = {"v": "中期目标(20××年—20××+n年)"};
                 sheet['B13'] = {"v": "一级指标"};
                 sheet['C13'] = {"v": "二级指标"};
                 sheet['D8'] = {"v": "中期资金总额"};
                 sheet['D9'] = {"v": "其中:财政拨款"};
                 sheet['D10'] = {"v": "其他资金"};
                 sheet['D13'] = {"v": "三级指标"};
                 sheet['D5'] = {"v": proDatas.PRJ_NAME};//项目名称 动态
                 sheet['D6'] = {"v": proDatas.MGR_DEPT_CODE+proDatas.MGR_DEPT_NAME};//主管部门代码名称
                 sheet['D7'] = {"v": proDatas.PRJ_KIND};//项目属性
                 sheet['E13'] = {"v": "指标值"};
                 sheet['E8'] = {"v": proDatas.MTT_AMOUNT};//中期资金总额
                 sheet['E9'] = {"v": proDatas.MTF_AMOUNT};//其中:财政拨款
                 sheet['E10'] = {"v": proDatas.MTO_AMOUNT};//其他资金
                 sheet['F6'] = {"v": "实施单位"};
                 sheet['F7'] = {"v": "项目期"};
                 sheet['F8'] = {"v": "年度资金总额"};
                 sheet['F9'] = {"v": "其中:财政拨款"};
                 sheet['F10'] = {"v": "其他资金"};
                 sheet['F11'] = {"v": "年度目标"};
                 sheet['F13'] = {"v": "二级指标"};
                 sheet['G13'] = {"v": "三级指标"};
                 sheet['H6'] = {"v": proDatas.EXEC_DEPT_NAME};//实施单位
                 sheet['H7'] = {"v": "开始-结束"};//项目期
                 sheet['H8'] = {"v": proDatas.YT_AMOUNT};// 年度资金总额
                 sheet['H9'] = {"v": proDatas.YF_AMOUNT};//其中:财政拨款
                 sheet['H10'] = {"v": proDatas.YO_AMOUNT};//其他资金
                 sheet['I13'] = {"v": "指标值"};   
                 return sheet//返回sheet
            }
    

    获取excel指标数据: exlFun.getExcelIndexsData

            exlFun.getExcelIndexsData = function(opt,sheet,rowsLength,maxHeadCol,indexsTypeNum){
                 var proDatas = opt.indexsData;
                 var indexsIndex = exlFun.getRowIndexs(indexsTypeNum);//指标行数下标
                 var indexsRow1 =  indexsIndex.indexRows1; 
                 var indexsRow2 =  indexsIndex.indexRows2;
                 console.log();
                 var lengths1 = indexsTypeNum.levelLength1;//[14,7]
                 var lengths2 = indexsTypeNum.levelLength2;//[14,7]
                 for (var r = 0; r <= rowsLength; r++) {//r:excel行
                     for (var c = 0; c < maxHeadCol; c++) {//c:excel列
                         var addrIndex =  exlFun.index2ColName(c + 1);//A-I 
                         if(r >= 13){//指标开始行
                             for(var a=0; a<indexsRow1.length; a++){
                                 if( (indexsRow1[a]+1) == r  && (addrIndex == 'B') ){//一级指标
                                     sheet[addrIndex + r] = {"v": proDatas[r-14].LEVEL1_INDEX};
                                 }
                             }
                             for(var b=0; b<indexsRow2.length; b++){
                                 if( (indexsRow2[b]+1) == r  && (addrIndex == 'C' || addrIndex == 'F') ){//二级指标
                                     sheet[addrIndex + r] = {"v": proDatas[r-14].LEVEL2_INDEX};
                                 }
                             }
                            if(r > 13){//14...
                                 for(var o=0; o<proDatas.length; o++){//三级指标和指标值
                                     sheet['D' + r] = {"v": proDatas[r-14].LEVEL3_INDEX};
                                     sheet['E' + r] = {"v": proDatas[r-14].INDEX_VAL};
                                     sheet['G' + r] = {"v": proDatas[r-14].LEVEL3_INDEX_YEAR};
                                     sheet['I' + r] = {"v": proDatas[r-14].INDEX_VAL_YEAR};
                                 }  
                            }
                                
                         }
                     }
                 }
                 return sheet
            }
    

    单条导出:exlFun.saveExcelFile

    //利用Blob将数据转换成excel格式
            exlFun.saveExcelFile = function(sheet, fileName){
                 var wb = {
                       SheetNames: ['Sheet1'],
                       Sheets: {
                             'Sheet1': sheet
                       }
                 };
                 var wopts = {bookType: 'xlsx', bookSST: false, type: 'binary'};
                 //要引入xlsx.js
                 var wbout = XLSX.write(wb, wopts);
                 saveAs(new Blob([s2ab(wbout)], {type: ""}), fileName);
            }
    
            //String转换为ArrayBuffer
            function s2ab(s) {
                var buf = new ArrayBuffer(s.length);
                var view = new Uint8Array(buf);
                for (var i = 0; i < s.length; ++i) {
                    view[i] = s.charCodeAt(i) & 0xFF;
                }
                return buf;
            }
    

    其他处理指标数据的方法:

     //获取不同类型指标数量
            exlFun.getIndexTypeNum = function(indexsData){
                var levelLength = {};
                levelLength.levelLength1 = [];//不同一级指标的个数
                levelLength.levelLength2 = [];//不同二级指标的个数
                var index1 = 0,index2 = 0;
                for(var i=0; i<indexsData.length; i++){
                     var num1 = 0;var num2 = 0;
                     if(indexsData[i].LEVEL1_INDEX){
                         if(i!=0){//不是第一个 指标一
                             num1 = i-index1;//指标个数
                             index1 = i;
                             levelLength.levelLength1.push(num1);
                         }
                     }
                     if(indexsData[i].LEVEL2_INDEX){
                         if(i!=0){//不是第一个 指标二
                             num2 = i-index2;//指标个数
                             index2 = i;
                             levelLength.levelLength2.push(num2);
                         }
                     }
                     if(i == indexsData.length-1){//判断最后一行指标
                         if(!indexsData[i].LEVEL1_INDEX){//最后一行没有指标一
                             num1 = i+1-index1;
                             index1 = i;
                             levelLength.levelLength1.push(num1);
                         }else{
                             levelLength.levelLength1.push(1);//最后一行单独的指标一
                         }
                         
                         if(!indexsData[i].LEVEL2_INDEX){
                             num2 = i+1-index2;
                             index2 = i;
                             levelLength.levelLength2.push(num2);
                         }else{
                             levelLength.levelLength2.push(1);
                         }
                         
                     }
                }
                return levelLength
            }     
           //获取一二级指标名称的行数
            exlFun.getRowIndexs = function(indexsTypeNum){
                var rowIndex = {};
                var lengths1 = indexsTypeNum.levelLength1;//[14,7]
                var lengths2 = indexsTypeNum.levelLength2;//[14,7]
                var indexRows1 = exlFun.getRowIndex(lengths1);
                var indexRows2 = exlFun.getRowIndex(lengths2);
                rowIndex.indexRows1 = indexRows1;
                rowIndex.indexRows2 = indexRows2;   
                return rowIndex
            }
            //获取某级指标名称行下标
            exlFun.getRowIndex = function(lengths){
                var startRow = 13;
                var n = 0,rows = [];
                rows.push(startRow);
                for(var k=0; k<lengths.length-1; k++){
                    n = lengths[k]; 
                    startRow = startRow + n;    
                    rows.push(startRow);
                }
                return rows
            }
           //指标单元格信息
            exlFun.getColMer = function(indexsTypeNum){
                var startRow1 = 13;
                var startRow2 = 13;
                var lengths1 = indexsTypeNum.levelLength1;//一级指标数量数组[14,6]
                var lengths2 = indexsTypeNum.levelLength2;//一级指标数量数组[14,6]
                var n = lengths1[0];
                var m = lengths2[0];
                var indexsMer = [];
                for(var k=1; k<=lengths1.length; k++){
                    //13~26/27~33(end) -->col:1 
                    var indexMer1 = {
                        s: {r: startRow1, c: 1},
                        e: {r: startRow1 + n - 1, c: 1}//TODO r:i+产出指标/效果指标个数 12+14=26  26+7=33 
                    };
                    startRow1 = startRow1 +n;
                    n = lengths1[k];    
                    indexsMer.push(indexMer1);
                }
                for(var k=1; k<=lengths2.length; k++){
                    //13~16/17~19/20~22 -->col:2 /5
                    var indexMer2 = {
                        s: {r: startRow2, c: 2},
                        e: {r: startRow2 + m - 1, c: 2}//TODO r:i+产出指标/效果指标个数 12+14=26  26+7=33 
                    };
                    var indexMer3 = {
                        s: {r: startRow2, c: 5},
                        e: {r: startRow2 + m - 1, c: 5}//TODO r:i+产出指标/效果指标个数 12+14=26  26+7=33 
                    };
                    startRow2 = startRow2 +m;
                    m = lengths2[k];    
                    indexsMer.push(indexMer2);
                    indexsMer.push(indexMer3);
                }
                return indexsMer
            }
    
    • 批量导出
      批量导出就获取数据的方法、 exlFun.saveExcelFile方法略有不同。
    /**
             * 批量导出
             */
            doBatchExp = function(){
                //TODO 1.根据CHR_ID从后台获取数据
                var currViewModel =  comFun.getCurrViewModel();//判断当前活动页
                ids = currViewModel.gridData.getSimpleData({//获取选择的行CHR_ID
                    type : 'select',
                    fields : [ 'CHR_ID' ]
                });
                if (ids == 0) {
                    ip.ipInfoJump("请至少选择一条数据!", "error");
                    return;
                }
                var batchProDatas = [];//存放不同项目数据
                ids.forEach(function(obj){
                     //TODO 从后台获取每条数据的项目信息和指标信息,放在detailsObj 
                     var detailsObj = ajaxObj.batchExp(obj.CHR_ID);
                     batchProDatas.push(detailsObj);
                })
                //TODO 批量导出,方法同单条导出,参数意义不同
                 exlFun.creatExcel(batchProDatas,null,null,"项目支出绩效目标申报表",'batch');  
            }
    

    利用Blob将数据转换成excel格式 -- 批量:exlFun.saveBatchExcelFile

            exlFun.saveBatchExcelFile = function(sheetArr,fileName,proNames){           
                var wb = {
                           SheetNames: [],
                           Sheets: {},
                 };
                 for(var i=0; i<sheetArr.length; i++ ){
                     wb.SheetNames.push('Sheet'+(i+1));
                     wb.Sheets['Sheet'+(i+1)] = sheetArr[i]
                     //以下代码可以替换页签(工作簿名称),但要保证名称一定不同
                     /*wb.SheetNames.push(proNames[i]);
                     wb.Sheets[proNames[i]] = sheetArr[i];*/
                 }
                 var wopts = {bookType: 'xlsx', bookSST: false, type: 'binary'};
                 var wbout = XLSX.write(wb, wopts);//xlsx.js
                 saveAs(new Blob([s2ab(wbout)], {type: ""}), fileName);
            }
            //String转换为ArrayBuffer
            function s2ab(s) {
                var buf = new ArrayBuffer(s.length);
                var view = new Uint8Array(buf);
                for (var i = 0; i < s.length; ++i) {
                    view[i] = s.charCodeAt(i) & 0xFF;
                }
                return buf;
            }
    

    相关文章

      网友评论

        本文标题:js导出excel报表(包括多个工作簿sheet导出)

        本文链接:https://www.haomeiwen.com/subject/pxullftx.html