Export.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2017~2021 https://www.yiovo.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
  8. // +----------------------------------------------------------------------
  9. // | Author: 萤火科技 <admin@yiovo.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types=1);
  12. namespace app\store\service\order;
  13. use PhpOffice\PhpSpreadsheet\Spreadsheet;
  14. use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
  15. use app\store\model\{Order as OrderModel, order\Export as ExportModel, OrderAddress as OrderAddressModel};
  16. use app\common\library\helper;
  17. use app\common\service\BaseService;
  18. use app\common\enum\order\{
  19. PayType as PayTypeEnum,
  20. PayStatus as PayStatusEnum,
  21. OrderSource as OrderSourceEnum,
  22. OrderStatus as OrderStatusEnum,
  23. DeliveryType as DeliveryTypeEnum,
  24. ReceiptStatus as ReceiptStatusEnum,
  25. DeliveryStatus as DeliveryStatusEnum,
  26. export\ExportStatus as ExportStatusEnum
  27. };
  28. use cores\exception\BaseException;
  29. /**
  30. * 服务层:订单导出Excel
  31. * Class Export
  32. * @package app\store\service\order
  33. */
  34. class Export extends BaseService
  35. {
  36. // 表格文件标题名称
  37. private $title = '订单导出结果';
  38. /**
  39. * 执行订单导出excel
  40. * @param array $param
  41. * @return bool
  42. * @throws BaseException
  43. */
  44. public function exportOrder(array $param): bool
  45. {
  46. // 根据条件查询订单列表
  47. $orderList = $this->getOrderList($param);
  48. // 格式化生成表格数据
  49. $excelList = $this->getExcelList($orderList->toArray(), $param['columns']);
  50. // 获取导出的记录列名集
  51. $columns = $this->getColumns($param['columns']);
  52. // 输出并写入到excel文件
  53. $filePath = $this->outputExcel($columns, $excelList);
  54. // 新增订单导出记录
  55. $this->record($param, $filePath);
  56. return true;
  57. }
  58. /**
  59. * 根据条件查询订单列表
  60. * @param array $param
  61. * @return mixed
  62. * @throws BaseException
  63. */
  64. private function getOrderList(array $param)
  65. {
  66. // 根据条件查询订单列表
  67. $model = new OrderModel;
  68. $orderList = $model->getListAll(OrderModel::LIST_TYPE_ALL, $param);
  69. if ($orderList->isEmpty()) {
  70. throwError('很抱歉,没有查询到订单数据');
  71. }
  72. return $orderList;
  73. }
  74. /**
  75. * 输出并写入到excel文件
  76. * @param array $columns 列名
  77. * @param array $excelList 表格内容
  78. * @return string
  79. * @throws BaseException
  80. */
  81. private function outputExcel(array $columns, array $excelList): string
  82. {
  83. // 生成工作表
  84. $spreadsheet = new Spreadsheet();
  85. $sheet = $spreadsheet->getActiveSheet()->setTitle($this->title);
  86. // 列宽
  87. $sheet->getDefaultColumnDimension()->setWidth(24);
  88. // 默认行高
  89. $sheet->getDefaultRowDimension()->setRowHeight(20);
  90. // 字体加粗(第一行)
  91. $sheet->getStyle('1')->getFont()->setBold(true);
  92. // 写入标题数据
  93. foreach ($columns as $key => $val) {
  94. $sheet->setCellValueByColumnAndRow($key + 1, 1, $val);
  95. }
  96. // 写入内容数据
  97. foreach ($excelList as $key => $item) {
  98. $row = $key + 2;
  99. foreach (array_values($item) as $k => $val) {
  100. $sheet->setCellValueByColumnAndRow($k + 1, $row, $val);
  101. }
  102. }
  103. // 生成文件路径
  104. $fileName = 'order-' . time() . '.xlsx';
  105. $filePath = $this->getExportPath();
  106. // 保存到文件
  107. try {
  108. $writer = new Xlsx($spreadsheet);
  109. $writer->save(public_path() . $filePath . $fileName);
  110. } catch (\PhpOffice\PhpSpreadsheet\Writer\Exception $e) {
  111. throwError($e->getMessage());
  112. }
  113. return $filePath . $fileName;
  114. }
  115. /**
  116. * 获取导出的文件夹路径
  117. * @return string
  118. */
  119. private function getExportPath(): string
  120. {
  121. $filePath = 'temp/' . $this->getStoreId() . '/';
  122. !is_dir($filePath) && mkdir($filePath, 0755, true);
  123. return $filePath;
  124. }
  125. /**
  126. * 写入订单导出记录
  127. * @param array $param
  128. * @param string $filePath
  129. * @return void
  130. */
  131. private function record(array $param, string $filePath): void
  132. {
  133. // 生成记录数据
  134. $data = [
  135. 'file_path' => $filePath,
  136. 'status' => ExportStatusEnum::COMPLETED,
  137. 'store_id' => $this->getStoreId(),
  138. ];
  139. // 起止时间
  140. if (!empty($param['betweenTime'])) {
  141. $times = between_time($param['betweenTime']);
  142. $data['start_time'] = $times['start_time'];
  143. $data['end_time'] = $times['end_time'];
  144. }
  145. // 新增记录
  146. $model = new ExportModel;
  147. $model->add($data);
  148. }
  149. /**
  150. * 获取导出的记录列名集
  151. * @param array $onlyFields
  152. * @return array
  153. */
  154. private function getColumns(array $onlyFields): array
  155. {
  156. return array_values(helper::pick($this->dictionary(), $onlyFields));
  157. }
  158. /**
  159. * 订单记录字典
  160. * @return string[]
  161. */
  162. private function dictionary(): array
  163. {
  164. return [
  165. 'order_id' => '订单ID',
  166. 'order_no' => '订单号',
  167. 'goods_detail' => '商品信息',
  168. 'total_price' => '商品总额',
  169. 'coupon_money' => '优惠券抵扣金额',
  170. 'points_money' => '积分抵扣金额',
  171. 'update_price' => '后台改价',
  172. 'express_price' => '运费金额',
  173. 'pay_price' => '订单实付款',
  174. 'pay_type' => '支付方式',
  175. 'create_time' => '下单时间',
  176. 'user_info' => '买家信息',
  177. 'buyer_remark' => '买家留言',
  178. 'delivery_type' => '配送方式',
  179. 'receipt_name' => '收货人',
  180. 'receipt_phone' => '联系电话',
  181. 'receipt_address' => '收货地址',
  182. 'express_company' => '物流公司',
  183. 'express_no' => '物流单号',
  184. 'pay_status' => '付款状态',
  185. 'pay_time' => '付款时间',
  186. 'delivery_status' => '发货状态',
  187. 'delivery_time' => '发货时间',
  188. 'receipt_status' => '收货状态',
  189. 'receipt_time' => '收货时间',
  190. 'order_status' => '订单状态',
  191. 'is_comment' => '是否已评价',
  192. 'order_source' => '订单来源',
  193. ];
  194. }
  195. /**
  196. * 格式化生成表格数据
  197. * @param array $orderList
  198. * @param array $onlyFields
  199. * @return array
  200. */
  201. private function getExcelList(array $orderList, array $onlyFields): array
  202. {
  203. // 获取订单表格数据
  204. $excelList = $this->getOrderDataForExcel($orderList);
  205. // 仅输出用户设置的字段
  206. $data = [];
  207. foreach ($excelList as $item) {
  208. $data[] = helper::pick($item, $onlyFields);
  209. }
  210. return $data;
  211. }
  212. /**
  213. * 获取订单列表数据(用于生成Excel)
  214. * @param $orderList
  215. * @return array
  216. */
  217. private function getOrderDataForExcel($orderList): array
  218. {
  219. // 表格内容
  220. $dataArray = [];
  221. foreach ($orderList as $order) {
  222. $dataArray[] = [
  223. 'order_id' => $order['order_id'],
  224. 'order_no' => $order['order_no'],
  225. 'goods_detail' => $this->filterGoodsInfo($order),
  226. 'total_price' => $this->filterValue($order['total_price']) . '元',
  227. 'coupon_money' => $this->filterValue($order['coupon_money']) . '元',
  228. 'points_money' => $this->filterValue($order['points_money']) . '元',
  229. 'update_price' => "{$order['update_price']['symbol']}{$order['update_price']['value']}元",
  230. 'express_price' => $this->filterValue($order['express_price']) . '元',
  231. 'pay_price' => $this->filterValue($order['pay_price']) . '元',
  232. 'pay_type' => PayTypeEnum::data()[$order['pay_type']]['name'],
  233. 'create_time' => $this->filterValue($order['create_time']),
  234. 'user_info' => $this->filterValue($order['user']['nick_name']),
  235. 'buyer_remark' => $this->filterValue($order['buyer_remark']),
  236. 'delivery_type' => DeliveryTypeEnum::data()[$order['delivery_type']]['name'],
  237. 'receipt_name' => !empty($order['address']) ? $this->filterValue($order['address']['name']) : '',
  238. 'receipt_phone' => !empty($order['address']) ? $this->filterValue($order['address']['phone']) : '',
  239. 'receipt_address' => !empty($order['address']) ? OrderAddressModel::fullAddress($order['address']) : '',
  240. 'express_company' => !empty($order['express']) ? $order['express']['express_name'] : '',
  241. 'express_no' => $this->filterValue($order['express_no']),
  242. 'pay_status' => PayStatusEnum::data()[$order['pay_status']]['name'],
  243. 'pay_time' => $order['pay_time'],
  244. 'delivery_status' => DeliveryStatusEnum::data()[$order['delivery_status']]['name'],
  245. 'delivery_time' => $order['delivery_time'] ?: '',
  246. 'receipt_status' => ReceiptStatusEnum::data()[$order['receipt_status']]['name'],
  247. 'receipt_time' => $order['receipt_time'] ?: '',
  248. 'order_status' => OrderStatusEnum::data()[$order['order_status']]['name'],
  249. 'is_comment' => $order['is_comment'] ? '是' : '否',
  250. 'order_source' => OrderSourceEnum::data()[$order['order_source']]['name'],
  251. ];
  252. }
  253. return $dataArray;
  254. }
  255. /**
  256. * 格式化商品信息
  257. * @param $order
  258. * @return string
  259. */
  260. private function filterGoodsInfo($order): string
  261. {
  262. $content = '';
  263. foreach ($order['goods'] as $key => $goods) {
  264. $content .= ($key + 1) . ".商品名称:{$goods['goods_name']}\n";
  265. !empty($goods['goods_attr']) && $content .= " 商品规格:{$goods['goods_attr']}\n";
  266. $content .= " 购买数量:{$goods['total_num']}\n";
  267. $content .= " 商品总价:{$goods['total_price']}元\n\n";
  268. }
  269. return $content;
  270. }
  271. /**
  272. * 表格值过滤
  273. * @param $value
  274. * @return string
  275. */
  276. private function filterValue($value): string
  277. {
  278. return $value;
  279. //return "\t" . $value . "\t";
  280. }
  281. }