PHPExcel 打印報表

    因工做需求,須要將前端頁面顯示的 table 報表打印成 Excel 文件,由於報表類型多樣,好多的 td 標籤存在跨行又跨列的狀況,PHPExcel 做爲一款 php 處理 Excel 的插件,雖然方便,但在處理這些報表起來也很是的複雜。javascript

    若是咱們可以在 js 中肯定整個 table 的行數和列數,並肯定每一個 td 在 Excel 中的座標以及跨行跨列後最終點的座標,而後在後臺 php 將接收到的數據打印至 Excel,這樣不只可以減緩服務端壓力,在前端的調用中也將爲咱們帶來便利。php

    前臺用到了 jQuery,獲取 table 數據及 td 座標的數據操做能夠封裝成一個插件並指定後臺接口。jQ 代碼以下:html

(function($){
  $.fn.extend({
    forExcel:function(){
      var list = [];// 傳入後臺的數據
      var span_all = []; 	// 記錄既跨行又跨列的坐標
      var max_td = []; 	// 記錄最大列數
      var height_tr = []; // 記錄行高
				
      // 行 tr 循環
      $(this).children().find("tr").each(function(i, dom){
	// 獲取每一行的高度 
	height_tr.push($(dom).height()*0.75); // 像素轉換
	// 記錄最大列數
	max_td.push($(dom).children("td").length);
	
        // 列 td 循環
	$(dom).children("td").each(function(isub, domsub){
	  var tdata = {};	
	  // 獲取跨行,跨列
          var col = $(domsub).attr("colspan");
	  col = col ? parseInt(col) : 0;
	  var row = $(domsub).attr("rowspan");
	  row = row ? parseInt(row) : 0;
						
          // 圖片判斷 ------ PHPExcel只容許本地圖片地址 -----------------
	  if($(domsub).find("img").length != 0){
	    tdata.img = $(domsub).find("img").length;
	    tdata.img_src = $(domsub).find("img").attr('src'); // 圖片地址需加前綴
	    tdata.img_width = $(domsub).find("img").width();
	    tdata.img_height = $(domsub).find("img").height();
	  }else{
	    tdata.img = "none";
	  }
						
	  // 記錄跨行坐標
	  if(row>0){
	    span_all.push({row:i, col:isub, rowspan:row, colspan:col});
	  }
						
	  // 獲取 td 在 Excel 中的位置
	  var data = getIdx(i, isub, span_all, this, row, col);
	  tdata.idx = data.idx;
	  tdata.span = data.span;
	  tdata.text = $(domsub).text();				
	  list.push(tdata);
	});
      });
				
      var tdata = {};
      tdata.tdlength = Math.max.apply(null, max_td);
      tdata.height_tr = height_tr;
      var countr = $(this).children().find("tr").length;
      var trdom = $(this).children().find("td").last();
      var rows = $(trdom).attr("rowspan");
      rows = rows ? parseInt(rows) : 1;
      tdata.trlength = countr+rows-1;
				
      tdata.tdData = list;
      var tableData = JSON.stringify(tdata);
      // 後臺接口
      $(this).after("<form id='forexcelform' action='後臺接口' method='post'></form>");
      $("#forexcelform").html("<input type='hidden' name=tbdata value='"+ tableData +"' />");
      $("#forexcelform").submit();
      $("#forexcelform").remove();
    }
  });

  // 返回列名
  function getColIdx(idx){
    var col =    ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',				'AA','AB','AC','AD','AE','AF','AG','AH','AI','AJ','AK','AL','AM','AN','AO','AP','AQ','AR','AS','AT','AU','AV','AW','AX','AY','AZ',				  'BA','BB','BC','BD','BE','BF','BG','BH','BI','BJ','BK','BL','BM','BN','BO','BP','BQ','BR','BS','BT','BU','BV','BW','BX','BY','BZ',					  'CA','CB','CC','CD','CE','CF','CG','CH','CI','CJ','CK','CL','CM','CN','CO','CP','CQ','CR','CS','CT','CU','CV','CW','CX','CY','CZ',					  'DA','DB','DC','DD','DE','DF','DG','DH','DI','DJ','DK','DL','DM','DN','DO','DP','DQ','DR','DS','DT','DU','DV','DW','DX','DY','DZ'];
    return col[idx];
  }
		
  // 返回坐標與跨行或跨列後的坐標 
  function getIdx(row, col, span_all, dom, span_row, span_col){
    var pre_colspan = 0; //
    // 是否位於跨行跨列的行數中
    $.each(span_all, function(i, val){
	var rows = span_all[i].row + span_all[i].rowspan;
	if(row>span_all[i].row && row<rows && col>=span_all[i].col){
	  pre_colspan += parseInt(span_all[i].colspan==0?1:span_all[i].colspan);
	}
    });
			
    var tr_colspan = 0;
    // 計算同行 td 前的 colspan
    $(dom).prevAll().each(function(i, domsub){
	var colspan = $(domsub).attr("colspan");
	colspan = colspan ? colspan : 1;
	tr_colspan += parseInt(colspan)-1;
    });
			
    pre_colspan += tr_colspan;
    // 記錄開始坐標
    var idx = getColIdx(col+pre_colspan) +""+ (row+1);
    // 記錄跨後終點坐標
    var span = "none";
    // 跨行或跨列後的坐標
    if(span_row>0 && span_col==0){
	span = getColIdx(col+pre_colspan) +""+ (span_row+row);
    }else if(span_row==0 && span_col>0){
	span = getColIdx(span_col+col+pre_colspan-1) +""+ (1+row);
    }else if(span_row>0 && span_col>0){
 	span = getColIdx(span_col+col+pre_colspan-1) +""+ (span_row+row);
    }
	return {idx: idx, span: span};
  }
})(jQuery);

