You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Laravel-Excel中实现单列合并并嵌套显示多列内容?

Laravel-Excel 实现主列合并并对应子列行数的解决方案

核心思路

要实现主列单元格纵向合并(行数等于对应子列数量),并在下方显示子列内容,需分两步完成:

  1. 构建符合表格结构的数据数组,主列仅在第一行显示,子列按行填充,空缺列留空;
  2. 通过Laravel-Excel的AfterSheet事件设置单元格合并规则,同时可添加样式优化显示效果。

步骤1:重构数据数组

从你的productGroup和all_product数据源中整理主列与子列的对应关系,生成规范的表格数据:

// 整理主列与子列的关联数据
$groupedProducts = [];
foreach ($productGroup as $group) {
    // 筛选当前分组下的有效子产品名称
    $subNames = [];
    foreach ($all_product as $product) {
        if ($group['id'] == $product->product_group_id && !empty($product->product_sur_name)) {
            $subNames[] = $product->product_sur_name;
        }
    }
    
    // 仅保留有子列的主列
    if (!empty($subNames)) {
        $groupedProducts[] = [
            'main_title' => $group['gorupName'], // 注意:此处字段名是你的代码拼写,若为笔误请修正为groupName
            'sub_items' => $subNames
        ];
    }
}

if ($customer_type == 2) {
    // 计算表格最大行数(取子列数量最多的分组的子列数)
    $maxRowCount = !empty($groupedProducts) ? max(array_map(fn($item) => count($item['sub_items']), $groupedProducts)) : 0;

    // 构建表格头部行
    $headerRow = array_merge(
        ['SL', 'Order No', 'Order Date', 'Challan No', 'Challan Date', 'Bill No', 'Party Name', 'Area'],
        array_column($groupedProducts, 'main_title'),
        ['Total']
    );

    // 构建子列数据行
    $dataRows = [];
    for ($i = 0; $i < $maxRowCount; $i++) {
        // 前8列固定留空
        $row = array_fill(0, 8, '');
        
        // 填充对应主列的子项,无则留空
        foreach ($groupedProducts as $group) {
            $row[] = $group['sub_items'][$i] ?? '';
        }
        
        // Total列留空
        $row[] = '';
        $dataRows[] = $row;
    }

    // 合并头部与数据行,得到最终表格数据
    $total_final_array = array_merge([$headerRow], $dataRows);
}

步骤2:创建Excel导出类并设置合并规则

使用Maatwebsite Excel的WithEvents接口,在表格生成后通过AfterSheet事件实现单元格合并:

namespace App\Exports;

use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Events\AfterSheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;

class ProductListExport implements FromCollection, WithEvents
{
    protected $tableData;
    protected $groupedData;

    public function __construct(array $tableData, array $groupedData)
    {
        $this->tableData = $tableData;
        $this->groupedData = $groupedData;
    }

    // 返回表格数据
    public function collection()
    {
        return collect($this->tableData);
    }

    // 注册表格事件
    public function registerEvents(): array
    {
        return [
            AfterSheet::class => function(AfterSheet $event) {
                $sheet = $event->sheet->getDelegate();
                $currentColumn = 9; // 前8列是固定列,主列从第9列(Excel的I列)开始

                foreach ($this->groupedData as $group) {
                    $subCount = count($group['sub_items']);
                    // 计算合并的单元格范围:第1行到第1+子列数行,当前列
                    $startCell = Coordinate::stringFromColumnIndex($currentColumn) . '1';
                    $endCell = Coordinate::stringFromColumnIndex($currentColumn) . (1 + $subCount);
                    
                    // 执行单元格合并
                    $sheet->mergeCells("$startCell:$endCell");

                    // 设置主列单元格样式(垂直居中、灰色背景)
                    $sheet->getStyle($startCell)->applyFromArray([
                        'alignment' => [
                            'vertical' => Alignment::VERTICAL_CENTER,
                            'horizontal' => Alignment::HORIZONTAL_CENTER,
                        ],
                        'fill' => [
                            'fillType' => Fill::FILL_SOLID,
                            'startColor' => ['rgb' => 'E0E0E0'],
                        ],
                    ]);

                    $currentColumn++;
                }

                // 可选:给所有单元格添加边框
                $lastColumn = Coordinate::stringFromColumnIndex($currentColumn);
                $lastRow = count($this->tableData);
                $sheet->getStyle("A1:$lastColumn$lastRow")->applyFromArray([
                    'borders' => [
                        'allBorders' => ['borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN],
                    ],
                ]);
            },
        ];
    }
}

步骤3:控制器中调用导出

在你的控制器方法中,实例化导出类并触发下载:

use App\Exports\ProductListExport;
use Maatwebsite\Excel\Facades\Excel;

public function exportExcel()
{
    // ... 此处省略获取productGroup、all_product、customer_type的逻辑 ...
    
    // 生成$total_final_array和$groupedProducts(参考步骤1)
    
    return Excel::download(
        new ProductListExport($total_final_array, $groupedProducts),
        'product_list.xlsx'
    );
}

关键说明

  1. 单元格合并必须通过AfterSheet事件实现,因为Laravel-Excel的数据填充阶段无法直接处理合并逻辑;
  2. 合并行数等于对应子列的数量,确保主列完全覆盖子列的行数;
  3. 数据行按最大子列数生成,避免子列内容被截断;
  4. 代码中gorupName为你的原代码拼写,若为数据库字段笔误请修正为groupName。

内容的提问来源于stack exchange,提问作者Anika Tabassum

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 15:57:16