|
|
@@ -0,0 +1,332 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+namespace App\Module\Transfer\AdminControllers\Tools;
|
|
|
+
|
|
|
+use App\Module\Transfer\Models\TransferOrder;
|
|
|
+use App\Module\Transfer\Enums\TransferStatus;
|
|
|
+use App\Module\Transfer\Enums\TransferType;
|
|
|
+use Dcat\Admin\Grid\Tools\AbstractTool;
|
|
|
+use Illuminate\Http\Request;
|
|
|
+use Illuminate\Support\Facades\Response;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 订单导出工具
|
|
|
+ */
|
|
|
+class ExportOrderTool extends AbstractTool
|
|
|
+{
|
|
|
+ /**
|
|
|
+ * 工具按钮HTML
|
|
|
+ *
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ public function render(): string
|
|
|
+ {
|
|
|
+ return <<<HTML
|
|
|
+<div class="btn-group" role="group">
|
|
|
+ <button type="button" class="btn btn-outline-success btn-sm" onclick="exportOrders('excel')">
|
|
|
+ <i class="fa fa-file-excel-o"></i> 导出Excel
|
|
|
+ </button>
|
|
|
+ <button type="button" class="btn btn-outline-info btn-sm" onclick="exportOrders('csv')">
|
|
|
+ <i class="fa fa-file-text-o"></i> 导出CSV
|
|
|
+ </button>
|
|
|
+ <button type="button" class="btn btn-outline-primary btn-sm" onclick="showExportModal()">
|
|
|
+ <i class="fa fa-cog"></i> 高级导出
|
|
|
+ </button>
|
|
|
+</div>
|
|
|
+
|
|
|
+<!-- 导出配置模态框 -->
|
|
|
+<div class="modal fade" id="exportModal" tabindex="-1" role="dialog">
|
|
|
+ <div class="modal-dialog" role="document">
|
|
|
+ <div class="modal-content">
|
|
|
+ <div class="modal-header">
|
|
|
+ <h5 class="modal-title">导出配置</h5>
|
|
|
+ <button type="button" class="close" data-dismiss="modal">
|
|
|
+ <span>×</span>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ <div class="modal-body">
|
|
|
+ <form id="exportForm">
|
|
|
+ <div class="form-group">
|
|
|
+ <label>导出格式</label>
|
|
|
+ <select name="format" class="form-control">
|
|
|
+ <option value="excel">Excel (.xlsx)</option>
|
|
|
+ <option value="csv">CSV (.csv)</option>
|
|
|
+ </select>
|
|
|
+ </div>
|
|
|
+ <div class="form-group">
|
|
|
+ <label>时间范围</label>
|
|
|
+ <div class="row">
|
|
|
+ <div class="col-6">
|
|
|
+ <input type="date" name="start_date" class="form-control" placeholder="开始日期">
|
|
|
+ </div>
|
|
|
+ <div class="col-6">
|
|
|
+ <input type="date" name="end_date" class="form-control" placeholder="结束日期">
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="form-group">
|
|
|
+ <label>订单状态</label>
|
|
|
+ <select name="status" class="form-control">
|
|
|
+ <option value="">全部状态</option>
|
|
|
+ <option value="1">已创建</option>
|
|
|
+ <option value="20">处理中</option>
|
|
|
+ <option value="30">已回调</option>
|
|
|
+ <option value="100">已完成</option>
|
|
|
+ <option value="-1">失败</option>
|
|
|
+ </select>
|
|
|
+ </div>
|
|
|
+ <div class="form-group">
|
|
|
+ <label>订单类型</label>
|
|
|
+ <select name="type" class="form-control">
|
|
|
+ <option value="">全部类型</option>
|
|
|
+ <option value="1">转入</option>
|
|
|
+ <option value="2">转出</option>
|
|
|
+ </select>
|
|
|
+ </div>
|
|
|
+ <div class="form-group">
|
|
|
+ <label>导出字段</label>
|
|
|
+ <div class="row">
|
|
|
+ <div class="col-6">
|
|
|
+ <label><input type="checkbox" name="fields[]" value="id" checked> 订单ID</label><br>
|
|
|
+ <label><input type="checkbox" name="fields[]" value="out_order_id" checked> 外部订单ID</label><br>
|
|
|
+ <label><input type="checkbox" name="fields[]" value="user_id" checked> 用户ID</label><br>
|
|
|
+ <label><input type="checkbox" name="fields[]" value="type" checked> 订单类型</label><br>
|
|
|
+ <label><input type="checkbox" name="fields[]" value="status" checked> 订单状态</label><br>
|
|
|
+ </div>
|
|
|
+ <div class="col-6">
|
|
|
+ <label><input type="checkbox" name="fields[]" value="amount" checked> 内部金额</label><br>
|
|
|
+ <label><input type="checkbox" name="fields[]" value="out_amount" checked> 外部金额</label><br>
|
|
|
+ <label><input type="checkbox" name="fields[]" value="exchange_rate"> 汇率</label><br>
|
|
|
+ <label><input type="checkbox" name="fields[]" value="created_at" checked> 创建时间</label><br>
|
|
|
+ <label><input type="checkbox" name="fields[]" value="completed_at"> 完成时间</label><br>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </form>
|
|
|
+ </div>
|
|
|
+ <div class="modal-footer">
|
|
|
+ <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
|
|
|
+ <button type="button" class="btn btn-primary" onclick="doExport()">导出</button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</div>
|
|
|
+
|
|
|
+<script>
|
|
|
+function exportOrders(format) {
|
|
|
+ var url = '{$this->getExportUrl()}';
|
|
|
+ var params = new URLSearchParams(window.location.search);
|
|
|
+ params.set('format', format);
|
|
|
+ window.open(url + '?' + params.toString());
|
|
|
+}
|
|
|
+
|
|
|
+function showExportModal() {
|
|
|
+ $('#exportModal').modal('show');
|
|
|
+}
|
|
|
+
|
|
|
+function doExport() {
|
|
|
+ var form = document.getElementById('exportForm');
|
|
|
+ var formData = new FormData(form);
|
|
|
+ var params = new URLSearchParams();
|
|
|
+
|
|
|
+ for (var pair of formData.entries()) {
|
|
|
+ if (pair[0] === 'fields[]') {
|
|
|
+ params.append('fields[]', pair[1]);
|
|
|
+ } else {
|
|
|
+ params.set(pair[0], pair[1]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var url = '{$this->getExportUrl()}';
|
|
|
+ window.open(url + '?' + params.toString());
|
|
|
+ $('#exportModal').modal('hide');
|
|
|
+}
|
|
|
+</script>
|
|
|
+HTML;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理导出请求
|
|
|
+ *
|
|
|
+ * @param Request $request
|
|
|
+ * @return \Illuminate\Http\Response
|
|
|
+ */
|
|
|
+ public function export(Request $request)
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ // 获取导出参数
|
|
|
+ $format = $request->get('format', 'excel');
|
|
|
+ $startDate = $request->get('start_date');
|
|
|
+ $endDate = $request->get('end_date');
|
|
|
+ $status = $request->get('status');
|
|
|
+ $type = $request->get('type');
|
|
|
+ $fields = $request->get('fields', []);
|
|
|
+
|
|
|
+ // 构建查询
|
|
|
+ $query = TransferOrder::with('transferApp');
|
|
|
+
|
|
|
+ // 应用筛选条件
|
|
|
+ if ($startDate) {
|
|
|
+ $query->where('created_at', '>=', $startDate . ' 00:00:00');
|
|
|
+ }
|
|
|
+ if ($endDate) {
|
|
|
+ $query->where('created_at', '<=', $endDate . ' 23:59:59');
|
|
|
+ }
|
|
|
+ if ($status !== null && $status !== '') {
|
|
|
+ $query->where('status', $status);
|
|
|
+ }
|
|
|
+ if ($type !== null && $type !== '') {
|
|
|
+ $query->where('type', $type);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取数据
|
|
|
+ $orders = $query->orderBy('created_at', 'desc')->get();
|
|
|
+
|
|
|
+ // 处理导出字段
|
|
|
+ $exportData = $this->prepareExportData($orders, $fields);
|
|
|
+
|
|
|
+ // 生成文件
|
|
|
+ $filename = 'transfer_orders_' . date('Y-m-d_H-i-s');
|
|
|
+
|
|
|
+ if ($format === 'csv') {
|
|
|
+ return $this->exportCsv($exportData, $filename);
|
|
|
+ } else {
|
|
|
+ return $this->exportExcel($exportData, $filename);
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ return response()->json([
|
|
|
+ 'status' => false,
|
|
|
+ 'message' => '导出失败: ' . $e->getMessage()
|
|
|
+ ], 500);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 准备导出数据
|
|
|
+ *
|
|
|
+ * @param \Illuminate\Support\Collection $orders
|
|
|
+ * @param array $fields
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ protected function prepareExportData($orders, array $fields): array
|
|
|
+ {
|
|
|
+ // 默认字段
|
|
|
+ if (empty($fields)) {
|
|
|
+ $fields = ['id', 'out_order_id', 'user_id', 'type', 'status', 'amount', 'out_amount', 'created_at'];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 字段标题映射
|
|
|
+ $fieldLabels = [
|
|
|
+ 'id' => '订单ID',
|
|
|
+ 'out_order_id' => '外部订单ID',
|
|
|
+ 'user_id' => '用户ID',
|
|
|
+ 'out_user_id' => '外部用户ID',
|
|
|
+ 'type' => '订单类型',
|
|
|
+ 'status' => '订单状态',
|
|
|
+ 'amount' => '内部金额',
|
|
|
+ 'out_amount' => '外部金额',
|
|
|
+ 'exchange_rate' => '汇率',
|
|
|
+ 'transfer_app_title' => '划转应用',
|
|
|
+ 'remark' => '备注',
|
|
|
+ 'error_message' => '错误信息',
|
|
|
+ 'created_at' => '创建时间',
|
|
|
+ 'processed_at' => '处理时间',
|
|
|
+ 'completed_at' => '完成时间'
|
|
|
+ ];
|
|
|
+
|
|
|
+ $data = [];
|
|
|
+
|
|
|
+ // 添加标题行
|
|
|
+ $headers = [];
|
|
|
+ foreach ($fields as $field) {
|
|
|
+ $headers[] = $fieldLabels[$field] ?? $field;
|
|
|
+ }
|
|
|
+ $data[] = $headers;
|
|
|
+
|
|
|
+ // 添加数据行
|
|
|
+ foreach ($orders as $order) {
|
|
|
+ $row = [];
|
|
|
+ foreach ($fields as $field) {
|
|
|
+ $value = $this->getFieldValue($order, $field);
|
|
|
+ $row[] = $value;
|
|
|
+ }
|
|
|
+ $data[] = $row;
|
|
|
+ }
|
|
|
+
|
|
|
+ return $data;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取字段值
|
|
|
+ *
|
|
|
+ * @param TransferOrder $order
|
|
|
+ * @param string $field
|
|
|
+ * @return mixed
|
|
|
+ */
|
|
|
+ protected function getFieldValue(TransferOrder $order, string $field)
|
|
|
+ {
|
|
|
+ switch ($field) {
|
|
|
+ case 'type':
|
|
|
+ return TransferType::from($order->type)->getDescription();
|
|
|
+ case 'status':
|
|
|
+ return TransferStatus::from($order->status)->getDescription();
|
|
|
+ case 'transfer_app_title':
|
|
|
+ return $order->transferApp->title ?? '';
|
|
|
+ case 'created_at':
|
|
|
+ case 'processed_at':
|
|
|
+ case 'completed_at':
|
|
|
+ return $order->{$field} ? $order->{$field}->format('Y-m-d H:i:s') : '';
|
|
|
+ default:
|
|
|
+ return $order->{$field} ?? '';
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 导出CSV
|
|
|
+ *
|
|
|
+ * @param array $data
|
|
|
+ * @param string $filename
|
|
|
+ * @return \Illuminate\Http\Response
|
|
|
+ */
|
|
|
+ protected function exportCsv(array $data, string $filename)
|
|
|
+ {
|
|
|
+ $output = fopen('php://temp', 'w');
|
|
|
+
|
|
|
+ foreach ($data as $row) {
|
|
|
+ fputcsv($output, $row);
|
|
|
+ }
|
|
|
+
|
|
|
+ rewind($output);
|
|
|
+ $csv = stream_get_contents($output);
|
|
|
+ fclose($output);
|
|
|
+
|
|
|
+ return Response::make($csv, 200, [
|
|
|
+ 'Content-Type' => 'text/csv',
|
|
|
+ 'Content-Disposition' => 'attachment; filename="' . $filename . '.csv"',
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 导出Excel(简化版,实际项目中建议使用PhpSpreadsheet)
|
|
|
+ *
|
|
|
+ * @param array $data
|
|
|
+ * @param string $filename
|
|
|
+ * @return \Illuminate\Http\Response
|
|
|
+ */
|
|
|
+ protected function exportExcel(array $data, string $filename)
|
|
|
+ {
|
|
|
+ // 简化的Excel导出(实际是CSV格式但扩展名为xlsx)
|
|
|
+ return $this->exportCsv($data, $filename);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取导出URL
|
|
|
+ *
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ protected function getExportUrl(): string
|
|
|
+ {
|
|
|
+ return admin_url('transfer/orders/export');
|
|
|
+ }
|
|
|
+}
|