• PhpSpreadsheet 导出特定格式 — 广告请款单


    需求说明

    最近需要实现一个导出这种格式的Excel表单,之前都有用过导出Excel的功能,但大都是表头+数据的形式,只用于获取数据,没有太多样式要求,不用合并单元格、合并居中等,也不用对每一行数据特异化定制的,所以对PhpSpreadsheet扩展库进行进阶理解。

    解决过程

    从github->官方文档->api文档->CSDN文章(文末有链接),完了跟着操作都会一直报错,csdn的那篇文章中一旦调用了样式的方法后,返回对象就变成了样式相关的,不能继续指定工作单元了,所以仍然不是太实用,只能作为参考了。

    最后通过看源码 + api文档实现了这部分的功能点。

    需要用到的方法

    1. mergeCells():合并单元格,参数为起始单元格到结束单元格
    2. getCellByColumnAndRow(): 获取指定位置的单元格对象
    3. setValueExplicit():设置单元格内容,并指定样式
    4. getStyle():获取单元格样式对象
    5. applyFromArray():指定单元格样式

    代码片段解读

    1、填充单元格数据

    $sheet->mergeCells('A1:K2')->getCellByColumnAndRow(1, 1)->setValueExplicit('广告请款单', $contentType);
    
    1. mergeCells('A1:K2'): 从A1合并到K2
    2. getCellByColumnAndRow(1, 1): 获取第一行第一列单元格对象
    3. setValueExplicit('广告请款单', $contentType): 填充内容为广告请款单, 并指定为字符串类型($contentType = DataType::TYPE_STRING)

    2、指定样式

    $styleArray = [
        'alignment' => [
            // 水平居中
            'horizontal' => Alignment::HORIZONTAL_CENTER,
            // 垂直居中
            'vertical' => Alignment::VERTICAL_CENTER,
            // 自动换行
            'wrapText' => true
        ],
    ];
    $sheet->getStyle('A1:K21')->applyFromArray($styleArray);
    
    1. 'wrapText' => true 指定单元格内容自动换行,会自动解析文本内容中的 , 换行符
    2. applyFromArray() 方法在PhpOfficePhpSpreadsheetStyleAlignment类中,可根据需要指定参数;
    3. 注意:指定样式要在所有单元格数据设置之后,因为设置样式后返回的结果是PhpOfficePhpSpreadsheetStyleAlignment对象,没有mergeCells()等设置单元格的方法了

    剩余的麻烦点就是计算每个特定合并单元的位置了

    暴力实现

    起初在试验过程,理论基础不够充足,所以就通过暴力计算每个样式位置并进行设置了。

    $contentType = DataType::TYPE_STRING;
    $sheet->mergeCells('A1:K2')->getCellByColumnAndRow(1, 1)->setValueExplicit('广告请款单', $contentType);
    
    $sheet->mergeCells('A3:B4')->getCellByColumnAndRow(1, 3)->setValueExplicit('申请时间', $contentType);
    $sheet->mergeCells('C3:E4')->getCellByColumnAndRow(3, 3)->setValueExplicit(date('Y-m-d H:i:s', $data['apply_clear_time']), $contentType);
    $sheet->mergeCells('F3:G4')->getCellByColumnAndRow(6, 3)->setValueExplicit('广告编号', $contentType);
    $sheet->mergeCells('H3:K4')->getCellByColumnAndRow(8, 3)->setValueExplicit($data['ad_no'], $contentType);
    
    $sheet->mergeCells('A5:B6')->getCellByColumnAndRow(1, 5)->setValueExplicit('收款单位', $contentType);
    $sheet->mergeCells('C5:K6')->getCellByColumnAndRow(3, 5)->setValueExplicit($data['real_name'], $contentType);
    
    $sheet->mergeCells('A7:B8')->getCellByColumnAndRow(1, 7)->setValueExplicit('银行账户', $contentType);
    $sheet->mergeCells('C7:K8')->getCellByColumnAndRow(3, 7)->setValueExplicit($data['bank_no'], $contentType);
    
    $sheet->mergeCells('A9:B10')->getCellByColumnAndRow(1, 9)->setValueExplicit('开户行', $contentType);
    $sheet->mergeCells('C9:K10')->getCellByColumnAndRow(3, 9)->setValueExplicit($data['bank_name'], $contentType);
    
    $sheet->mergeCells('A11:B12')->getCellByColumnAndRow(1, 11)->setValueExplicit('金额', $contentType);
    $sheet->mergeCells('C11:E12')->getCellByColumnAndRow(3, 11)->setValueExplicit($data['amount'], $contentType);
    $sheet->mergeCells('F11:G12')->getCellByColumnAndRow(6, 11)->setValueExplicit('大写金额', $contentType);
    $sheet->mergeCells('H11:K12')->getCellByColumnAndRow(8, 11)->setValueExplicit($data['amount_desc'], $contentType);
    
    $sheet->mergeCells('A13:B14')->getCellByColumnAndRow(1, 13)->setValueExplicit('备注', $contentType);
    $sheet->mergeCells('C13:K14')->getCellByColumnAndRow(3, 13)->setValueExplicit($data['desc'], $contentType);
    
    $sheet->mergeCells('A15:D16')->getCellByColumnAndRow(1, 15)->setValueExplicit('广告BD审核', $contentType);
    $sheet->mergeCells('E15:H16')->getCellByColumnAndRow(5, 15)->setValueExplicit('广告主管审核', $contentType);
    $sheet->mergeCells('I15:K16')->getCellByColumnAndRow(9, 15)->setValueExplicit('总经理审核', $contentType);
    
    $sheet->mergeCells('A17:D19')->getCellByColumnAndRow(1, 17)->setValueExplicit($data['auth_log_list'][0]['auth_desc'], $contentType);
    $sheet->mergeCells('E17:H19')->getCellByColumnAndRow(5, 17)->setValueExplicit($data['auth_log_list'][1]['auth_desc'], $contentType);
    $sheet->mergeCells('I17:K19')->getCellByColumnAndRow(9, 17)->setValueExplicit($data['auth_log_list'][2] ? $data['auth_log_list'][2]['auth_desc'] : '无需审核', $contentType);
    
    $sheet->mergeCells('A20:B21')->getCellByColumnAndRow(1, 20)->setValueExplicit('财务', $contentType);
    $sheet->mergeCells('C20:K21')->getCellByColumnAndRow(3, 20)->setValueExplicit('', $contentType);
    

    封装

    复杂点

    唯一需要计算一下的就是mergeCells()方法和getCellByColumnAndRow()方法的参数

    $sheet->mergeCells($start.':'.$end)->getCellByColumnAndRow($column_start, $row_start)->setValueExplicit($column[2], $contentType);
    

    但是通过暴力破解的过程也很好得到规律。

    通用方法

    public static function exportSpecialExcel($data, $filename='', $post=false)
    {
        // 此处只需要导出单条数据,对内存没要求,
        // ini_set('memory_limit', '3072M');
    
        if (empty($filename)) {
            $filename = date('Y-m-d') . '导出表格';
        }
    
        $pathinfo = pathinfo($filename);
        if (empty($pathinfo['extension']) || !in_array($pathinfo['extension'], ['xls', 'xlsx'])) {
            $filename = $filename . '.xlsx';
        }
    
        $spreadsheet = new Spreadsheet();
        $sheet= $spreadsheet->getActiveSheet();
    
        $contentType = DataType::TYPE_STRING;
    
        /**
         * column
         *  0 - 行高
         *  1 - 列宽
         *  2 - 数据内容
         */
        $row_start = 1;
        foreach ($data as $row) {
            $column_start = 1;
            foreach ($row as $column) {
                $start = (static::$column_header[$column_start]) . $row_start;
                $end = (static::$column_header[$column_start + $column[1] - 1]).($row_start + $column[0] - 1);
                $sheet->mergeCells($start.':'.$end)->getCellByColumnAndRow($column_start, $row_start)->setValueExplicit($column[2], $contentType);
                $column_start += $column[1];
            }
            $row_start += $row[0][0];
        }
    
        $styleArray = [
            'alignment' => [
                'horizontal' => Alignment::HORIZONTAL_CENTER,
                'vertical' => Alignment::VERTICAL_CENTER,
                'wrapText' => true
            ],
        ];
        $sheet->getStyle('A1:K21')->applyFromArray($styleArray);
    
        header('Content-Description: File Transfer');
        header('Expires: 0');
        header('Pragma: public');
        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');//告诉浏览器输出07Excel文件
        header('Content-Disposition: attachment;filename="' . $filename . '"');
        header('Cache-Control: max-age=0');
        $writer = new Xlsx($spreadsheet);
        $writer->save('php://output');
        //删除清空:
        LogHelper::access(memory_get_peak_usage(), 'export_memory');
        $spreadsheet->disconnectWorksheets();
        unset($spreadsheet);
        exit;
    }
    

    业务数据

    每个子元素数组由行高、列宽、数据内容三者组成

    $showData = [
        [
            [2, 11, '广告请款单'],
        ],
        [
            [2, 2, '申请时间'],
            [2, 3, date('Y-m-d H:i:s', $data['apply_clear_time'])],
            [2, 2, '广告编号'],
            [2, 4, $data['ad_no']],
        ],
        [
            [2, 2, '收款单位'],
            [2, 9, $data['real_name']],
        ],
        [
            [2, 2, '银行账户'],
            [2, 9, $data['bank_no']],
    
        ],
        [
            [2, 2, '开户行'],
            [2, 9, $data['bank_name']],
        ],
        [
            [2, 2, '金额'],
            [2, 3, $data['amount']],
            [2, 2, '大写金额'],
            [2, 4, $data['amount_desc']],
        ],
        [
            [2, 2, '备注'],
            [2, 9, $data['desc']],
        ],
        [
            [2, 4, '广告BD审核'],
            [2, 4, '广告主管审核'],
            [2, 3, '总经理审核'],
        ],
        [
            [3, 4, $data['auth_log_list'][0]['auth_desc']],
            [3, 4, $data['auth_log_list'][1]['auth_desc']],
            [3, 3, isset($data['auth_log_list'][2]) ? $data['auth_log_list'][2]['auth_desc'] : '无需审核'],
        ],
        [
            [2, 2, '财务'],
            [2, 9, ''],
        ],
    ];
    

    如此便实现了本次的业务需求,也便于今后相关业务功能的实现

    参考资料

    1. github-PhpSpreadsheet: github源码库,可学习安装
    2. phpspreadsheet 文档 全英文文档
    3. phpspreadsheet api 库的类和方法说明
    4. CSDN-详解PhpSpreadsheet设置单元格:由官方文档整理出的部分使用案例,但过于简单,直接使用仍然会出现问题
  • 相关阅读:
    UNIX 环境模拟工具Cygwin安装及使用图文教程
    转转转!SpringMVC访问静态资源的三种方式
    转!!!解释Eclipse下Tomcat项目部署路径问题(.metadata.pluginsorg.eclipse.wst.server.core mp0wtpwebapps)
    JavaWeb中读取文件资源的路径问题 -- 转自新浪博客
    springMVC学习(10)-上传图片
    springMVC学习(9)-全局异常处理
    springMVC学习(8)-数据回显
    springMVC学习(7)-springMVC校验
    springMVC学习(6)-包装pojo类型、数组、list、Map类型参数绑定
    springMVC学习(5)-参数绑定
  • 原文地址:https://www.cnblogs.com/zqunor/p/11712075.html
Copyright © 2020-2023  润新知