Export.php 11 KB

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