該插件獲取以下圖的請求參數爲前端

{"tdlength":3,"height_tr":[16.5,16.5,16.5],"width_td":15.76,"trlength":3,"tdData":[{"idx":"A1","span":"A2","text":"eq(跨2行)","img":"none"},{"idx":"B1","span":"none","text":"  eq","img":"none"},{"idx":"C1","span":"none","text":"eq","img":"none"},{"idx":"B2","span":"none","text":"eq","img":"none"},{"idx":"C2","span":"none","text":"eq","img":"none"},{"idx":"A3","span":"B3","text":"eq(跨2列)","img":"none"},{"idx":"C3","span":"none","text":"eq","img":"none"}]}java

而在後臺 php 接口中,核心代碼以下json

public function x_xPrintExcel(){
		vendor("PHPExcel.PHPExcel"); // thinkPHP 加載插件
		$objPHPExcel = new PHPExcel();
		// 設置文件的一些屬性,在xls文件——>屬性——>詳細信息裏能夠看到這些值,xml表格裏是沒有這些值的
		$objPHPExcel
			->getProperties()  //得到文件屬性對象,給下文提供設置資源
			->setCreator( "")                 //設置文件的建立者
			->setLastModifiedBy( "")          //設置最後修改者
			->setTitle( "Office 2007 XLSX Test Document" )    //設置標題
			->setSubject( "Office 2007 XLSX Test Document" )  //設置主題
			->setDescription( "Test document for Office 2007 XLSX, generated using PHP classes.") //設置備註
			->setKeywords( "office 2007 openxml php")        //設置標記
			->setCategory( "Test result file");                //設置類別
		
		$tbdata = $_POST['tbdata'];
		$a = str_replace('\\','',$tbdata); // 前臺傳入 json 字符串
		$_tdata = json_decode($a);
		$tbdata = $_tdata->tdData;
		//dump($tbdata);die();
		for($i=0; $i<count($tbdata); $i++){
			$idx = $tbdata[$i]->idx;
			$text = $tbdata[$i]->text;
			$span = $tbdata[$i]->span;
			$img = $tbdata[$i]->img;
			$img_src = $tbdata[$i]->img_src;
			$img_width = $tbdata[$i]->img_width;
			$img_height = $tbdata[$i]->img_height;
			
			if("none" != $img){
				/*實例化插入圖片類*/
				$objDrawing = new PHPExcel_Worksheet_Drawing();
				$objDrawing->setResizeProportional(false);

				$objDrawing->setPath($img_src);
				$objDrawing->setWidth($img_width);
				$objDrawing->setHeight($img_height);
				$objDrawing->setCoordinates($idx);//單元格
				$objDrawing->setWorksheet($objPHPExcel->setActiveSheetIndex(0));//$sheet爲當前工做表
			}else{
				$objPHPExcel->setActiveSheetIndex(0)  //設置第一個內置表(一個xls文件裏能夠有多個表)爲活動的
				->setCellValue( $idx, $text );//setWrapText
			}
			// 垂直居中
			$objPHPExcel->getActiveSheet()->getStyle($idx)->getAlignment()->setVertical(PHPExcel_Style_Alignment::VERTICAL_CENTER);
			//自動換行
			$objPHPExcel->getActiveSheet()->getStyle($idx)->getAlignment()->setWrapText(true);
			if("none" != $span){
				$objPHPExcel->getActiveSheet()->mergeCells( $idx.':'.$span);	
			}
		}
		// 確定行列
		$tdlength = $_tdata->tdlength;
		$trlength = $_tdata->trlength;
			
		$cellName = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
							'AA','AB','AC','AD','AE','AF','AG','AH','AI','AJ','AK','AL','AM','AN','AO','AP','AQ','AR','AS','AT','AU','AV','AW','AX','AY','AZ',
							'BA','BB','BC','BD','BE','BF','BG','BH','BI','BJ','BK','BL','BM','BN','BO','BP','BQ','BR','BS','BT','BU','BV','BW','BX','BY','BZ',
							'CA','CB','CC','CD','CE','CF','CG','CH','CI','CJ','CK','CL','CM','CN','CO','CP','CQ','CR','CS','CT','CU','CV','CW','CX','CY','CZ',
							'DA','DB','DC','DD','DE','DF','DG','DH','DI','DJ','DK','DL','DM','DN','DO','DP','DQ','DR','DS','DT','DU','DV','DW','DX','DY','DZ');
		
		$height_tr = $_tdata->height_tr; // 行高
		// 設置邊框
		for($i=0; $i<$trlength; $i++){
			// 行高 
			$objPHPExcel->getActiveSheet()->getRowDimension(''.($i+1).'')->setRowHeight($height_tr[$i]);
			for($j=0; $j<$tdlength; $j++){
				$idx = $cellName[$j].''.($i+1) ;
				$objPHPExcel->getActiveSheet()->getStyle($idx)->getBorders()->getTop()->setBorderStyle(PHPExcel_Style_Border::BORDER_THIN);
				$objPHPExcel->getActiveSheet()->getStyle($idx)->getBorders()->getBottom()->setBorderStyle(PHPExcel_Style_Border::BORDER_THIN);
				$objPHPExcel->getActiveSheet()->getStyle($idx)->getBorders()->getLeft()->setBorderStyle(PHPExcel_Style_Border::BORDER_THIN);
				$objPHPExcel->getActiveSheet()->getStyle($idx)->getBorders()->getRight()->setBorderStyle(PHPExcel_Style_Border::BORDER_THIN);
			}
		}
		//
		for($j=0; $j<$tdlength; $j++){
			$objPHPExcel->getActiveSheet()->getColumnDimension($cellName[$j])->setWidth(15);
		}
		header('Content-Type: application/vnd.ms-excel');
		header('Content-Disposition: attachment;filename="simple.xls"');
		header('Cache-Control: max-age=0');
		$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
		$objWriter->save('php://output');
		exit;
	}

效果以下:app

相關文章
相關標籤/搜索