Export.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2017~2024 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\service\Goods as GoodsService;
  19. use app\common\enum\order\{
  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 app\common\enum\payment\Method as PaymentMethodEnum;
  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 string $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. $orderList = (new OrderModel)->getListAll($param);
  69. if (empty($orderList) || $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. // 获取导出的文件夹路径
  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 = 'downloads/' . $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_method' => '支付方式',
  176. 'create_time' => '下单时间',
  177. 'user_info' => '买家信息',
  178. 'buyer_remark' => '买家留言',
  179. 'delivery_type' => '配送方式',
  180. 'receipt_name' => '收货人',
  181. 'receipt_phone' => '联系电话',
  182. 'receipt_address' => '收货地址',
  183. 'pay_status' => '付款状态',
  184. 'pay_time' => '付款时间',
  185. 'delivery_status' => '发货状态',
  186. 'delivery_time' => '发货时间',
  187. 'receipt_status' => '收货状态',
  188. 'receipt_time' => '收货时间',
  189. 'order_status' => '订单状态',
  190. 'is_comment' => '是否已评价',
  191. 'order_source' => '订单来源',
  192. ];
  193. }
  194. /**
  195. * 格式化生成表格数据
  196. * @param array $orderList
  197. * @param array $onlyFields
  198. * @return array
  199. */
  200. private function getExcelList(array $orderList, array $onlyFields): array
  201. {
  202. // 获取订单表格数据
  203. $excelList = $this->getOrderDataForExcel($orderList);
  204. // 仅输出用户设置的字段
  205. $data = [];
  206. foreach ($excelList as $item) {
  207. $data[] = helper::pick($item, $onlyFields);
  208. }
  209. return $data;
  210. }
  211. /**
  212. * 获取订单列表数据(用于生成Excel)
  213. * @param $orderList
  214. * @return array
  215. */
  216. private function getOrderDataForExcel($orderList): array
  217. {
  218. // 表格内容
  219. $dataArray = [];
  220. foreach ($orderList as $order) {
  221. $dataArray[] = [
  222. 'order_id' => $this->filterValue($order['order_id']),
  223. 'order_no' => $this->filterValue($order['order_no']),
  224. 'goods_detail' => $this->filterGoodsInfo($order),
  225. 'total_price' => $this->filterValue($order['total_price']) . '元',
  226. 'coupon_money' => $this->filterValue($order['coupon_money']) . '元',
  227. 'points_money' => $this->filterValue($order['points_money']) . '元',
  228. 'update_price' => "{$order['update_price']['symbol']}{$order['update_price']['value']}元",
  229. 'express_price' => $this->filterValue($order['express_price']) . '元',
  230. 'pay_price' => $this->filterValue($order['pay_price']) . '元',
  231. 'pay_method' => $this->filterPayMethod($order['pay_method']),
  232. 'create_time' => $this->filterValue($order['create_time']),
  233. 'user_info' => $this->filterValue($order['user']['nick_name']),
  234. 'buyer_remark' => $this->filterValue($order['buyer_remark']),
  235. 'delivery_type' => DeliveryTypeEnum::data()[$order['delivery_type']]['name'],
  236. 'receipt_name' => !empty($order['address']) ? $this->filterValue($order['address']['name']) : '',
  237. 'receipt_phone' => !empty($order['address']) ? $this->filterValue($order['address']['phone']) : '',
  238. 'receipt_address' => !empty($order['address']) ? OrderAddressModel::fullAddress($order['address']) : '',
  239. 'pay_status' => PayStatusEnum::data()[$order['pay_status']]['name'],
  240. 'pay_time' => $order['pay_time'],
  241. 'delivery_status' => DeliveryStatusEnum::data()[$order['delivery_status']]['name'],
  242. 'delivery_time' => $order['delivery_time'] ?: '',
  243. 'receipt_status' => ReceiptStatusEnum::data()[$order['receipt_status']]['name'],
  244. 'receipt_time' => $order['receipt_time'] ?: '',
  245. 'order_status' => OrderStatusEnum::data()[$order['order_status']]['name'],
  246. 'is_comment' => $order['is_comment'] ? '是' : '否',
  247. 'order_source' => OrderSourceEnum::data()[$order['order_source']]['name'],
  248. ];
  249. }
  250. return $dataArray;
  251. }
  252. /**
  253. * 格式化支付方式
  254. * @param string $payMethod
  255. * @return string
  256. */
  257. private function filterPayMethod(string $payMethod): string
  258. {
  259. $enum = PaymentMethodEnum::data();
  260. return isset($enum[$payMethod]) ? $enum[$payMethod]['name'] : '';
  261. }
  262. /**
  263. * 格式化商品信息
  264. * @param $order
  265. * @return string
  266. */
  267. private function filterGoodsInfo($order): string
  268. {
  269. $content = '';
  270. foreach ($order['goods'] as $key => $goods) {
  271. $content .= ($key + 1) . ".商品名称:{$goods['goods_name']}\n";
  272. if (!empty($goods['goods_props'])) {
  273. $goodsAttr = GoodsService::goodsPropsToAttr($goods['goods_props']);
  274. $content .= " 商品规格:{$goodsAttr}\n";
  275. }
  276. $content .= " 购买数量:{$goods['total_num']}\n";
  277. $content .= " 商品总价:{$goods['total_price']}元\n\n";
  278. }
  279. return $content;
  280. }
  281. /**
  282. * 表格值过滤
  283. * @param $value
  284. * @return string
  285. */
  286. private function filterValue($value): string
  287. {
  288. return "\t{$value}\t";
  289. }
  290. }