data = $data; $this->month = $month; $this->year = $year; $this->workingDays = $workingDays; $this->daysInMonth = cal_days_in_month(CAL_GREGORIAN, $month, $year); } public function registerEvents(): array { return [ AfterSheet::class => function(AfterSheet $event) { $sheet = $event->sheet->getDelegate(); $lastRow = count($this->data) + 4; $noteColumn = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($this->daysInMonth + 4); // Xử lý đặc biệt cho cột Notes $sheet->getStyle("{$noteColumn}5:{$noteColumn}{$lastRow}") ->getAlignment() ->setWrapText(true) ->setVertical(Alignment::VERTICAL_TOP) ->setHorizontal(Alignment::HORIZONTAL_LEFT); // Tắt auto-size cho cột Notes và set độ rộng cố định $sheet->getColumnDimension($noteColumn) ->setAutoSize(false) ->setWidth(60); // Tự động điều chỉnh chiều cao cho từng dòng có nội dung for ($row = 5; $row <= $lastRow; $row++) { $cellValue = $sheet->getCell($noteColumn . $row)->getValue(); if (!empty($cellValue)) { // Tính toán chiều cao dựa trên nội dung $sheet->getRowDimension($row)->setRowHeight(-1); // Tính toán lại chiều cao dựa trên số dòng trong nội dung $lineCount = substr_count($cellValue, "\n") + 1; $minHeight = max(30, $lineCount * 15); // 15 pixels cho mỗi dòng // Lấy chiều cao hiện tại sau khi auto-size $currentHeight = $sheet->getRowDimension($row)->getRowHeight(); // Nếu chiều cao tự động nhỏ hơn chiều cao tối thiểu, sử dụng chiều cao tối thiểu if ($currentHeight < $minHeight) { $sheet->getRowDimension($row)->setRowHeight($minHeight); } } else { $sheet->getRowDimension($row)->setRowHeight(30); } } // Refresh các tính toán của Excel $sheet->calculateColumnWidths(); }, ]; } public function array(): array { // Lấy headers $headers = $this->headings(); // Lấy dữ liệu người dùng $userRows = []; foreach ($this->data as $user) { $row = [ $user['user']['name'] ?? 'Unknown', 0, // Total days $this->workingDays, // Off days (initialize with working days) ]; $totalDays = 0; // Add data for each day in month for ($day = 1; $day <= $this->daysInMonth; $day++) { $dayData = ''; if (isset($user['history'])) { foreach ($user['history'] as $history) { if ($history['day'] === $day) { $total = $history['total'] ?? 0; if ($total >= 7 * 3600) { $dayData = '1'; $totalDays += 1; } else if ($total >= 3.5 * 3600) { $dayData = '0.5'; $totalDays += 0.5; } break; } } } $row[] = $dayData; } // Update total and off days $row[1] = $totalDays; $row[2] = $this->workingDays - $totalDays; // Add Notes column with formatted content $notes = []; if (isset($user['history'])) { foreach ($user['history'] as $history) { if (!empty($history['notes'])) { $dayNotes = []; foreach ($history['notes'] as $note) { $dayNotes[] = "- {$note['reasonName']} ({$note['timeTypeName']}): {$note['note']}"; } if (!empty($dayNotes)) { $notes[] = "Day {$history['day']}:\n" . implode("\n", $dayNotes); } } } } $row[] = !empty($notes) ? implode("\n\n", $notes) : ''; $userRows[] = $row; } return array_merge($headers, $userRows); } public function headings(): array { $firstRow = ['Day', '', '']; // Second row: Day of week $secondRow = ['', '', '']; $date = Carbon::create($this->year, $this->month, 1); for ($day = 1; $day <= $this->daysInMonth; $day++) { $firstRow[] = $day; $secondRow[] = $date->format('D'); $date->addDay(); } // Add Notes column $firstRow[] = 'Notes'; $secondRow[] = ''; return [$firstRow, $secondRow]; } public function styles(Worksheet $sheet) { $lastColumn = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($this->daysInMonth + 4); $lastRow = count($this->data) + 4; $noteColumn = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($this->daysInMonth + 4); // Title and working days $sheet->mergeCells("A1:{$lastColumn}1"); $sheet->setCellValue('A1', "DANH SÁCH CHẤM CÔNG THÁNG {$this->month} NĂM {$this->year}"); $sheet->mergeCells("A2:{$lastColumn}2"); $sheet->setCellValue('A2', "Số ngày làm việc: {$this->workingDays}"); // Merge cells for "Day" title and set value $sheet->mergeCells("A3:C3"); $sheet->setCellValue('A3', 'Day'); // Set values for A4, B4, C4 $sheet->setCellValue('A4', 'User'); $sheet->setCellValue('B4', 'Total'); $sheet->setCellValue('C4', 'Off'); // Styling $sheet->getStyle("A1:{$lastColumn}1")->getFont()->setBold(true)->setSize(14); $sheet->getStyle("A2:{$lastColumn}2")->getFont()->setBold(true); $sheet->getStyle("A3:{$lastColumn}4")->getFont()->setBold(true); // Border style $borderStyle = [ 'borders' => [ 'allBorders' => [ 'borderStyle' => Border::BORDER_THIN, ], ], ]; // Apply borders to the data area $sheet->getStyle("A1:{$lastColumn}{$lastRow}")->applyFromArray($borderStyle); // Center align all cells except Notes column $sheet->getStyle("A1:{$lastColumn}{$lastRow}") ->getAlignment() ->setHorizontal(Alignment::HORIZONTAL_CENTER) ->setVertical(Alignment::VERTICAL_CENTER); // Left align Notes column và bật wrap text $sheet->getStyle("{$noteColumn}5:{$noteColumn}{$lastRow}") ->getAlignment() ->setHorizontal(Alignment::HORIZONTAL_LEFT) ->setVertical(Alignment::VERTICAL_TOP) ->setWrapText(true); // Set width for Note column - tăng độ rộng để hiển thị tốt hơn $sheet->getColumnDimension($noteColumn)->setWidth(60); // Tự động điều chỉnh chiều cao cho các dòng có nội dung Notes for ($row = 5; $row <= $lastRow; $row++) { $cellValue = $sheet->getCell($noteColumn . $row)->getValue(); if (!empty($cellValue)) { // Đết chiều cao tự động $sheet->getRowDimension($row)->setRowHeight(-1); // Đảm bảo chiều cao tối thiểu $currentHeight = $sheet->getRowDimension($row)->getRowHeight(); if ($currentHeight < 30) { $sheet->getRowDimension($row)->setRowHeight(30); } } else { // Chiều cao mặc định cho các dòng không có note $sheet->getRowDimension($row)->setRowHeight(30); } } // Set column widths $sheet->getColumnDimension('A')->setWidth(30); $sheet->getColumnDimension('B')->setWidth(10); $sheet->getColumnDimension('C')->setWidth(10); for ($i = 4; $i <= $this->daysInMonth + 3; $i++) { $sheet->getColumnDimension(\PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($i))->setWidth(5); } return []; } }