ManagementSystem/BACKEND/app/Exports/TimekeepingExport.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 [];
}
}