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 [];
|
|
}
|
|
}
|