ItemSalarySheetExport.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. <?php
  2. namespace App\Exports;
  3. use Maatwebsite\Excel\Concerns\FromCollection;
  4. use Maatwebsite\Excel\Concerns\WithEvents;
  5. use Maatwebsite\Excel\Concerns\WithStyles;
  6. use Maatwebsite\Excel\Concerns\WithCustomStartCell;
  7. use Maatwebsite\Excel\Events\AfterSheet;
  8. use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
  9. use PhpOffice\PhpSpreadsheet\Style\Alignment;
  10. use PhpOffice\PhpSpreadsheet\Style\Border;
  11. use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
  12. class ItemSalarySheetExport implements FromCollection, WithEvents, WithStyles, WithCustomStartCell
  13. {
  14. protected $projects;
  15. protected $data;
  16. protected $company;
  17. public function __construct(array $projects, array $data, $company)
  18. {
  19. $this->projects = $projects;
  20. $this->data = $data;
  21. $this->company = $company;
  22. }
  23. /**
  24. * 数据从第 5 行开始写入(1-4行留给自定义表头)
  25. */
  26. public function startCell(): string
  27. {
  28. return 'A5';
  29. }
  30. /**
  31. * 返回导出数据集合
  32. */
  33. public function collection()
  34. {
  35. return collect($this->data);
  36. }
  37. /**
  38. * 处理复杂的表头合并、列宽、固定文字
  39. */
  40. public function registerEvents(): array
  41. {
  42. return [
  43. AfterSheet::class => function(AfterSheet $event) {
  44. $sheet = $event->sheet->getDelegate();
  45. // 1. 计算总列数
  46. $projectCount = count($this->projects);
  47. $totalColNum = 1 + ($projectCount * 2) + 1; // 年月(1) + 每个项目2列 + 合计(1)
  48. $highestColumn = Coordinate::stringFromColumnIndex($totalColNum);
  49. // --- 2. 设置列宽 ---
  50. $sheet->getColumnDimension('A')->setWidth(15); // 年月列
  51. for ($i = 0; $i < $projectCount; $i++) {
  52. $startColNum = 2 + ($i * 2);
  53. $colLetterDays = Coordinate::stringFromColumnIndex($startColNum); // 天数
  54. $colLetterSalary = Coordinate::stringFromColumnIndex($startColNum + 1); // 工资
  55. // 设置比例:工资约为天数的 2 倍强
  56. $sheet->getColumnDimension($colLetterDays)->setWidth(7);
  57. $sheet->getColumnDimension($colLetterSalary)->setWidth(16);
  58. // --- 3. 第三、四行:RD项目表头设置 ---
  59. // 第三行项目名水平合并 (B3:C3)
  60. $sheet->mergeCells("{$colLetterDays}3:{$colLetterSalary}3");
  61. $sheet->setCellValue("{$colLetterDays}3", $this->projects[$i]);
  62. // 第四行子标题
  63. $sheet->setCellValue("{$colLetterDays}4", '天数');
  64. $sheet->setCellValue("{$colLetterSalary}4", '工资');
  65. }
  66. // 合计列宽度
  67. $sheet->getColumnDimension($highestColumn)->setWidth(18);
  68. // --- 4. 第一行:主标题 ---
  69. $sheet->mergeCells("A1:{$highestColumn}1");
  70. $sheet->setCellValue('A1', '研发项目工资总表');
  71. $sheet->getStyle('A1')->getFont()->setSize(14);
  72. $sheet->getStyle('A1')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
  73. // --- 5. 第二行:单位名称 ---
  74. $sheet->mergeCells("A2:{$highestColumn}2");
  75. $sheet->setCellValue('A2', '单位名称:'. $this->company);
  76. $sheet->getStyle('A2')->getFont()->setSize(14);
  77. // --- 6. 垂直合并“年月”和“合计” ---
  78. $sheet->mergeCells('A3:A4');
  79. $sheet->setCellValue('A3', '年月');
  80. $lastColLetter = $highestColumn;
  81. $sheet->mergeCells("{$lastColLetter}3:{$lastColLetter}4");
  82. $sheet->setCellValue("{$lastColLetter}3", '合计');
  83. // 表头区域整体居中
  84. $sheet->getStyle("A3:{$highestColumn}4")->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER);
  85. },
  86. ];
  87. }
  88. /**
  89. * 设置表格基础样式和边框
  90. */
  91. public function styles(Worksheet $sheet)
  92. {
  93. $highestRow = $sheet->getHighestRow();
  94. $highestColumn = $sheet->getHighestColumn();
  95. // 定义统一的边框和对齐样式
  96. $commonStyle = [
  97. 'borders' => [
  98. 'allBorders' => [
  99. 'borderStyle' => Border::BORDER_THIN,
  100. 'color' => ['argb' => '000000'],
  101. ],
  102. ],
  103. 'alignment' => [
  104. 'vertical' => Alignment::VERTICAL_CENTER,
  105. 'horizontal' => Alignment::HORIZONTAL_CENTER,
  106. ],
  107. 'font' => [
  108. 'name' => '宋体',
  109. 'size' => 14,
  110. ],
  111. ];
  112. $sheet->getStyle("A1:{$highestColumn}{$highestRow}")->applyFromArray($commonStyle);
  113. $sheet->getStyle("A1")->getFont()->setSize(14);
  114. $sheet->getStyle("A2")->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT);
  115. return [];
  116. }
  117. }