ResearchExpenseSheetExport.php 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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\WithTitle;
  7. use Maatwebsite\Excel\Concerns\WithCustomStartCell;
  8. use Maatwebsite\Excel\Events\AfterSheet;
  9. use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
  10. use PhpOffice\PhpSpreadsheet\Style\Alignment;
  11. use PhpOffice\PhpSpreadsheet\Style\Border;
  12. class ResearchExpenseSheetExport implements FromCollection, WithEvents, WithStyles, WithCustomStartCell, WithTitle
  13. {
  14. protected $sheetTitle; // Sheet 标签名,如 "2025-RD01"
  15. protected $data;
  16. protected $projectInfo;
  17. protected $year;
  18. public function __construct(string $sheetTitle, array $data, array $projectInfo = [])
  19. {
  20. $this->sheetTitle = $sheetTitle;
  21. $this->data = $data;
  22. $this->projectInfo = $projectInfo;
  23. // 自动从 Sheet 标题中提取前4位作为大标题年份
  24. $this->year = substr($sheetTitle, 0, 4);
  25. }
  26. public function title(): string
  27. {
  28. return $this->sheetTitle;
  29. }
  30. public function startCell(): string
  31. {
  32. return 'A7'; // 数据从 A7 开始写入
  33. }
  34. public function collection()
  35. {
  36. return collect($this->data);
  37. }
  38. public function registerEvents(): array
  39. {
  40. return [
  41. AfterSheet::class => function(AfterSheet $event) {
  42. $sheet = $event->sheet->getDelegate();
  43. // --- 1. 设置列宽 (精简适中版) ---
  44. $sheet->getColumnDimension('A')->setWidth(12); // 日期
  45. $sheet->getColumnDimension('B')->setWidth(6); // 种类
  46. $sheet->getColumnDimension('C')->setWidth(6); // 号数
  47. $sheet->getColumnDimension('D')->setWidth(30); // 摘要
  48. $sheet->getColumnDimension('E')->setWidth(14); // 会计金额
  49. $sheet->getColumnDimension('F')->setWidth(14); // 税法金额
  50. $sheet->getColumnDimension('G')->setWidth(13); // 人员人工
  51. $sheet->getColumnDimension('H')->setWidth(13); // 直接投入
  52. $sheet->getColumnDimension('I')->setWidth(11); // 折旧
  53. $sheet->getColumnDimension('J')->setWidth(11); // 无形资产
  54. $sheet->getColumnDimension('K')->setWidth(11); // 新产品
  55. $sheet->getColumnDimension('L')->setWidth(11); // 其他
  56. $sheet->getColumnDimension('M')->setWidth(18); // 委托境内
  57. $sheet->getColumnDimension('N')->setWidth(18); // 委托境外
  58. // --- 2. 设置行高 ---
  59. $sheet->getRowDimension('2')->setRowHeight(45); // 大标题行
  60. $sheet->getRowDimension('3')->setRowHeight(40); // 项目信息行
  61. $sheet->getRowDimension('4')->setRowHeight(22); // 表头1
  62. $sheet->getRowDimension('5')->setRowHeight(25); // 表头2
  63. $sheet->getRowDimension('6')->setRowHeight(60); // 表头底行 (容纳长文字)
  64. // --- 3. 第二行:大标题 (居中/加粗) ---
  65. $sheet->mergeCells("A2:N2");
  66. $sheet->setCellValue('A2', "{$this->year}年研发支出辅助账");
  67. $sheet->getStyle('A2')->applyFromArray([
  68. 'font' => ['size' => 16],
  69. 'alignment' => [
  70. 'horizontal' => Alignment::HORIZONTAL_CENTER,
  71. 'vertical' => Alignment::VERTICAL_CENTER,
  72. ],
  73. ]);
  74. // --- 4. 第三行:项目信息 (精准合并/无边框) ---
  75. // 项目编号:标签 ABC,值 DE
  76. $sheet->mergeCells("A3:C3");
  77. $sheet->setCellValue('A3', '项目编号:');
  78. $sheet->mergeCells("D3:E3");
  79. $sheet->setCellValue('D3', $this->projectInfo['code'] ?? '');
  80. // 项目名称:标签 F,值 G (开启换行)
  81. $sheet->setCellValue('F3', '项目名称:');
  82. $sheet->setCellValue('G3', $this->projectInfo['name'] ?? '');
  83. $sheet->getStyle('G3')->getAlignment()->setWrapText(true);
  84. $sheet->setCellValue('H3', '完成情况:');
  85. $sheet->setCellValue('I3', '已完成');
  86. $sheet->setCellValue('J3', '支出类型:');
  87. $sheet->setCellValue('K3', '费用化');
  88. $sheet->setCellValue('M3', '金额单位:');
  89. $sheet->setCellValue('N3', '元');
  90. // 第三行对齐
  91. $sheet->getStyle('A3:N3')->getAlignment()->setVertical(Alignment::VERTICAL_CENTER);
  92. // --- 5. 复杂表头绘制 (第 4-6 行) ---
  93. // A-D 凭证信息
  94. $sheet->mergeCells("A4:D5");
  95. $sheet->setCellValue('A4', '凭证信息');
  96. $sheet->setCellValue('A6', '日期');
  97. $sheet->setCellValue('B6', '种类');
  98. $sheet->setCellValue('C6', '号数');
  99. $sheet->setCellValue('D6', '摘要');
  100. // E-F 金额列 (垂直合并)
  101. $sheet->mergeCells("E4:E6");
  102. $sheet->setCellValue('E4', "会计凭证记载\n金额");
  103. $sheet->mergeCells("F4:F6");
  104. $sheet->setCellValue('F4', "税法规定的归\n集金额");
  105. // G-N 费用明细总标题
  106. $sheet->mergeCells("G4:N4");
  107. $sheet->setCellValue('G4', '费用明细(税法规定)');
  108. // 各科目垂直合并 (5-6行)
  109. $subItems = [
  110. 'G' => '人员人工费用', 'H' => '直接投入费用', 'I' => '折旧费用',
  111. 'J' => '无形资产摊销', 'K' => '新产品设计费等', 'L' => '其他相关费用'
  112. ];
  113. foreach ($subItems as $col => $text) {
  114. $sheet->mergeCells("{$col}5:{$col}6");
  115. $sheet->setCellValue("{$col}5", $text);
  116. }
  117. // 委托研发费用
  118. $sheet->mergeCells("M5:N5");
  119. $sheet->setCellValue('M5', '委托研发费用');
  120. $sheet->setCellValue('M6', "委托境内机构或个人进行研\n发活动所发生的费用");
  121. $sheet->setCellValue('N6', "委托境外机构进行研发活动\n所发生的费用");
  122. // --- 6. 开启换行 ---
  123. $sheet->getStyle('A4:N6')->getAlignment()->setWrapText(true);
  124. },
  125. ];
  126. }
  127. public function styles(Worksheet $sheet)
  128. {
  129. $highestRow = $sheet->getHighestRow();
  130. // 全局基础样式:从第 4 行开始加边框 (跳过第 3 行项目信息)
  131. $sheet->getStyle("A4:N{$highestRow}")->applyFromArray([
  132. 'borders' => [
  133. 'allBorders' => ['borderStyle' => Border::BORDER_THIN],
  134. ],
  135. 'alignment' => [
  136. 'vertical' => Alignment::VERTICAL_CENTER,
  137. 'horizontal' => Alignment::HORIZONTAL_CENTER,
  138. ],
  139. 'font' => ['name' => '宋体', 'size' => 10],
  140. ]);
  141. return [];
  142. }
  143. }