Laravel Excel -公式添加额外的@符号,打破公式

9udxz4iz  于 2023-04-13  发布在  其他
关注(0)|答案(1)|浏览(172)

我正在Laravel中使用Export方法来生成包含公式的XLSX文件。一切正常,但在Export上,公式在几个地方添加了一个额外的@符号,然后打破了公式...单元格值呈现为#VALUE
这是一个函数:

namespace App\Exports\Reports;

use App\Exports\Sheets\Reports\SheetOne;
use App\Exports\Sheets\Reports\SheetTwo;
use App\Exports\Sheets\Reports\SheetThree;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;

class ExcelReport implements WithMultipleSheets {
  public function sheets(): array {
    return [
      new SheetOne($this->sheetOneData),
      new SheetTwo($this->sheetTwoData),
      new SheetThree($this->sheetThreeData)
    ];
  }
}

问题在“表2”上:

namespace App\Exports\Sheets\Reports;

use App\Models\SheetTwoData;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\WithTitle;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\FromCollection;

class SheetTwo implements FromCollection, WithHeadings, WithMapping, WithTitle {
  protected Collection $sheetTwoData;
  private int $maxIndex;

  public function __construct(Collection $sheetTwoData) {
    $this->sheetTwoData = $sheetTwoData;
    $this->maxIndex = 2 + $sheetTwoData->count() - 1;
  }

  public function collection(): collection {
    $calcOne = "SheetTwo!D2:D{$this->maxIndex}";
    $calcTwo = "SheetTwo!G2:G{$this->maxIndex}";

    return $this->sheetTwoData->push([
      '',
      'Totals',
      "=SUBTOTAL(109, C2:C{$this->maxIndex})",
      "=SUM(IF({$calcOne}<>\"\",1/COUNTIF({$calcOne},{$calcOne}),0))",
      "=SUM(IF({$calcTwo}<>\"\",1/COUNTIF({$calcTwo},{$calcTwo}),0))",
      ''
    ]);
  }

  public function headings(): array {
    return [
      'Column A',
      'Column B',
      'Column C',
      'Column D',
      'Column E',
      'Column F',
      'Column G'
    ];
  }

  public function map($row): array {
    if ($row instanceof SheetTwoData) {
      return $row->toArray();
    }

    return $row;
  }

  public function title(): string {
    return 'SheetTwo';
  }

然后通过一个按钮将其连接到POST表单,当单击该按钮时,通过Chrome(或任何浏览器)将生成的XLSX作为下载流传输:

if ($request->method() == 'POST') {
  return Excel::download(new ExcelReport([
    'sheetOneData' => SheetOneData::all(),
    'sheetTwoData' => SheetTwoData::all(),
    'sheetThreeData' => SheetThreeData::all()
  ]), 'excel-report.xlsx');
}

这一切都很好,文件被下载,但$calcOne$calcTwo字符串被调整。如果我在return $row;(用这些公式呈现行的处理程序)之前添加dd($row);,我会看到这样的结果:

array:6 [▼
  0 => ""
  1 => "Totals"
  2 => "=SUBTOTAL(109, C2:C50)"
  3 => "=SUM(IF(SheetTwo!D2:D50<>"",1/COUNTIF(SheetTwo!D2:D50,SheetTwo!D2:D50),0))"
  4 => "=SUM(IF(SheetTwo!G2:G50<>"",1/COUNTIF(SheetTwo!G2:G50,SheetTwo!G2:G50),0))"
  5 => ""
]

但是,在XLSX文件中,这些公式呈现为:

=SUM(IF(@SheetTwo!D2:D50<>"",1/COUNTIF(SheetTwo!D2:D50,@SheetTwo!D2:D50),0))

$calcTwo,目标G2:G50也以同样的方式被打破)。
以前有人遇到过这个问题吗?Google不太有帮助,因为搜索@"at symbol"非常模糊,Excel的帮助非常糟糕。谢谢!
旁注:如果我手动从生成的XLSX文件中删除这个@符号,那么公式就可以按预期工作。这个XLSX文件的全部意义在于我可以生成它并通过电子邮件发送,所以目前我可以在发送之前修改它,但将来可能会完全自动化。

pn9klfpd

pn9klfpd1#

我不知道为什么会发生这种情况,但maatwebsite/excel只是phpoffice/phpspreadsheet的 Package 器。每当我不得不包含公式时,我都会通过事件获取底层的Phpspreadsheet示例。
但问题是,这些方法是静态的,所以如果不使用丑陋的hack,就无法真正访问$this->maxIndex

namespace App\Exports\Sheets\Reports;

use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\{FromCollection, RegistersEventListeners, WithEvents, WithHeadings, WithMapping, WithTitle};
use Maatwebsite\Excel\Events\AfterSheet;

class SheetTwo implements FromCollection, WithEvents, WithHeadings, WithMapping, WithTitle,
{
    use RegistersEventListeners;

    protected Collection $sheetTwoData;

    public function __construct(Collection $sheetTwoData)
    {
        $this->sheetTwoData = $sheetTwoData;
    }

    public function collection(): Collection
    {
        return $this->sheetTwoData;
    }

    ...

    public static function afterSheet(AfterSheet $event)
    {
        // $event->sheet returns \Maatwebsite\Excel\Sheet which has all the methods of \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet
        $highestRow = $event->sheet->getHighestRow();
        $newRow = $highestRow + 1; 

        $event->sheet->setCellValue('B' . $newRow, 'Totals');
        $event->sheet->setCellValue('C' . $newRow, "=SUBTOTAL(109, C2:C{})");
        $event->sheet->setCellValue('D' . $newRow, "=SUM(IF(D2:D{$highestRow}<>\"\",1/COUNTIF(D2:D{$highestRow},D2:D{$highestRow}),0))");
        $event->sheet->setCellValue('E' . $newRow, "=SUM(IF(G2:G{$highestRow}<>\"\",1/COUNTIF(G2:G{$highestRow},G2:G{$highestRow}),0))");
    }
}

考虑到这些是SheetTwo工作表上的公式,您不需要在其值中指定SheetTwo!

相关问题