-
要完成导出样式如下图
- 1-4行:标题
- 5-12行:项目的基本信息 inputProData
- 13-20行:项目的指标信息 indexsArray(每种指标的数量不固定)
-
需要的数据和格式:
2.1 inputProData是个对象{},基本信息以键值对的方式存在inputProData对象中。
2.2 indexsArray是个数组[], 每一条指标信息对应一个indexsArray[i]。
具体数据格式如下图。ps:这里假设已获取了下图这些数据。
- HTML
- 这里讲1.单条导出2.批量导出,单条导出从页面获取数据导出成excel,批量导出从后台获取数据。批量导出是导出一个excel多个工作簿sheet
- 按钮绑定事件如下图。
<span onclick="doInputImport()">单条导出</span>
<span onclick="doInputeExp()">批量导出</span>
- 要引入 'jszip', 'bolb', 'xlsx', 'fileSaver' JS!!! jszip引用要放在最前面。
- 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;
}