MultiHeadExcel.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. <?php
  2. namespace excel;
  3. class MultiHeadExcel
  4. {
  5. //直接调用export_help方法
  6. //
  7. //-->二级表头格式
  8. //$head=[
  9. // '字段a'=>'标题名称',
  10. // '字段bc'=>[
  11. // 'name'=>'标题名称',
  12. // 'children'=>[
  13. // '字段b'=>'标题名称',
  14. // '字段c'=>'标题名称'
  15. // ]
  16. // ]
  17. //]
  18. //
  19. //-->三级表头格式
  20. //$head=[
  21. // '字段a'=>'a',
  22. // '字段bcd'=>[
  23. // 'name'=>'b',
  24. // 'children'=>[
  25. // '字段bc'=>[
  26. // 'name'=>'bc',
  27. // 'children'=>[
  28. // '字段b'=>'b',
  29. // '字段c'=>'c',
  30. // ],
  31. // ],
  32. // '字段d'=>'d'
  33. // ],
  34. // ],
  35. //];
  36. //
  37. protected $max_width;
  38. public function __construct()
  39. {
  40. require_once(__DIR__.'/PHPExcel.php');
  41. }
  42. /**
  43. * 处理表头数据
  44. * @param array $head 表头数组
  45. * @param array $heads 返回数组
  46. * @param int $x x轴
  47. * @param int $y y轴
  48. * @return array
  49. */
  50. public function changehead($head=[],&$heads=[],$x=0,$y=0)
  51. {
  52. if(empty($heads[$y])){
  53. $heads[$y] = [];
  54. }
  55. $w = 0; //宽度
  56. $h = $y; //高度
  57. foreach ($head as $v){
  58. if(!empty($v['children'])){
  59. $heads[$y][$x] = $v['name'];
  60. if($h == $y){
  61. $h++;
  62. }
  63. if(empty($heads[$y])){
  64. $heads[$h] = [];
  65. }
  66. $res = $this->changehead($v['children'],$heads,$x,$h);
  67. $x+=$res[3];
  68. }else{
  69. $heads[$y][$x] = $v;
  70. $x++;
  71. }
  72. $w++;
  73. }
  74. $this->max_width = $this->max_width>$x?$this->max_width:$x;
  75. return [$heads,$x,$y,$w,$h];
  76. }
  77. /**
  78. * 处理表头单元格
  79. * @param $head
  80. * @param $lenth
  81. * @param $letter
  82. * @return array
  83. */
  84. public function mergehead($head,$lenth,$letter,$row=1)
  85. {
  86. $check = [];$widthmerge = [];
  87. $check_ = [];$heightmerge = [];
  88. foreach ($head as $k=>$v) {
  89. $check_[$k] = [];
  90. for ($i = 0; $i < $lenth; $i++) {
  91. $check_[$k][$i] = empty($v[$i])?0:$v[$i];
  92. if (empty($v[$i])){
  93. //左右合并
  94. if($i>0){
  95. if(empty($widthmerge[$k])){
  96. $widthmerge[$k] = [];
  97. }
  98. if(!empty($check[$i])){
  99. goto a;
  100. }else{
  101. $l = count($widthmerge[$k]);
  102. if($l>0){
  103. $end = $widthmerge[$k][$l-1];
  104. }else{
  105. $end = [];
  106. }
  107. if(empty($end[0])){
  108. $widthmerge[$k][] = [$i-1];
  109. }else if(empty($end[1])){
  110. if(($i-$end[0])==3){
  111. $widthmerge[$k][$l-1][1] = $i-2;
  112. $widthmerge[$k][] = [$i-1];
  113. }else{
  114. $widthmerge[$k][$l-1][1] = $i;
  115. }
  116. }else if(($i-$end[1])==1){
  117. $widthmerge[$k][$l-1][1] = $i;
  118. }else{
  119. $widthmerge[$k][] = [$i-1];
  120. }
  121. $check_[$k][$i] = $check_[$k][$i-1];
  122. }
  123. }
  124. //上下合并
  125. a:
  126. if($k>0){
  127. if(empty($check_[$k][$i])){
  128. if(empty($heightmerge[$i])){
  129. $heightmerge[$i] = [$letter[$i] . ($row-1),$letter[$i] . $row];
  130. }else{
  131. $heightmerge[$i][1] = $letter[$i] . $row;
  132. }
  133. }
  134. }
  135. }else{
  136. $check[$i] = true;
  137. }
  138. }
  139. $row++;
  140. }
  141. return [$widthmerge,$heightmerge];
  142. }
  143. /**
  144. * 返回A-ZZ
  145. * @return array
  146. */
  147. public function getA_ZZ()
  148. {
  149. $letter = range('A', 'Z');
  150. $x = $letter;
  151. $y = $letter;
  152. foreach ($x as $xv){
  153. foreach ($y as $yv){
  154. $letter[] = $xv.$yv;
  155. }
  156. }
  157. return $letter;
  158. }
  159. /**
  160. * @title: 判断是否为图片
  161. * @param $str
  162. * @return bool
  163. * @Author: wangkewei
  164. * @Date: 2021/9/27 19:48
  165. */
  166. public function is_image_string($str)
  167. {
  168. if(strstr($str,'jpg')!=false
  169. || strstr($str,'jpeg')!=false
  170. || strstr($str,'png')!=false
  171. || strstr($str,'gif')!=false
  172. || strstr($str,'bmp')!=false){
  173. if(is_file(public_path().$str)){
  174. return true;
  175. }
  176. }
  177. return false;
  178. }
  179. /**
  180. * 导出
  181. * @param array $xlsData 表格数据
  182. * @param array $head 表格头
  183. * @param array $save_path 文件保存路径
  184. * @param string $title 标题(非必填)
  185. * @throws \Exception
  186. */
  187. public function export_help($xlsData=[],$head=[],$save_path='',$title='')
  188. {
  189. //A-ZZ
  190. $letter = $this->getA_ZZ();
  191. //实例化
  192. $objExcel = new \PHPExcel();
  193. //设置内容
  194. $objActSheet = $objExcel->getActiveSheet();
  195. //处理表头
  196. $heads = $this->changehead($head);
  197. //返回的一维数组表头
  198. $head = $heads[0];
  199. //表格列数
  200. $lenth = $this->max_width;
  201. //是否存在标题
  202. if(empty($title)){
  203. $row = 1;
  204. }else{
  205. //设置标题
  206. $styleArray = array(
  207. 'font' => array(
  208. 'bold' => true,
  209. 'color' => array('rgb' => 'FFFFFF'),
  210. 'size' => '20'
  211. ),
  212. 'fill' => array(
  213. 'type'=>\PHPExcel_Style_Fill::FILL_SOLID,
  214. 'color' => array('rgb' => '0070C0')
  215. ));
  216. $objActSheet->setCellValue("A1", ''."$title");
  217. $objActSheet->mergeCells('A1:'.$letter[($lenth-1)].'1');
  218. $objActSheet->getStyle( 'A1:'.$letter[($lenth-1)].'1')->applyFromArray($styleArray);
  219. $row = 2;
  220. }
  221. //解决标题居中问题
  222. $merges = $this->mergehead($head,$lenth,$letter,$row);
  223. //合并标题单元格
  224. //上下合并
  225. $heightmerge = $merges[1];
  226. foreach ($heightmerge as $v){
  227. $objActSheet->mergeCells($v[0].':'.$v[1]);
  228. }
  229. //左右合并
  230. $widthmerge = $merges[0];
  231. for ($i = 0; $i < count($head); $i++) {
  232. if(!empty($widthmerge[$i])){
  233. foreach ($widthmerge[$i] as $v){
  234. if(empty($v[1])){
  235. $v[1] = $v[0]+1;
  236. }
  237. $objActSheet->mergeCells($letter[$v[0]].($i+$row).':'.$letter[$v[1]].($i+$row));
  238. }
  239. }
  240. }
  241. //填充表头信息
  242. foreach ($head as $k=>$v) {
  243. for ($i = 0; $i < $lenth; $i++) {
  244. if (!empty($v[$i])){
  245. $objActSheet->setCellValue($letter[$i] . $row, ''."$v[$i]");
  246. }
  247. }
  248. $row++;
  249. }
  250. $row--;
  251. // 表格高度
  252. $objActSheet->getRowDimension($row)->setRowHeight(25);
  253. //填充表格信息
  254. foreach ($xlsData as $k => $v) {
  255. $row ++;
  256. $i=0;
  257. $v = array_values($v);
  258. //表格内容
  259. //判断是否为图片
  260. foreach($v as $jv){
  261. $image_slice = [];
  262. if(is_array($jv)){
  263. $image_slice = $jv;
  264. }
  265. if(is_string($jv) && strstr($jv,',')){
  266. $image_slice = explode(',',$jv);
  267. }
  268. if(empty($image_slice)){
  269. if($this->is_image_string($jv)){
  270. $objDrawing = new \PHPExcel_Worksheet_Drawing();
  271. $objDrawing->setPath(public_path().$jv);
  272. $objDrawing->setWidthAndHeight(30,30);
  273. $objDrawing->setCoordinates($letter[$i].$row);
  274. $objDrawing->setWorksheet($objActSheet);
  275. $i++;
  276. continue;
  277. }
  278. }else{
  279. $image_slice_export = [];
  280. foreach ($image_slice as $isv){
  281. if($this->is_image_string($isv)){
  282. $image_slice_export[] = $isv;
  283. }
  284. }
  285. if(!empty($image_slice_export)){
  286. foreach ($image_slice_export as $k=>$ise){
  287. $objDrawing = new \PHPExcel_Worksheet_Drawing();
  288. $objDrawing->setPath(public_path().$ise);
  289. $objDrawing->setOffsetX(35*$k);
  290. $objDrawing->setOffsetY(5);
  291. $objDrawing->setWidthAndHeight(30,30);
  292. $objDrawing->setCoordinates($letter[$i].$row);
  293. $objDrawing->setWorksheet($objActSheet);
  294. }
  295. $i++;
  296. continue;
  297. }
  298. }
  299. //不为图片直接填充
  300. $objActSheet->setCellValue($letter[$i].$row, ' '."$v[$i]");
  301. $i++;
  302. }
  303. // 表格高度
  304. $objActSheet->getRowDimension($row)->setRowHeight(25);
  305. }
  306. $end=$letter[$lenth].$row;
  307. // 设置垂直居中
  308. $objActSheet->getStyle('A1:'.$end)->getAlignment()
  309. ->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);
  310. // 设置水平居中
  311. $objActSheet->getStyle('A1:'.$end)->getAlignment()
  312. ->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
  313. //设置表格的宽度
  314. $width = 20;
  315. for ($i = 0; $i < $lenth; $i++) {
  316. $objActSheet->getColumnDimension($letter[$i])->setWidth($width);
  317. }
  318. //设置文档属性
  319. $objWriter = \PHPExcel_IOFactory::createWriter($objExcel, 'Excel5');
  320. $objWriter->save($save_path);
  321. }
  322. /**
  323. * @title: 导出工作簿
  324. * @desc: 同时将多张工作表导出在同一个工作簿中
  325. * @param {array} {bookData} {} {工作簿数据}
  326. * @param {string} {bookData.title} {} {工作表标题}
  327. * @param {array} {bookData.head} {} {工作表表头}
  328. * @param {array} {bookData.body} {} {工作表内容}
  329. * @param {string} {save_path} {} {文件保存路径}
  330. * @return {*}
  331. * @author: Rock
  332. * @method: POST
  333. * @Date: 2023-03-07 15:10:30
  334. */
  335. public function exportBook($bookData,$save_path)
  336. {
  337. //A-ZZ
  338. $letter = $this->getA_ZZ();
  339. //实例化
  340. $objExcel = new \PHPExcel();
  341. foreach($bookData as $sheet=>$xlsData){
  342. $objExcel->setActiveSheetIndex($sheet);//选择选择工作表
  343. $objActSheet = $objExcel->getActiveSheet();
  344. //处理表头
  345. $heads = $this->changehead($head);
  346. //返回的一维数组表头
  347. $head = $heads[0];
  348. //表格列数
  349. $lenth = $this->max_width;
  350. //是否存在标题
  351. if(empty($title)){
  352. $row = 1;
  353. }else{
  354. //设置标题
  355. $styleArray = array(
  356. 'font' => array(
  357. 'bold' => true,
  358. 'color' => array('rgb' => 'FFFFFF'),
  359. 'size' => '20'
  360. ),
  361. 'fill' => array(
  362. 'type'=>\PHPExcel_Style_Fill::FILL_SOLID,
  363. 'color' => array('rgb' => '0070C0')
  364. ));
  365. $objActSheet->setCellValue("A1", ''."$title");
  366. $objActSheet->mergeCells('A1:'.$letter[($lenth-1)].'1');
  367. $objActSheet->getStyle( 'A1:'.$letter[($lenth-1)].'1')->applyFromArray($styleArray);
  368. $objActSheet->setTitle($title);//设置工作表标题
  369. $row = 2;
  370. }
  371. //解决标题居中问题
  372. $merges = $this->mergehead($head,$lenth,$letter,$row);
  373. //合并标题单元格
  374. //上下合并
  375. $heightmerge = $merges[1];
  376. foreach ($heightmerge as $v){
  377. $objActSheet->mergeCells($v[0].':'.$v[1]);
  378. }
  379. //左右合并
  380. $widthmerge = $merges[0];
  381. for ($i = 0; $i < count($head); $i++) {
  382. if(!empty($widthmerge[$i])){
  383. foreach ($widthmerge[$i] as $v){
  384. if(empty($v[1])){
  385. $v[1] = $v[0]+1;
  386. }
  387. $objActSheet->mergeCells($letter[$v[0]].($i+$row).':'.$letter[$v[1]].($i+$row));
  388. }
  389. }
  390. }
  391. //填充表头信息
  392. foreach ($head as $k=>$v) {
  393. for ($i = 0; $i < $lenth; $i++) {
  394. if (!empty($v[$i])){
  395. $objActSheet->setCellValue($letter[$i] . $row, ''."$v[$i]");
  396. }
  397. }
  398. $row++;
  399. }
  400. $row--;
  401. // 表格高度
  402. $objActSheet->getRowDimension($row)->setRowHeight(25);
  403. //填充表格信息
  404. foreach ($xlsData as $k => $v) {
  405. $row ++;
  406. $i=0;
  407. $v = array_values($v);
  408. //表格内容
  409. //判断是否为图片
  410. foreach($v as $jv){
  411. $image_slice = [];
  412. if(is_array($jv)){
  413. $image_slice = $jv;
  414. }
  415. if(is_string($jv) && strstr($jv,',')){
  416. $image_slice = explode(',',$jv);
  417. }
  418. if(empty($image_slice)){
  419. if($this->is_image_string($jv)){
  420. $objDrawing = new \PHPExcel_Worksheet_Drawing();
  421. $objDrawing->setPath(public_path().$jv);
  422. $objDrawing->setWidthAndHeight(30,30);
  423. $objDrawing->setCoordinates($letter[$i].$row);
  424. $objDrawing->setWorksheet($objActSheet);
  425. $i++;
  426. continue;
  427. }
  428. }else{
  429. $image_slice_export = [];
  430. foreach ($image_slice as $isv){
  431. if($this->is_image_string($isv)){
  432. $image_slice_export[] = $isv;
  433. }
  434. }
  435. if(!empty($image_slice_export)){
  436. foreach ($image_slice_export as $k=>$ise){
  437. $objDrawing = new \PHPExcel_Worksheet_Drawing();
  438. $objDrawing->setPath(public_path().$ise);
  439. $objDrawing->setOffsetX(35*$k);
  440. $objDrawing->setOffsetY(5);
  441. $objDrawing->setWidthAndHeight(30,30);
  442. $objDrawing->setCoordinates($letter[$i].$row);
  443. $objDrawing->setWorksheet($objActSheet);
  444. }
  445. $i++;
  446. continue;
  447. }
  448. }
  449. //不为图片直接填充
  450. $objActSheet->setCellValue($letter[$i].$row, ' '."$v[$i]");
  451. $i++;
  452. }
  453. // 表格高度
  454. $objActSheet->getRowDimension($row)->setRowHeight(25);
  455. }
  456. $end=$letter[$lenth].$row;
  457. // 设置垂直居中
  458. $objActSheet->getStyle('A1:'.$end)->getAlignment()
  459. ->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);
  460. // 设置水平居中
  461. $objActSheet->getStyle('A1:'.$end)->getAlignment()
  462. ->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
  463. //设置表格的宽度
  464. $width = 20;
  465. for ($i = 0; $i < $lenth; $i++) {
  466. $objActSheet->getColumnDimension($letter[$i])->setWidth($width);
  467. }
  468. }
  469. //设置文档属性
  470. $objWriter = \PHPExcel_IOFactory::createWriter($objExcel, 'Excel5');
  471. $objWriter->save($save_path);
  472. }
  473. }