TableHeadExport.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. <?php
  2. namespace App\Exports;
  3. use Illuminate\Support\Collection;
  4. use Maatwebsite\Excel\Concerns\FromCollection;
  5. use Maatwebsite\Excel\Concerns\WithCustomValueBinder;
  6. use Maatwebsite\Excel\Concerns\WithHeadings;
  7. use Maatwebsite\Excel\Concerns\WithStrictNullComparison;
  8. use Maatwebsite\Excel\Concerns\WithEvents;
  9. use Maatwebsite\Excel\Events\AfterSheet;
  10. use PhpOffice\PhpSpreadsheet\Cell\DefaultValueBinder;
  11. use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
  12. class TableHeadExport extends DefaultValueBinder implements
  13. WithCustomValueBinder,
  14. FromCollection,
  15. WithStrictNullComparison,
  16. WithHeadings,
  17. WithEvents
  18. {
  19. protected $data;
  20. protected $headers;
  21. protected $headerComments; // 表头批注:键=表头名,值=批注内容
  22. public function __construct($data, $headers = [], $headerComments = [], $enums = [])
  23. {
  24. $this->data = $data;
  25. $this->headers = $headers;
  26. $this->headerComments = $headerComments;
  27. $this->enums = $enums; // 例如:['性别' => ['男', '女'], '状态' => ['启用', '禁用']]
  28. }
  29. public function collection()
  30. {
  31. return new Collection($this->createData());
  32. }
  33. public function createData()
  34. {
  35. return $this->export();
  36. }
  37. public function headings(): array
  38. {
  39. return $this->headers;
  40. }
  41. private function export()
  42. {
  43. $list = [];
  44. foreach ($this->data as $v) {
  45. $list[] = $v;
  46. }
  47. return $list;
  48. }
  49. public function registerEvents(): array
  50. {
  51. return [
  52. AfterSheet::class => function(AfterSheet $event) {
  53. if (empty($this->headerComments)) {
  54. return; // 不传就不加批注
  55. }
  56. $sheet = $event->sheet->getDelegate();
  57. // 1. 获取总列数
  58. $columnCount = count($this->headers);
  59. // 2. 循环设置每一列的宽度
  60. for ($i = 1; $i <= $columnCount; $i++) {
  61. $columnLetter = Coordinate::stringFromColumnIndex($i);
  62. // 设置固定宽度,例如 20
  63. $sheet->getColumnDimension($columnLetter)->setWidth(25);
  64. // 或者设置为自动宽度(根据内容自适应)
  65. // $sheet->getColumnDimension($columnLetter)->setAutoSize(true);
  66. }
  67. // --- 2. 核心:添加下拉枚举 (新逻辑) ---
  68. foreach ($this->headers as $index => $headerName) {
  69. if (!isset($this->enums[$headerName])) continue;
  70. $columnLetter = Coordinate::stringFromColumnIndex($index + 1);
  71. $options = $this->enums[$headerName];
  72. // 设置下拉范围,例如从第 2 行到第 1000 行
  73. $range = "{$columnLetter}2:{$columnLetter}1000";
  74. $validation = $sheet->getDataValidation($range);
  75. $validation->setType(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::TYPE_LIST);
  76. $validation->setErrorStyle(\PhpOffice\PhpSpreadsheet\Cell\DataValidation::STYLE_STOP);
  77. $validation->setAllowBlank(true);
  78. $validation->setShowInputMessage(true);
  79. $validation->setShowErrorMessage(true);
  80. $validation->setShowDropDown(true);
  81. $validation->setErrorTitle('输入错误');
  82. $validation->setError('请从下拉列表中选择有效选项');
  83. $validation->setPromptTitle('选择提示');
  84. $validation->setPrompt('请选择一个预设值');
  85. // 将数组转为 Excel 识别的格式:"项1,项2,项3"
  86. $validation->setFormula1('"' . implode(',', $options) . '"');
  87. }
  88. foreach ($this->headers as $index => $headerName) {
  89. if (!isset($this->headerComments[$headerName])) {
  90. continue; // 该表头没设置批注
  91. }
  92. $columnLetter = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($index + 1);
  93. $cell = $columnLetter . '1';
  94. $commentText = $this->headerComments[$headerName];
  95. // 创建批注
  96. $comment = $sheet->getComment($cell);
  97. $comment->getText()->createTextRun($commentText);
  98. $comment->setAuthor('系统提示');
  99. // 设置批注框大小(可调整数值)
  100. $comment->setWidth('200pt'); // 宽度
  101. $comment->setHeight('100pt'); // 高度
  102. }
  103. }
  104. ];
  105. }
  106. }