248 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
			
		
		
	
	
			248 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
<?php
 | 
						|
 | 
						|
namespace App\Exports;
 | 
						|
 | 
						|
use Carbon\Carbon;
 | 
						|
use Maatwebsite\Excel\Concerns\FromArray;
 | 
						|
use Maatwebsite\Excel\Concerns\WithEvents;
 | 
						|
use Maatwebsite\Excel\Concerns\WithHeadings;
 | 
						|
use Maatwebsite\Excel\Concerns\WithStyles;
 | 
						|
use Maatwebsite\Excel\Events\AfterSheet;
 | 
						|
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
 | 
						|
use PhpOffice\PhpSpreadsheet\Style\Border;
 | 
						|
use PhpOffice\PhpSpreadsheet\Style\Alignment;
 | 
						|
 | 
						|
class TimekeepingExport implements FromArray, WithHeadings, WithStyles, WithEvents
 | 
						|
{
 | 
						|
    protected $data;
 | 
						|
    protected $month;
 | 
						|
    protected $year;
 | 
						|
    protected $workingDays;
 | 
						|
    protected $daysInMonth;
 | 
						|
 | 
						|
    public function __construct($data, $month, $year, $workingDays)
 | 
						|
    {
 | 
						|
        $this->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 [];
 | 
						|
    }
 | 
						|
} 
 |