TransferOrderController.php 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. <?php
  2. namespace App\Module\Transfer\AdminControllers;
  3. use App\Module\Transfer\AdminControllers\Helper\TransferOrderHelper;
  4. use App\Module\Transfer\Models\TransferOrder;
  5. use App\Module\Transfer\Repositories\TransferOrderRepository;
  6. use App\Module\Transfer\Logics\TransferLogic;
  7. use Dcat\Admin\Grid;
  8. use Dcat\Admin\Show;
  9. use Spatie\RouteAttributes\Attributes\Resource;
  10. use Spatie\RouteAttributes\Attributes\Post;
  11. use Spatie\RouteAttributes\Attributes\Get;
  12. use UCore\DcatAdmin\AdminController;
  13. /**
  14. * 划转订单管理控制器
  15. *
  16. * 路由注解:
  17. * - Resource: transfer/orders (订单管理,只读)
  18. * - 额外路由: 重试订单、手动完成、统计信息、导出
  19. */
  20. #[Resource('transfer/orders', names: 'admin.transfer.orders', except: ['create', 'store', 'edit', 'update', 'destroy'])]
  21. class TransferOrderController extends AdminController
  22. {
  23. /**
  24. * 页面标题
  25. */
  26. protected $title = '划转订单管理';
  27. /**
  28. * 模型类
  29. */
  30. protected $model = TransferOrder::class;
  31. /**
  32. * 仓库类
  33. */
  34. protected $repository = TransferOrderRepository::class;
  35. /**
  36. * 配置数据表格
  37. */
  38. protected function grid(): Grid
  39. {
  40. $grid = Grid::make(new TransferOrder(), function (Grid $grid) {
  41. // 使用辅助类配置表格
  42. TransferOrderHelper::grid($grid);
  43. // 设置每页显示数量
  44. $grid->paginate(50);
  45. // 禁用创建和编辑按钮
  46. $grid->disableCreateButton();
  47. $grid->disableEditButton();
  48. // 设置表格标题
  49. // $grid->header(function () {
  50. // return view('transfer::admin.order.header', [
  51. // 'todayStats' => TransferOrderHelper::getTodayStats(),
  52. // 'statusStats' => TransferOrderHelper::getStatusStats(),
  53. // 'typeStats' => TransferOrderHelper::getTypeStats(),
  54. // ]);
  55. // });
  56. });
  57. return $grid;
  58. }
  59. /**
  60. * 配置数据详情
  61. */
  62. protected function detail($id): Show
  63. {
  64. $show = Show::make($id, new TransferOrder(), function (Show $show) use ($id) {
  65. // 使用辅助类配置详情
  66. TransferOrderHelper::show($show);
  67. // 添加自定义面板
  68. $show->panel()
  69. ->title('划转订单详情')
  70. ->tools(function ($tools) use ($id) {
  71. $order = TransferOrder::find($id);
  72. if ($order && $order->canRetry()) {
  73. $tools->append('<a class="btn btn-sm btn-outline-warning" href="javascript:void(0)" onclick="retryOrder('.$id.')">重试订单</a>');
  74. }
  75. if ($order && $order->isTransferOut() && !$order->isFinalStatus()) {
  76. $tools->append('<a class="btn btn-sm btn-outline-success" href="javascript:void(0)" onclick="manualComplete('.$id.')">手动完成</a>');
  77. }
  78. });
  79. });
  80. return $show;
  81. }
  82. /**
  83. * 重试订单
  84. */
  85. #[Post('transfer/orders/{id}/retry', name: 'admin.transfer.orders.retry')]
  86. public function retry($id)
  87. {
  88. try {
  89. $order = TransferOrder::findOrFail($id);
  90. if (!$order->canRetry()) {
  91. return response()->json([
  92. 'status' => false,
  93. 'message' => '订单状态不允许重试'
  94. ]);
  95. }
  96. $result = TransferLogic::retryOrder($id);
  97. if ($result) {
  98. return response()->json([
  99. 'status' => true,
  100. 'message' => '订单重试成功'
  101. ]);
  102. } else {
  103. return response()->json([
  104. 'status' => false,
  105. 'message' => '订单重试失败'
  106. ]);
  107. }
  108. } catch (\Exception $e) {
  109. return response()->json([
  110. 'status' => false,
  111. 'message' => '重试失败: ' . $e->getMessage()
  112. ]);
  113. }
  114. }
  115. /**
  116. * 手动完成订单
  117. */
  118. #[Post('transfer/orders/{id}/manual-complete', name: 'admin.transfer.orders.manual-complete')]
  119. public function manualComplete($id)
  120. {
  121. try {
  122. $remark = request('remark', '管理员手动完成');
  123. $order = TransferOrder::findOrFail($id);
  124. if ($order->isFinalStatus()) {
  125. return response()->json([
  126. 'status' => false,
  127. 'message' => '订单已处于最终状态'
  128. ]);
  129. }
  130. if (!$order->isTransferOut()) {
  131. return response()->json([
  132. 'status' => false,
  133. 'message' => '只有转出订单支持手动完成'
  134. ]);
  135. }
  136. $result = TransferLogic::manualComplete($id, $remark);
  137. if ($result) {
  138. return response()->json([
  139. 'status' => true,
  140. 'message' => '订单手动完成成功'
  141. ]);
  142. } else {
  143. return response()->json([
  144. 'status' => false,
  145. 'message' => '订单手动完成失败'
  146. ]);
  147. }
  148. } catch (\Exception $e) {
  149. return response()->json([
  150. 'status' => false,
  151. 'message' => '手动完成失败: ' . $e->getMessage()
  152. ]);
  153. }
  154. }
  155. /**
  156. * 获取订单统计信息
  157. */
  158. #[Get('transfer/orders/statistics', name: 'admin.transfer.orders.statistics')]
  159. public function statistics()
  160. {
  161. try {
  162. $stats = [
  163. 'today' => TransferOrderHelper::getTodayStats(),
  164. 'status' => TransferOrderHelper::getStatusStats(),
  165. 'type' => TransferOrderHelper::getTypeStats(),
  166. ];
  167. return response()->json([
  168. 'status' => true,
  169. 'data' => $stats
  170. ]);
  171. } catch (\Exception $e) {
  172. return response()->json([
  173. 'status' => false,
  174. 'message' => '获取统计信息失败: ' . $e->getMessage()
  175. ]);
  176. }
  177. }
  178. /**
  179. * 导出订单数据
  180. */
  181. #[Get('transfer/orders/export', name: 'admin.transfer.orders.export')]
  182. public function export()
  183. {
  184. try {
  185. $filters = request()->all();
  186. // 构建查询
  187. $query = TransferOrder::with('transferApp');
  188. // 应用筛选条件
  189. if (isset($filters['transfer_app_id'])) {
  190. $query->where('transfer_app_id', $filters['transfer_app_id']);
  191. }
  192. if (isset($filters['type'])) {
  193. $query->where('type', $filters['type']);
  194. }
  195. if (isset($filters['status'])) {
  196. $query->where('status', $filters['status']);
  197. }
  198. if (isset($filters['start_date'])) {
  199. $query->where('created_at', '>=', $filters['start_date']);
  200. }
  201. if (isset($filters['end_date'])) {
  202. $query->where('created_at', '<=', $filters['end_date']);
  203. }
  204. $orders = $query->orderBy('created_at', 'desc')->limit(10000)->get();
  205. // 生成CSV数据
  206. $csvData = [];
  207. $csvData[] = [
  208. 'ID', '应用名称', '外部订单ID', '用户ID', '外部用户ID',
  209. '类型', '状态', '外部金额', '内部金额', '汇率',
  210. '创建时间', '完成时间', '备注'
  211. ];
  212. foreach ($orders as $order) {
  213. $csvData[] = [
  214. $order->id,
  215. $order->transferApp->title,
  216. $order->out_order_id,
  217. $order->user_id,
  218. $order->out_user_id,
  219. $order->type->getDescription(),
  220. $order->status->getDescription(),
  221. $order->out_amount,
  222. $order->amount,
  223. $order->exchange_rate,
  224. $order->created_at->format('Y-m-d H:i:s'),
  225. $order->completed_at?->format('Y-m-d H:i:s'),
  226. $order->remark,
  227. ];
  228. }
  229. // 生成CSV文件
  230. $filename = 'transfer_orders_' . date('Y-m-d_H-i-s') . '.csv';
  231. $handle = fopen('php://output', 'w');
  232. header('Content-Type: text/csv');
  233. header('Content-Disposition: attachment; filename="' . $filename . '"');
  234. // 添加BOM以支持中文
  235. fwrite($handle, "\xEF\xBB\xBF");
  236. foreach ($csvData as $row) {
  237. fputcsv($handle, $row);
  238. }
  239. fclose($handle);
  240. exit;
  241. } catch (\Exception $e) {
  242. return response()->json([
  243. 'status' => false,
  244. 'message' => '导出失败: ' . $e->getMessage()
  245. ]);
  246. }
  247. }
  248. }