Реализация генерации отчётов Excel и CSV
Экспорт данных в Excel и CSV используется для финансовых отчётов, выгрузки базы клиентов, аналитических таблиц. Для больших объёмов генерация выполняется в фоне с уведомлением пользователя по готовности.
Laravel: Laravel Excel (PhpSpreadsheet)
// Простой экспорт
class UsersExport implements FromCollection, WithHeadings, WithMapping
{
public function __construct(private Carbon $from, private Carbon $to) {}
public function collection(): Collection
{
return User::whereBetween('created_at', [$this->from, $this->to])
->with('orders')
->get();
}
public function headings(): array
{
return ['ID', 'Имя', 'Email', 'Заказов', 'Сумма', 'Дата регистрации'];
}
public function map($user): array
{
return [
$user->id,
$user->name,
$user->email,
$user->orders->count(),
number_format($user->orders->sum('total'), 2),
$user->created_at->format('d.m.Y'),
];
}
}
// Контроллер
public function export(Request $request): BinaryFileResponse
{
return Excel::download(
new UsersExport($request->date('from'), $request->date('to')),
'users-' . now()->format('Y-m-d') . '.xlsx'
);
}
Excel со стилями и формулами
class FinancialReportExport implements FromView, WithTitle, ShouldAutoSize
{
public function __construct(private array $data) {}
public function view(): View
{
return view('exports.financial-report', ['data' => $this->data]);
}
public function title(): string
{
return 'Финансовый отчёт';
}
// Дополнительные листы
public function sheets(): array
{
return [
new SummarySheet($this->data),
new DetailSheet($this->data),
];
}
}
// Стили в Blade-шаблоне
// resources/views/exports/financial-report.blade.php
Асинхронный экспорт для больших данных
// Экспорт 100k+ строк — выполнять в очереди
class LargeExport implements FromQuery, WithChunkReading
{
public function query(): Builder
{
return Order::with('items', 'user')->orderBy('id');
}
public function chunkSize(): int
{
return 1000;
}
}
// Controller
public function exportLarge(Request $request): JsonResponse
{
$filename = 'orders-' . now()->format('Y-m-d-H-i') . '.xlsx';
Excel::queue(new LargeExport, $filename, 's3')
->chain([new NotifyUserOfCompletedExport($request->user(), $filename)]);
return response()->json(['message' => 'Экспорт запущен, вы получите уведомление по готовности']);
}
Node.js: ExcelJS
import ExcelJS from 'exceljs';
async function generateOrdersReport(orders: Order[]): Promise<Buffer> {
const workbook = new ExcelJS.Workbook();
workbook.creator = 'MyApp';
const sheet = workbook.addWorksheet('Заказы', {
pageSetup: { paperSize: 9, orientation: 'landscape' },
});
// Заголовки с форматированием
sheet.columns = [
{ header: '№ Заказа', key: 'number', width: 15 },
{ header: 'Клиент', key: 'customer', width: 30 },
{ header: 'Сумма', key: 'total', width: 15, style: { numFmt: '#,##0.00 ₽' } },
{ header: 'Статус', key: 'status', width: 15 },
{ header: 'Дата', key: 'date', width: 15 },
];
// Стиль заголовка
sheet.getRow(1).eachCell(cell => {
cell.font = { bold: true, color: { argb: 'FFFFFFFF' } };
cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF1F3A5F' } };
cell.alignment = { vertical: 'middle', horizontal: 'center' };
});
sheet.getRow(1).height = 25;
// Данные
orders.forEach((order, index) => {
const row = sheet.addRow({
number: order.number,
customer: order.customer.name,
total: order.total,
status: order.status,
date: order.createdAt.toLocaleDateString('ru-RU'),
});
// Чередующийся фон строк
if (index % 2 === 0) {
row.eachCell(cell => {
cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF5F5F5' } };
});
}
});
// Итоговая строка
const totalRow = sheet.addRow({
number: 'ИТОГО',
total: { formula: `SUM(C2:C${orders.length + 1})` },
});
totalRow.font = { bold: true };
// Заморозить первую строку
sheet.views = [{ state: 'frozen', ySplit: 1 }];
// Автофильтр
sheet.autoFilter = { from: 'A1', to: `E1` };
return workbook.xlsx.writeBuffer() as Promise<Buffer>;
}
CSV экспорт
// PHP: потоковый CSV для очень больших данных
public function exportCsv(): StreamedResponse
{
return response()->streamDownload(function () {
$output = fopen('php://output', 'w');
fprintf($output, chr(0xEF) . chr(0xBB) . chr(0xBF)); // BOM для Excel
fputcsv($output, ['ID', 'Имя', 'Email', 'Дата'], ';');
User::lazy(500)->each(function (User $user) use ($output) {
fputcsv($output, [
$user->id,
$user->name,
$user->email,
$user->created_at->format('d.m.Y'),
], ';');
});
fclose($output);
}, 'users-' . now()->format('Y-m-d') . '.csv');
}
Срок реализации
Excel/CSV экспорт с базовыми стилями для Laravel или Node.js: 1–2 дня. Асинхронный экспорт больших объёмов с уведомлением: 2–3 дня. Сложные многолистовые отчёты с формулами: 3–4 дня.







