SpoutImport.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. <?php
  2. namespace App\Models;
  3. //安装 composer require box/spout
  4. use Box\Spout\Writer\Common\Creator\Style\StyleBuilder;
  5. use Box\Spout\Common\Entity\Style\CellAlignment;
  6. use Box\Spout\Reader\Common\Creator\ReaderEntityFactory;
  7. use Box\Spout\Writer\Common\Creator\WriterEntityFactory;
  8. use Illuminate\Support\Facades\File;
  9. use Illuminate\Support\Facades\Log;
  10. class SpoutImport
  11. {
  12. private $headers = []; // 表头
  13. private $request = null; // 请求对象
  14. private $filePath = ""; // 文件路径
  15. private $importNum = 1000; // 单次导入数量
  16. private $filename = "excel_import"; // 文件名
  17. private $firstRowContent = []; // 第一行内容
  18. /**
  19. * 初始化
  20. *
  21. * @param array $headers 表头
  22. * @param [type] $query
  23. */
  24. public function __construct(array $headers)
  25. {
  26. $this->headers = $headers;
  27. }
  28. // 设置请求对象
  29. public function setRequest($request)
  30. {
  31. $this->request = $request;
  32. return $this;
  33. }
  34. // 设置文件路径
  35. public function setFilePath($filePath)
  36. {
  37. $this->filePath = $filePath;
  38. return $this;
  39. }
  40. // 设置单次导入数量
  41. public function setImportNum($importNum)
  42. {
  43. $this->importNum = $importNum;
  44. return $this;
  45. }
  46. // 设置文件名
  47. public function setFilename($filename)
  48. {
  49. $this->filename = $filename;
  50. return $this;
  51. }
  52. // 获取第一行内容
  53. public function getFirstRowContent()
  54. {
  55. return $this->firstRowContent;
  56. }
  57. /**
  58. * 获取表格数据
  59. *
  60. * @param string $saveCatalogue 文件流存储的目录,指定文件无需设置
  61. * @return array
  62. */
  63. public function getExcelData($saveCatalogue = "imports/")
  64. {
  65. if ($this->request) {
  66. // 获取上传的文件
  67. $file = $this->request->file('file');
  68. // 生成唯一的文件名
  69. $filename = $this->filename . uniqid() . $file->getClientOriginalExtension();
  70. $file->move(public_path($saveCatalogue), $filename);
  71. $filePath = public_path($saveCatalogue) . $filename;
  72. } else {
  73. if (empty($this->filePath)) {
  74. return false;
  75. }
  76. $filePath = $this->filePath;
  77. }
  78. // 读取 Excel 文件
  79. $reader = ReaderEntityFactory::createXLSXReader();
  80. $reader->open($filePath);
  81. $listAll = [];
  82. $isFirstRow = true;
  83. foreach ($reader->getSheetIterator() as $sheet) {
  84. foreach ($sheet->getRowIterator() as $row) {
  85. if ($isFirstRow) {
  86. // 跳过第一行(表头)
  87. foreach ($row->getCells() as $cell) {
  88. $this->firstRowContent[] = trim($cell->getValue());
  89. }
  90. $isFirstRow = false;
  91. continue;
  92. }
  93. if (count($listAll) > $this->importNum) {
  94. return ['code' => 0, 'msg' => "单次导入限制{$this->importNum}条"];
  95. }
  96. $list = [];
  97. $cells = $row->getCells();
  98. if($this->headers){
  99. $i = 0;
  100. foreach ($this->headers as $value) {
  101. $list[$value] = trim($cells[$i]->getValue());
  102. $i++;
  103. }
  104. }else{
  105. foreach ($cells as $cell) {
  106. $list[] = trim($cell->getValue());
  107. }
  108. }
  109. $listAll[] = $list;
  110. }
  111. }
  112. $reader->close();
  113. return $listAll;
  114. }
  115. /**
  116. * 获取执行结果
  117. *
  118. * @param array $dataList 数据列表
  119. * @param string $saveCatalogue 文件流存储的目录
  120. * @return String 执行结果文件路径
  121. */
  122. public function getResult(array $dataList, $saveCatalogue = "imports/out/")
  123. {
  124. $writer = WriterEntityFactory::createXLSXWriter();
  125. $filename = $this->filename . "_out" . uniqid() . '.xlsx';
  126. if (!File::exists(public_path($saveCatalogue))) {
  127. File::makeDirectory(public_path($saveCatalogue), 0777, true, true);
  128. }
  129. $file_path = public_path($saveCatalogue) . $filename;
  130. $writer->openToFile($file_path);
  131. // 添加表头
  132. $headers = array_keys($this->headers);
  133. $headersValue = array_values($this->headers);
  134. array_push($headers, '执行结果');
  135. array_push($headersValue, 'result');
  136. $header = WriterEntityFactory::createRowFromArray($headers);
  137. $writer->addRow($header);
  138. foreach ($dataList as $value) {
  139. $rowData = [];
  140. foreach ($headersValue as $item) {
  141. $rowData[] = $value[$item];
  142. }
  143. $row = WriterEntityFactory::createRowFromArray($rowData);
  144. $writer->addRow($row);
  145. }
  146. $writer->close();
  147. return $saveCatalogue . $filename;
  148. }
  149. // 生成导入模板 [ 安装PhpSpreadsheet扩展 composer require phpoffice/phpspreadsheet ]
  150. function generateImportTemplat(array $headers, array $widthArr = [])
  151. {
  152. // 创建 Spout XLSX 写入器
  153. $writer = WriterEntityFactory::createXLSXWriter();
  154. // 保存到临时文件
  155. $tempFilePath = sys_get_temp_dir() . '/import_template.xlsx';
  156. // 打开 Spout 写入器并开始写入到临时文件
  157. $writer->openToFile($tempFilePath);
  158. // 定义表头样式
  159. $headerStyle = (new StyleBuilder())
  160. ->setCellAlignment(CellAlignment::CENTER)
  161. ->setFontBold()
  162. ->setFontSize(12)
  163. ->build();
  164. // 写入表头
  165. $headerRow = WriterEntityFactory::createRowFromArray($headers, $headerStyle);
  166. $writer->addRow($headerRow);
  167. // 关闭 Spout 写入器
  168. $writer->close();
  169. // 使用 PHPSpreadsheet 加载生成的临时文件
  170. $spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($tempFilePath);
  171. // 获取活动工作表
  172. $sheet = $spreadsheet->getActiveSheet();
  173. if (empty($widthArr)) {
  174. // 设置列宽度,可以根据内容动态调整或自定义列宽
  175. for ($col = 'A'; $col <= $sheet->getHighestColumn(); $col++) {
  176. $sheet->getColumnDimension($col)->setAutoSize(true); // 自动调整列宽
  177. }
  178. } else {
  179. // 设置列宽的示例(如果你想自定义宽度)
  180. $index = 0;
  181. for ($col = 'A'; $col <= $sheet->getHighestColumn(); $col++) {
  182. $sheet->getColumnDimension($col)->setWidth($widthArr[$index]); // 自定义列宽
  183. $index++;
  184. }
  185. }
  186. // 保存处理后的文件
  187. $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx');
  188. $outputFilePath = $this->filename;
  189. // 提供下载
  190. header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
  191. header('Content-Disposition: attachment;filename="' . $outputFilePath . '.xlsx"');
  192. header('Cache-Control: max-age=0');
  193. header('Cache-Control: max-age=1');
  194. $writer->save('php://output'); // 直接输出到浏览器
  195. // 删除临时文件(如果需要)
  196. unlink($tempFilePath);
  197. }
  198. }