Excel.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. <?php
  2. namespace App\libs\helpers;
  3. use PhpOffice\PhpSpreadsheet\Spreadsheet;
  4. use PhpOffice\PhpSpreadsheet\Style\Alignment;
  5. use PhpOffice\PhpSpreadsheet\Style\Border;
  6. use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
  7. use PhpOffice\PhpSpreadsheet\Worksheet\MemoryDrawing;
  8. class Excel
  9. {
  10. /**
  11. * 初始实例化
  12. * @var Spreadsheet|null
  13. */
  14. private $excel = null;
  15. /**
  16. * 导出暂存地址
  17. * @var string
  18. */
  19. private $path = '';
  20. /**
  21. * 定义表格格子 最高到AG
  22. * @var string[]
  23. */
  24. private $ziMu = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','AA','AB','AC','AD','AE','AF','AG'];
  25. /**
  26. * 标题
  27. * @var array
  28. */
  29. private $title = [];
  30. /**
  31. * 导入数据源
  32. * @var array
  33. */
  34. private $data = [];
  35. /**
  36. * 默认域名
  37. * @var string
  38. */
  39. private $defaultDomain = 'https://yxd.wangkuncheng.cn';
  40. /**
  41. * 是否自动换行
  42. * @var bool
  43. */
  44. private $setWrapText = true;
  45. /**
  46. * 导出表格名称
  47. * @var string
  48. */
  49. private $excelName = '';
  50. /**
  51. * 实例化
  52. * @var Spreadsheet|null
  53. */
  54. private $spreadsheet = null;
  55. /**
  56. * 是否输出导出地址
  57. *
  58. * @var bool
  59. */
  60. private $isExportPath = false;
  61. /**
  62. * 导出的地址
  63. * @var string
  64. */
  65. public $exportPath = '';
  66. /**
  67. * 项目编号
  68. * @var string
  69. */
  70. private $projectName = '';
  71. /**
  72. * 项目导出文件暂存地址
  73. * @var string
  74. */
  75. private $projectExcelPath = '';
  76. /**
  77. * 是否开本地地址
  78. *
  79. * @var bool
  80. */
  81. private $isLocalhost = false;
  82. /**
  83. * 格式是否为图片
  84. *
  85. * @var array
  86. */
  87. private $ceilImage = [];
  88. /**
  89. * 格式图片样式
  90. *
  91. * @var array
  92. */
  93. private $ceilImageStyle = [];
  94. /**
  95. * 初始化
  96. *
  97. * @param string $project 项目文件名 例如
  98. * @param string $path 路径地址
  99. * @param array $data 表数据
  100. * @param array $title 表头
  101. * Excel constructor.
  102. */
  103. public function __construct(string $project = '', string $path = '', array $data = [], array $title = [])
  104. {
  105. $this->spreadsheet = new Spreadsheet();
  106. $this->excel = $this->spreadsheet->getActiveSheet();
  107. $this->path = $_SERVER['DOCUMENT_ROOT'].'/'.$project.'/'.$path;
  108. $this->projectName = $project;
  109. $this->projectExcelPath = $path;
  110. $this->data = $data;
  111. $this->title = $title;
  112. // exec("chmod 777 ".$this->path,$output,$status);
  113. }
  114. /**
  115. * 设置表格名称
  116. *
  117. * @param string $excelName
  118. * @return $this
  119. */
  120. public function setExcelName(string $excelName = ''){
  121. $this->excelName = $excelName;
  122. return $this;
  123. }
  124. /**
  125. * 设置是否导出地址
  126. *
  127. * @param bool $isExportPath
  128. */
  129. public function setIsExportPath(bool $isExportPath)
  130. {
  131. $this->isExportPath = $isExportPath;
  132. return $this;
  133. }
  134. /**
  135. * 设置是否开启本地
  136. *
  137. * @param bool $isLocalhost 是否开启 true false
  138. * @param string $localhostPath 本地域名地址 如果域名下一级目录不能直接直接对应项目名称 请传入域名下的相对路径
  139. */
  140. public function setIsLocalhost(bool $isLocalhost ,string $localhostPath)
  141. {
  142. $this->defaultDomain = $localhostPath;
  143. $this->isLocalhost = $isLocalhost;
  144. return $this;
  145. }
  146. /**
  147. * 设置边框
  148. *
  149. * @throws \PhpOffice\PhpSpreadsheet\Exception
  150. */
  151. public function borderThin(){
  152. $this->excel->getStyle($this->getRange())->getBorders()->getAllBorders()->setBorderStyle(Border::BORDER_THIN);
  153. return $this;
  154. }
  155. /**
  156. * 设置自动换行
  157. *
  158. * @param bool $wrap
  159. * @return $this
  160. */
  161. public function setAutoWrapText(bool $wrap = true){
  162. $this->setWrapText = $wrap;
  163. return $this;
  164. }
  165. /**
  166. * 设置行宽
  167. * 数据示例:['rowName'=>'A','value'=>50]
  168. *
  169. * @param array $data
  170. * @return $this
  171. */
  172. public function setRowWidth(array $data = []){
  173. foreach ($data as $value){
  174. $this->excel->getColumnDimension($value['rowName'])->setWidth($value['value']);
  175. }
  176. return $this;
  177. }
  178. /**
  179. * 设置行高:两种形式
  180. * 1.整数:则默认设置全部行高
  181. * 2.数组:单独设置每一行行高
  182. * 数组格式[30,30] 一维数组形式传入值即可 如果传入数组count小于data数据count 那么剩余的 默认30行高
  183. *
  184. * @param int $height
  185. * @return $this
  186. */
  187. public function setRowHeight($height = 30){
  188. $index = 2;
  189. for ($i = 0; $i < count($this->data); $i++){
  190. $this->excel->getRowDimension($index)->setRowHeight(is_array($height) ? ($height[$i] ?? 30) : $height);
  191. $index++;
  192. }
  193. return $this;
  194. }
  195. /**
  196. * 设置全局居中
  197. *
  198. * @return $this
  199. */
  200. public function setCenter(){
  201. $this->excel->getStyle($this->getRange())->applyFromArray([
  202. 'alignment' => [
  203. 'horizontal' => Alignment::HORIZONTAL_CENTER,// 水平居中
  204. 'vertical' => Alignment::VERTICAL_CENTER //垂直居中
  205. ]
  206. ]);
  207. return $this;
  208. }
  209. /**
  210. * 保存并导出
  211. *
  212. * @param array $data
  213. * @return $this
  214. */
  215. public function save(){
  216. $this->setWrap();
  217. $this->setCellValue();
  218. $this->exportData();
  219. $writer = new Xlsx($this->spreadsheet);
  220. if (empty($this->excelName)){
  221. $this->excelName = date('Y-m-d');
  222. }
  223. $writer->save($this->path.'/'.$this->excelName . '.xlsx');
  224. if ($this->isExportPath){
  225. $this->exportPath = $this->defaultDomain.'/'.$this->projectName.'/'.$this->projectExcelPath.'/'.$this->excelName . '.xlsx';
  226. }else{
  227. header("Location: ".$this->defaultDomain.'/'.$this->projectName.'/'.$this->projectExcelPath.'/'.$this->excelName . '.xlsx');
  228. }
  229. return $this;
  230. }
  231. /**
  232. * 创建图片
  233. * @param string $ceil
  234. * @param string $url
  235. * @throws \PhpOffice\PhpSpreadsheet\Exception
  236. */
  237. private function setImage(string $url = '',string $ceil = ''){
  238. if (!empty($url)){
  239. // $src = imagecreatefromstring(file_get_contents($url));
  240. $exp = explode('/',$url);
  241. // $url = '/www/wwwroot/1001/1001-staff/uploads/'.$exp[5].$exp[6];
  242. // $url = 'E:\SiWeiDingZhi\1001\1001-staff\uploads/'.$exp[5].'/'.$exp[6];
  243. $url = '/www/wwwroot/1001/1001-staff/uploads/'.$exp[5].'/'.$exp[6];
  244. $src = imagecreatefromstring(file_get_contents($url));
  245. list($src_w, $src_h) = getimagesize($url);
  246. $img = imagecreatetruecolor($src_w,$src_h);
  247. imagecopymerge($img,$src,0,0,0,0,$src_w,$src_h,100);
  248. $drawing = new MemoryDrawing();
  249. $drawing->setName($url);
  250. $drawing->setDescription($url);
  251. $drawing->setCoordinates($ceil);
  252. $drawing->setImageResource($img);
  253. $drawing->setHeight(80);
  254. $drawing->setOffsetX(10);
  255. $drawing->setOffsetY(10);
  256. $drawing->setRenderingFunction(MemoryDrawing::RENDERING_JPEG);
  257. $drawing->setMimeType(MemoryDrawing::MIMETYPE_DEFAULT);
  258. if (!empty($this->ceilImageStyle)){
  259. $ceilText = substr($ceil,0,1);
  260. if (!empty($this->ceilImageStyle[$ceilText])){
  261. $drawing->setHeight($this->ceilImageStyle[$ceilText]['height']);
  262. $drawing->setWidth($this->ceilImageStyle[$ceilText]['width']);
  263. $drawing->setOffsetX($this->ceilImageStyle[$ceilText]['OffsetX']);
  264. $drawing->setOffsetY($this->ceilImageStyle[$ceilText]['OffsetY']);
  265. }
  266. }
  267. $drawing->setWorksheet($this->spreadsheet->getActiveSheet());
  268. }
  269. }
  270. /**
  271. * 设置格子是否导出为图片
  272. *
  273. * @param array $images
  274. * @return $this
  275. */
  276. public function setExportCeilImage(array $images = []){
  277. if (count($images) != count($images,1)){
  278. foreach ($images ?? [] as $v){
  279. $this->ceilImage[] = key($images);
  280. next($images);
  281. }
  282. $this->ceilImageStyle = $images;
  283. }else{
  284. $this->ceilImage = $images;
  285. }
  286. return $this;
  287. }
  288. /**
  289. * 设置导出数据
  290. *
  291. */
  292. private function exportData(){
  293. $index = 2;
  294. $keyName = $this->getArrayKey();
  295. for ($i = 0;$i < count($this->data);$i++){
  296. for ($j = 0;$j < count($this->title);$j++){
  297. if (in_array($this->ziMu[$j],$this->ceilImage)){
  298. if (!empty($this->data[$i][$keyName[$j]])){
  299. $this->setImage($this->data[$i][$keyName[$j]],$this->ziMu[$j] . $index);
  300. }
  301. }else{
  302. $this->excel->setCellValue($this->ziMu[$j] . $index, $this->data[$i][$keyName[$j]]);
  303. }
  304. }
  305. $index++;
  306. }
  307. }
  308. /**
  309. * 获取数组指针
  310. *
  311. * @return array
  312. */
  313. private function getArrayKey(){
  314. $result = [];
  315. if (empty($this->data)){
  316. throw new \think\Exception('传入表数据为空', 40004);
  317. }
  318. for ($i=0,$len=count($this->data[0]); $i<$len; $i++) {
  319. $result[] = key($this->data[0]);
  320. next($this->data[0]);
  321. }
  322. return $result;
  323. }
  324. /**
  325. * 设置自动换行
  326. *
  327. */
  328. private function setWrap(){
  329. if ($this->setWrapText){
  330. $this->excel->getStyle($this->getRange())->getAlignment()->setWrapText(true);
  331. }
  332. }
  333. /**
  334. * 获取数据范围值
  335. *
  336. * @return string
  337. */
  338. private function getRange(){
  339. if(empty($this->title) || empty($this->data)){
  340. throw new \think\Exception('初始化请传入数据', 40006);
  341. }
  342. return 'A1:'.$this->ziMu[count($this->title) - 1].(count($this->data) + 1);
  343. }
  344. /**
  345. * 设置表头
  346. *
  347. */
  348. private function setCellValue(){
  349. if (empty($this->title)){
  350. throw new \think\Exception('传入表头为空', 40005);
  351. }
  352. foreach ($this->title as $key=>$value){
  353. $this->excel->setCellValue($this->ziMu[$key].'1', $this->title[$key]);
  354. }
  355. }
  356. }