Order.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. <?php
  2. /**
  3. * 订单管理控制器
  4. */
  5. namespace app\admin\controller\order;
  6. use app\common\controller\Backend;
  7. use think\facade\Db;
  8. use PhpOffice\PhpSpreadsheet\Spreadsheet;
  9. use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
  10. use PhpOffice\PhpSpreadsheet\Cell\DataType;
  11. class Order extends Backend
  12. {
  13. protected array $noNeedLogin = ['*'];
  14. /**
  15. * 订单列表
  16. * @return void
  17. */
  18. public function index(): void
  19. {
  20. $where = [];
  21. // 订单编号搜索
  22. if (!empty($this->request->get('order_no'))) {
  23. $orderNo = $this->request->get('order_no');
  24. $where[] = ['o.order_no', 'like', '%' . $orderNo . '%'];
  25. }
  26. // 商品名称搜索
  27. if (!empty($this->request->get('product_name'))) {
  28. $productName = $this->request->get('product_name');
  29. $where[] = ['oi.item_name', 'like', '%' . $productName . '%'];
  30. }
  31. // 会员名称搜索
  32. if (!empty($this->request->get('user_name'))) {
  33. $userName = $this->request->get('user_name');
  34. $where[] = ['u.name', 'like', '%' . $userName . '%'];
  35. }
  36. // 分佣人搜索
  37. if (!empty($this->request->get('distributor_name'))) {
  38. $distributorName = $this->request->get('distributor_name');
  39. $where[] = ['du.name', 'like', '%' . $distributorName . '%'];
  40. }
  41. // 支付状态筛选
  42. if (!empty($this->request->get('pay_status'))) {
  43. $payStatus = $this->request->get('pay_status');
  44. $where['o.pay_status'] = $payStatus;
  45. }
  46. // 支付方式筛选
  47. if (!empty($this->request->get('pay_method'))) {
  48. $payMethod = $this->request->get('pay_method');
  49. $where['o.pay_method'] = $payMethod;
  50. }
  51. // 日期范围筛选
  52. if (!empty($this->request->get('date_range'))) {
  53. $dateRange = $this->request->get('date_range');
  54. $dateArr = explode(' - ', $dateRange);
  55. if (count($dateArr) == 2) {
  56. $startDate = $dateArr[0];
  57. $endDate = $dateArr[1];
  58. $where[] = ['o.order_time', '>=', $startDate . ' 00:00:00'];
  59. $where[] = ['o.order_time', '<=', $endDate . ' 23:59:59'];
  60. }
  61. }
  62. // 排序
  63. $order = [];
  64. if (!empty($this->request->get('order'))) {
  65. $order_a = $this->request->get('order');
  66. $order_a = explode(',', $order_a);
  67. $order[$order_a[0]] = $order_a[1];
  68. } else {
  69. $order['o.order_time'] = 'desc';
  70. }
  71. // 分页
  72. $page = $this->request->get('page', 1);
  73. $limit = $this->request->get('limit', 20);
  74. // 查询数据(使用订单商品表作为主表,一个订单可能对应多个商品)
  75. $orderList = Db::name('order_item')
  76. ->alias('oi')
  77. ->leftJoin('order o', 'oi.order_id = o.id')
  78. ->leftJoin('user_on u', 'o.user_id = u.id')
  79. ->leftJoin('user_on du', 'o.distributor_id = du.id')
  80. ->field('
  81. o.order_time,
  82. o.order_no,
  83. oi.item_name,
  84. oi.quantity,
  85. oi.unit_price,
  86. u.name,
  87. o.pay_amount,
  88. o.pay_method,
  89. o.pay_status,
  90. o.commission_amount,
  91. du.name,
  92. o.order_time,
  93. o.pay_time,
  94. oi.id,
  95. o.id as order_id
  96. ')
  97. ->where($where)
  98. ->order($order)
  99. ->paginate([
  100. 'list_rows' => $limit,
  101. 'page' => $page
  102. ]);
  103. // 转换字段格式
  104. $list = $orderList->items();
  105. foreach ($list as &$item) {
  106. // 支付方式转换
  107. $payMethodMap = [
  108. 'wechat' => '微信',
  109. 'alipay' => '支付宝',
  110. 'bank' => '银行卡',
  111. 'balance' => '余额'
  112. ];
  113. $item['pay_method'] = $payMethodMap[$item['pay_method']] ?? $item['pay_method'];
  114. // 支付状态转换
  115. $payStatusMap = [
  116. 0 => '待支付',
  117. 1 => '已支付',
  118. 2 => '支付失败',
  119. 3 => '已取消'
  120. ];
  121. $item['pay_status_text'] = $payStatusMap[$item['pay_status']] ?? $item['pay_status'];
  122. // 格式化日期
  123. if (!empty($item['order_time'])) {
  124. $item['order_time'] = date('Y-m-d', strtotime($item['order_time']));
  125. }
  126. }
  127. $this->success('查询成功', [
  128. 'list' => $list,
  129. 'total' => $orderList->total()
  130. ]);
  131. }
  132. /**
  133. * 构建查询条件
  134. * @return array
  135. */
  136. private function buildWhere(): array
  137. {
  138. $where = [];
  139. if (!empty($this->request->get('order_no'))) {
  140. $where[] = ['o.order_no', 'like', '%' . $this->request->get('order_no') . '%'];
  141. }
  142. if (!empty($this->request->get('item_name'))) {
  143. $where[] = ['oi.item_name', 'like', '%' . $this->request->get('item_name') . '%'];
  144. }
  145. if (!empty($this->request->get('user_name'))) {
  146. $where[] = ['u.name', 'like', '%' . $this->request->get('user_name') . '%'];
  147. }
  148. if (!empty($this->request->get('distributor_name'))) {
  149. $where[] = ['du.name', 'like', '%' . $this->request->get('distributor_name') . '%'];
  150. }
  151. if ($this->request->get('pay_status') !== '' && $this->request->get('pay_status') !== null) {
  152. $where['o.pay_status'] = $this->request->get('pay_status');
  153. }
  154. if (!empty($this->request->get('pay_method'))) {
  155. $where['o.pay_method'] = $this->request->get('pay_method');
  156. }
  157. if (!empty($this->request->get('date_range'))) {
  158. $dateRange = $this->request->get('date_range');
  159. $dateArr = explode(' - ', $dateRange);
  160. if (count($dateArr) == 2) {
  161. $startDate = $dateArr[0];
  162. $endDate = $dateArr[1];
  163. $where[] = ['o.order_time', '>=', $startDate . ' 00:00:00'];
  164. $where[] = ['o.order_time', '<=', $endDate . ' 23:59:59'];
  165. }
  166. }
  167. return $where;
  168. }
  169. /**
  170. * 构建排序
  171. * @return array
  172. */
  173. private function buildOrder(): array
  174. {
  175. $order = [];
  176. if (!empty($this->request->get('order'))) {
  177. $order_a = $this->request->get('order');
  178. $order_a = explode(',', $order_a);
  179. $order[$order_a[0]] = $order_a[1];
  180. } else {
  181. $order['o.order_time'] = 'desc';
  182. }
  183. return $order;
  184. }
  185. /**
  186. * 使用PhpSpreadsheet导出Excel文件
  187. * @return void
  188. */
  189. public function export(): void
  190. {
  191. // 获取查询条件
  192. $where = $this->buildWhere();
  193. $order = $this->buildOrder();
  194. // 查询所有数据
  195. $data = Db::name('order_item')
  196. ->alias('oi')
  197. ->leftJoin('order o', 'oi.order_id = o.id')
  198. ->leftJoin('user_on u', 'o.user_id = u.id')
  199. ->leftJoin('user_on du', 'o.distributor_id = du.id')
  200. ->field('
  201. o.order_no as 订单编号,
  202. DATE(o.order_time) as 日期,
  203. oi.item_name as 商品名称,
  204. oi.quantity as 购买数量,
  205. oi.unit_price as 商品单价,
  206. u.name as 会员名称,
  207. o.pay_amount as 支付金额,
  208. o.pay_method as 支付方式,
  209. o.pay_status as 支付状态,
  210. o.commission_amount as 最后佣金,
  211. du.name as 分佣人名称,
  212. o.order_time as 下单时间,
  213. o.pay_time as 支付时间
  214. ')
  215. ->where($where)
  216. ->order($order)
  217. ->select()
  218. ->toArray();
  219. if (empty($data)) {
  220. $this->error(__('没有找到符合条件的数据'));
  221. }
  222. // 转换字段格式
  223. foreach ($data as &$item) {
  224. // 支付方式转换
  225. $payMethodMap = [
  226. 'wechat' => '微信支付',
  227. 'alipay' => '支付宝',
  228. 'bank' => '银行卡',
  229. 'balance' => '余额支付'
  230. ];
  231. $item['支付方式'] = $payMethodMap[$item['支付方式']] ?? $item['支付方式'];
  232. // 支付状态转换
  233. $payStatusMap = [
  234. 0 => '待支付',
  235. 1 => '已支付',
  236. 2 => '支付失败',
  237. 3 => '已取消'
  238. ];
  239. $item['支付状态'] = $payStatusMap[$item['支付状态']] ?? $item['支付状态'];
  240. // 格式化金额(PhpSpreadsheet会自动处理数字格式)
  241. $item['商品单价'] = (float)$item['商品单价'];
  242. $item['支付金额'] = (float)$item['支付金额'];
  243. $item['最后佣金'] = (float)$item['最后佣金'];
  244. // 格式化时间
  245. if ($item['下单时间']) {
  246. $item['下单时间'] = date('Y-m-d H:i:s', strtotime($item['下单时间']));
  247. }
  248. if ($item['支付时间']) {
  249. $item['支付时间'] = date('Y-m-d H:i:s', strtotime($item['支付时间']));
  250. }
  251. }
  252. try {
  253. $spreadsheet = new Spreadsheet();
  254. $sheet = $spreadsheet->getActiveSheet();
  255. // 定义表头
  256. $headers = [
  257. '订单编号', '日期', '商品名称', '购买数量', '商品单价',
  258. '会员名称', '支付金额', '支付方式', '支付状态',
  259. '最后佣金', '分佣人名称', '下单时间', '支付时间'
  260. ];
  261. // 设置表头
  262. $col = 'A';
  263. foreach ($headers as $header) {
  264. $sheet->setCellValue($col . '1', $header);
  265. // 设置表头加粗和背景色
  266. $sheet->getStyle($col . '1')->getFont()->setBold(true);
  267. $sheet->getStyle($col . '1')->getFill()
  268. ->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
  269. ->getStartColor()->setRGB('D9D9D9');
  270. $col++;
  271. }
  272. // 填充数据
  273. $row = 2;
  274. foreach ($data as $item) {
  275. $col = 'A';
  276. foreach ($item as $value) {
  277. $cellAddress = $col . $row;
  278. // 特殊处理订单编号(防止科学计数法)
  279. if ($col === 'A') {
  280. $sheet->setCellValueExplicit($cellAddress, $value, DataType::TYPE_STRING);
  281. $sheet->getStyle($cellAddress)->getNumberFormat()->setFormatCode('@');
  282. } else {
  283. $sheet->setCellValue($cellAddress, $value);
  284. }
  285. $col++;
  286. }
  287. $row++;
  288. }
  289. // 设置列宽自适应
  290. $lastColumn = $sheet->getHighestColumn();
  291. for ($col = 'A'; $col <= $lastColumn; $col++) {
  292. $sheet->getColumnDimension($col)->setAutoSize(true);
  293. }
  294. // 生成文件名
  295. $fileName = '订单数据_' . date('YmdHis') . '.xlsx';
  296. // 清除输出缓冲区
  297. ob_clean();
  298. // 设置HTTP头
  299. header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
  300. header('Content-Disposition: attachment;filename="' . $fileName . '"');
  301. header('Cache-Control: max-age=0');
  302. // 输出到浏览器
  303. $writer = new Xlsx($spreadsheet);
  304. $writer->save('php://output');
  305. exit;
  306. } catch (\Exception $e) {
  307. $this->error('导出失败:' . $e->getMessage());
  308. }
  309. }
  310. /**
  311. * 获取订单状态选项
  312. * @return void
  313. */
  314. public function statusOptions(): void
  315. {
  316. $options = [
  317. ['value' => 0, 'label' => '待支付'],
  318. ['value' => 1, 'label' => '已支付'],
  319. ['value' => 2, 'label' => '支付失败'],
  320. ['value' => 3, 'label' => '已取消']
  321. ];
  322. $this->success('获取成功', $options);
  323. }
  324. /**
  325. * 获取支付方式选项
  326. * @return void
  327. */
  328. public function payMethodOptions(): void
  329. {
  330. $options = [
  331. ['value' => 'wechat', 'label' => '微信'],
  332. ['value' => 'alipay', 'label' => '支付宝'],
  333. ['value' => 'bank', 'label' => '银行卡'],
  334. ['value' => 'balance', 'label' => '余额']
  335. ];
  336. $this->success('获取成功', $options);
  337. }
  338. /**
  339. * 获取支付方式文本
  340. * @param string $method
  341. * @return string
  342. */
  343. private function getPayMethodText(string $method): string
  344. {
  345. $map = [
  346. 'wechat' => '微信支付',
  347. 'alipay' => '支付宝',
  348. 'bank' => '银行卡',
  349. 'balance' => '余额支付'
  350. ];
  351. return $map[$method] ?? $method;
  352. }
  353. /**
  354. * 获取支付状态文本
  355. * @param int $status
  356. * @return string
  357. */
  358. private function getPayStatusText(int $status): string
  359. {
  360. $map = [
  361. 0 => '待支付',
  362. 1 => '已支付',
  363. 2 => '支付失败',
  364. 3 => '已取消'
  365. ];
  366. return $map[$status] ?? '未知';
  367. }
  368. }