SpreadsheetExcelService.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. <?php
  2. namespace crmeb\services;
  3. class SpreadsheetExcelService
  4. {
  5. //
  6. private static $instance = null;
  7. //PHPSpreadsheet实例化对象
  8. private static $spreadsheet = null;
  9. //sheet实例化对象
  10. private static $sheet = null;
  11. //表头计数
  12. protected static $count;
  13. //表头占行数
  14. protected static $topNumber = 3;
  15. //表能占据表行的字母对应self::$cellkey
  16. protected static $cells;
  17. //表头数据
  18. protected static $data = [];
  19. //文件名
  20. protected static $title = '订单导出';
  21. //行宽
  22. protected static $width = 20;
  23. //行高
  24. protected static $height = 50;
  25. //保存文件目录
  26. protected static $path = './phpExcel/';
  27. //设置style
  28. private static $styleArray = [
  29. // 'borders' => [
  30. // 'allBorders' => [
  31. // // PHPExcel_Style_Border里面有很多属性,想要其他的自己去看
  32. // // 'style' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THICK,//边框是粗的
  33. // // 'style' => \PHPExcel_Style_Border::BORDER_DOUBLE,//双重的
  34. // // 'style' => \PHPExcel_Style_Border::BORDER_HAIR,//虚线
  35. // // 'style' => \PHPExcel_Style_Border::BORDER_MEDIUM,//实粗线
  36. // // 'style' => \PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT,//虚粗线
  37. // // 'style' => \PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT,//点虚粗线
  38. // 'style' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN,//细边框
  39. // // 'color' => ['argb' => 'FFFF0000'],
  40. // ],
  41. // ],
  42. 'font' => [
  43. 'bold' => true
  44. ],
  45. 'alignment' => [
  46. 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
  47. 'vertical' => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER
  48. ]
  49. ];
  50. private function __construct(){}
  51. private function __clone(){}
  52. public static function instance()
  53. {
  54. if (self::$instance === null) {
  55. self::$instance = new self();
  56. self::$spreadsheet = $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
  57. self::$sheet = $spreadsheet->getActiveSheet();
  58. }
  59. return self::$instance;
  60. }
  61. /**
  62. *设置字体格式
  63. * @param $title string 必选
  64. * return string
  65. */
  66. public static function setUtf8($title)
  67. {
  68. return iconv('utf-8', 'gb2312', $title);
  69. }
  70. /**
  71. * 创建保存excel目录
  72. * return string
  73. */
  74. public static function savePath()
  75. {
  76. if(!is_dir(self::$path)){
  77. if (mkdir(self::$path, 0700) == false) {
  78. return false;
  79. }
  80. }
  81. //年月一级目录
  82. $mont_path = self::$path.date('Ym');
  83. if(!is_dir($mont_path)){
  84. if (mkdir($mont_path, 0700) == false) {
  85. return false;
  86. }
  87. }
  88. //日二级目录
  89. $day_path = $mont_path.'/'.date('d');
  90. if(!is_dir($day_path)){
  91. if (mkdir($day_path, 0700) == false) {
  92. return false;
  93. }
  94. }
  95. return $day_path;
  96. }
  97. /**
  98. * 设置标题
  99. * @param $title string || array ['title'=>'','name'=>'','info'=>[]]
  100. * @param $Name string
  101. * @param $info string || array;
  102. * @param $funName function($style,$A,$A2) 自定义设置头部样式
  103. * @return $this
  104. */
  105. public function setExcelTile($title = '', $Name = '', $info = [], $funName = null)
  106. {
  107. //设置参数
  108. if (is_array($title)) {
  109. if (isset($title['title'])) $title = $title['title'];
  110. if (isset($title['name'])) $Name = $title['name'];
  111. if (isset($title['info'])) $info = $title['info'];
  112. }
  113. if (empty($title))
  114. $title = self::$title;
  115. else
  116. self::$title = $title;
  117. if (empty($Name)) $Name = time();
  118. //设置Excel属性
  119. self::$spreadsheet->getProperties()
  120. ->setCreator("Neo")
  121. ->setLastModifiedBy("Neo")
  122. ->setTitle(self::setUtf8($title))
  123. ->setSubject($Name)
  124. ->setDescription("")
  125. ->setKeywords($Name)
  126. ->setCategory("");
  127. self::$sheet->setTitle($Name);
  128. self::$sheet->setCellValue('A1', $title);
  129. self::$sheet->setCellValue('A2', self::setCellInfo($info));
  130. //文字居中
  131. self::$sheet->getStyle('A1')->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER);
  132. self::$sheet->getStyle('A2')->getAlignment()->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER);
  133. //合并表头单元格
  134. self::$sheet->mergeCells('A1:' . self::$cells . '1');
  135. self::$sheet->mergeCells('A2:' . self::$cells . '2');
  136. self::$sheet->getRowDimension(1)->setRowHeight(40);
  137. self::$sheet->getRowDimension(2)->setRowHeight(20);
  138. //设置表头字体
  139. self::$sheet->getStyle('A1')->getFont()->setName('黑体');
  140. self::$sheet->getStyle('A1')->getFont()->setSize(20);
  141. self::$sheet->getStyle('A1')->getFont()->setBold(true);
  142. self::$sheet->getStyle('A2')->getFont()->setName('宋体');
  143. self::$sheet->getStyle('A2')->getFont()->setSize(14);
  144. self::$sheet->getStyle('A2')->getFont()->setBold(true);
  145. self::$sheet->getStyle('A3:' . self::$cells . '3')->getFont()->setBold(true);
  146. return $this;
  147. }
  148. /**
  149. * 设置第二行标题内容
  150. * @param $info array (['name'=>'','site'=>'','phone'=>123] || ['我是表名','我是地址','我是手机号码'] ) || string 自定义
  151. * @return string
  152. */
  153. private static function setCellInfo($info)
  154. {
  155. $content = ['操作者:', '导出日期:' . date('Y-m-d', time()), '地址:', '电话:'];
  156. if (is_array($info) && !empty($info)) {
  157. if (isset($info['name'])) {
  158. $content[0] .= $info['name'];
  159. } else {
  160. $content[0] .= isset($info[0]) ? $info[0] : '';
  161. }
  162. if (isset($info['site'])) {
  163. $content[2] .= $info['site'];
  164. } else {
  165. $content[2] .= isset($info[1]) ? $info[1] : '';
  166. }
  167. if (isset($info['phone'])) {
  168. $content[3] .= $info['phone'];
  169. } else {
  170. $content[3] .= isset($info[2]) ? $info[2] : '';
  171. }
  172. return implode(' ', $content);
  173. } else if (is_string($info)) {
  174. return empty($info) ? implode(' ', $content) : $info;
  175. }
  176. }
  177. /**
  178. * 设置头部信息
  179. * @param $data array
  180. * @return $this
  181. */
  182. public static function setExcelHeader($data)
  183. {
  184. $span = 'A';
  185. foreach ($data as $key => $value) {
  186. self::$sheet->getColumnDimension($span)->setWidth(self::$width);
  187. self::$sheet->setCellValue($span.self::$topNumber, $value);
  188. $span++;
  189. }
  190. self::$sheet->getRowDimension(3)->setRowHeight(self::$height);
  191. self::$cells = $span;
  192. return new self;
  193. }
  194. /**
  195. *
  196. * execl数据导出
  197. * @param $data 需要导出的数据 格式和以前的可是一样
  198. *
  199. * 特殊处理:合并单元格需要先对数据进行处理
  200. */
  201. public function setExcelContent($data = [])
  202. {
  203. if (!empty($data) && is_array($data)) {
  204. $column = self::$topNumber+1;
  205. // 行写入
  206. foreach ($data as $key => $rows) {
  207. $span = 'A';
  208. // 列写入
  209. foreach ($rows as $keyName => $value) {
  210. self::$sheet->setCellValue($span . $column, $value);
  211. $span++;
  212. }
  213. $column++;
  214. }
  215. self::$sheet->getDefaultRowDimension()->setRowHeight(self::$height);
  216. //设置内容字体样式
  217. self::$sheet->getStyle('A1:' . $span.$column)->applyFromArray(self::$styleArray);
  218. //设置边框
  219. self::$sheet->getStyle('A1:' . $span.$column)->getBorders()->getAllBorders()->setBorderStyle(\PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN);
  220. //设置自动换行
  221. self::$sheet->getStyle('A4:' . $span.$column)->getAlignment()->setWrapText(true);
  222. }
  223. return new self;
  224. }
  225. /**
  226. * 保存表格数据,直接下载
  227. * @param $filename 文件名称
  228. * @param $suffix 文件后缀名
  229. * @param $is_save 是否保存文件
  230. * @return 保存文件:return string
  231. */
  232. public function excelSave($fileName = '',$suffix = 'xlsx',$is_save = false)
  233. {
  234. if(empty($fileName)){
  235. $fileName = date('YmdHis').time();
  236. }
  237. if(empty($suffix)){
  238. $suffix = 'xlsx';
  239. }
  240. // 重命名表(UTF8编码不需要这一步)
  241. if (mb_detect_encoding($fileName) != "UTF-8") {
  242. $fileName = iconv("utf-8", "gbk//IGNORE", $fileName);
  243. }
  244. if ($suffix == 'xlsx') {
  245. header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
  246. $class = "\PhpOffice\PhpSpreadsheet\Writer\Xlsx";
  247. } elseif ($suffix == 'xls') {
  248. header('Content-Type:application/vnd.ms-excel');
  249. $class = "\PhpOffice\PhpSpreadsheet\Writer\Xls";
  250. }
  251. // 清理缓存
  252. ob_end_clean();
  253. $spreadsheet = self::$spreadsheet;
  254. $writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
  255. if(!$is_save){//直接下载
  256. header('Content-Disposition: attachment;filename="' . $fileName . '.' . $suffix . '"');
  257. header('Cache-Control: max-age=0');
  258. $writer->save('php://output');
  259. // 删除清空 释放内存
  260. $spreadsheet->disconnectWorksheets();
  261. unset($spreadsheet);
  262. exit;
  263. }else{//保存文件
  264. $path = self::savePath().'/'.$fileName.'.'.$suffix;
  265. //$writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx');
  266. //$writer->save($path);
  267. $writer->save($path);
  268. // 删除清空 释放内存
  269. $spreadsheet->disconnectWorksheets();
  270. unset($spreadsheet);
  271. return $path;
  272. }
  273. }
  274. }