ThinkPHP利用phpOffice/Spreadsheet实现Excel导出(加粗、背景色、文字颜色、合并行列)

  • A+
所属分类:PHP ThinkPHP5

首先我们使用composer安装:

composer require phpoffice/phpspreadsheet

然后建立一个抽象的工具类Export并为其创建单例类:

namespace app\common\tool;

abstract class Export
{
   private static $instance = [];
    /**
         * @return static
         */
      public static function getInstance()
      {
            $class = get_called_class();
            if(!isset(self::$instance[$class]) || !self::$instance[$class] instanceof $class){
                self::$instance[$class] = new static();
            }
            return self::$instance[$class];
      }  
}

然后我们定义3个方法,分别定义文件的标题(sheet)名,文件的后缀格式以及表头是否加粗显示:

定义标题:

public function setFileTitle() : string
{
    return 'sheet';
}

定义文件后缀格式:

public function setFileFormat() : string
{
    return 'Xlsx';
}

定义表头是否加粗:

public function setFileHeaderBold(): bool
{
    return true;
}

定义两个抽象方法要求子类必须实现:

定义表头的内容:

abstract public function setFileHeader(): array ;

定义文件的名称:

abstract public function setFileName(): string ;

我们来实现导出的功能:

public function export($datas)
{
    $spreadsheet = new Spreadsheet();
    //设置当前的sheet对象 并获取 sheet
    $worksheet = $spreadsheet->setActiveSheetIndex(0);
    $startRow = 1;
    $fields = [];
    
        foreach ($this->setFileHeader() as $key => $headers){
                $startCell = 1;
                foreach ($headers as $column => $header){
                    //表头中设置text的属性
                    if(isset($header['text'])){
                        //获取当前要做成的单元格对象
                        $nowColumn = $this->getNowColumn($worksheet, $startCell, $startRow);
                        $worksheet->setCellValue($nowColumn, $header['text']);
                        //设置单元格的宽度
                        if(isset($header['width'])){
                            $worksheet->getColumnDimension(Coordinate::stringFromColumnIndex($startCell))->setWidth($header['width']);
                        }
                        //设置表头加粗
                        $worksheet->getStyle($nowColumn)->getFont()->setBold($this->setFileHeaderBold());
                        //设置水平居中
                        if(isset($header['align'])){
                            $worksheet->getStyle($nowColumn)->getAlignment()->setHorizontal($header['align']);
                        }else{
                            $worksheet->getStyle($nowColumn)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT);
                        }
                        //设置垂直居中
                        $worksheet->getStyle($nowColumn)->getAlignment()->setVertical(Alignment::VERTICAL_CENTER);
                        //设置背景颜色
                        if(isset($header['bgColor'])){
                            $worksheet->getStyle($nowColumn)->getFill()->setFillType(Fill::FILL_SOLID)
                                ->getStartColor()->setARGB($header['bgColor']);
                        }
                        //设置文字颜色
                        if(isset($header['fontColor'])){
                            $worksheet->getStyle($nowColumn)->getFont()->getColor()->setARGB($header['fontColor']);
                        }
                        //合并列
                        if(isset($header['colspan']) && $header['colspan'] >= 2){
                            $mergeCells = $nowColumn.':'.Coordinate::stringFromColumnIndex($startCell + $header['colspan'] - 1).$startRow;
                            $worksheet->mergeCells($mergeCells);
                            $startCell = $startCell + $header['colspan'] -1;

                        }
                        //合并行
                        if(isset($header['rowspan']) && $header['rowspan'] >= 2){
                            $mergeCells = $nowColumn.':'.Coordinate::stringFromColumnIndex($startCell).($startRow + $header['rowspan'] - 1);
                            $worksheet->mergeCells($mergeCells);

                        }
                    }
                    //field在datas中存在,用于取数据
                    if(isset($header['field'])){
                        $fields[] = $header['field'];
                    }
                    $startCell++;

                }
                $startRow++;
            }
            //设置sheet标题
            $worksheet->setTitle($this->setFileTitle());
            //输出内容到sheet
            foreach ($datas as $key => $data){
                $row = $startRow + $key;
                foreach ($fields as $index => $field){
                    //如果存在getFieldNameAttr()则调用,实现字段的判断
                    $method = 'get'.ucfirst(Loader::parseName($field, 1)).'Attr';
                    if(method_exists($this, $method)){
                        $value = $this->$method(...[$field, $data]);
                    }else if(isset($data[$field])){
                        //存在取值
                        $value = $data[$field];
                    }else{
                        //不存在留空
                        $value = '';
                    }
                    //设置单元格值
                    $worksheet->setCellValue(Coordinate::stringFromColumnIndex($index + 1).$row, $value);
                }
            }
        $this->downloadExcel($spreadsheet, $this->setFileName(), $this->setFileFormat());
}

获取当前单元格的位置:

private function getNowColumn($worksheet, &$startCell, $startRow)
{
   $nowColumn = Coordinate::stringFromColumnIndex($startCell).$startRow;

   if(!$this->isMergeCell($worksheet, $nowColumn)){
       return $nowColumn;
   }
   $startCell++;
   return $this->getNowColumn($worksheet, $startCell, $startRow);
}

判断当前单元格是否合并的状态:

private function isMergeCell($worksheet, $nowColumn)
{
    foreach ($worksheet->getMergeCells() as $cells) {
        if ($worksheet->getCell($nowColumn)->isInRange($cells)) {
            return true;
        }
    }
    return false;
}

下载文件的方法:

private function downloadExcel($spreadsheet, $fileName, $format)
{
    header("Content-Type:application/octet-stream");
    if ($format == 'Xlsx') {
        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
    } elseif ($format == 'Xls') {
        header('Content-Type: application/vnd.ms-excel');
    }
    header("Content-Disposition: attachment;filename="
        . $fileName. '.' . strtolower($format));
    header('Cache-Control: max-age=0');
    $writer = IOFactory::createWriter($spreadsheet, $format);
    $writer->save('php://output');
    exit;
}

我们来实现一个具体的导出,如用户导出:

首先建立UserExport:

namespace app\common\tool\export;

use app\common\tool\Export;

class UserExport extends Export
{
    public function setFileHeader(): array
    {
       return [
           [
               ['field' => 'user_name', 'text' => '用户名', 'width' => 60, 'bgColor' => '67834B', 'fontColor' => 'FFFFFF']
           ]
       ];
    }

    public function setFileName(): string
    {
        return 'userData'.date("Ymd");
    }

}

高级用法:

    public function setFileHeader(): array
    {
       return [
            [
                ['text' => '用户信息', 'width' => 20, 'rowspan' => 2],
                ['text' => '其他信息', 'colspan' => 5, 'bgColor' => '0589FA'],
            ],
            [
                ['field' => 'mem_name','text' => '姓名'],
                ['field' => 'telephone', 'text' => '电话', 'width' => 25],
                ['field' => 'city', 'text' => '城市'],
            ]
        ];
    }

设置字段的值:

public function getTelephoneAttr($key, $data)
{
    return $data['telephone']; //手机号隐藏中间的四位处理
}

avatar

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: